From 36535a236497e5441f3ad9830589b3dee3d088f6 Mon Sep 17 00:00:00 2001 From: Maximilian Betz <Maximilian.Betz@awi.de> Date: Fri, 11 Mar 2022 11:08:57 +0100 Subject: [PATCH] input validation on add event added --- lib/addevent.dart | 378 +++++++++++++++++++++++------------------ lib/configuration.dart | 1 + 2 files changed, 209 insertions(+), 170 deletions(-) diff --git a/lib/addevent.dart b/lib/addevent.dart index 02a72b8..b937338 100644 --- a/lib/addevent.dart +++ b/lib/addevent.dart @@ -19,7 +19,9 @@ class _AddEventPageState extends State<AddEvent> { late String lat = ""; late String alt = ""; late double accuracy = 0.0; - late StreamSubscription<Position> streamHandler; + late StreamSubscription<Position> streamHandler; //For canceling GNSS stream on dispose + bool _labelValidate = false; + bool _descriptionValidate = false; Future startGNSS() async { debugPrint("Check Location Permission"); @@ -98,6 +100,18 @@ class _AddEventPageState extends State<AddEvent> { super.dispose(); } + bool _validateInput(){ + final EventStoreInstance eventsStore = EventStoreInstance(); + if (RegExp(r'^[a-z A-Z . \- 0-9 , ( ) + - _ :]+$').hasMatch( + eventsStore.currentEvent.label)) { + if (RegExp(r'^[a-z A-Z . \- 0-9 , ( ) + - _ :]+$').hasMatch( + eventsStore.currentEvent.description)) { + return true; + } + } + return false; + } + void _storeCurrentEvent() { final EventStoreInstance eventsStore = EventStoreInstance(); eventsStore.currentEvent.status = "PENDING"; @@ -149,175 +163,189 @@ class _AddEventPageState extends State<AddEvent> { if (configuration.initialized == true) { return Scaffold( appBar: AppBar(title: const Text("Add Event")), - body: SingleChildScrollView( child: - Column( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: <Widget>[ - const SizedBox(height: 10.0), - TextFormField( - initialValue: eventsStore.currentEvent.label, - autovalidateMode: AutovalidateMode.always, - decoration: const InputDecoration( - border: OutlineInputBorder(), - labelText: 'Label', - errorText: 'Only: a-z , A-Z , _ , 0-9 , ,(Comma) , ( , ) , + , - , . , :' - ), - onChanged: (value) { - }, - onFieldSubmitted: (value){ - eventsStore.currentEvent.label = value; - - setState(() {}); - }, - validator: (value) { - if (!RegExp(r'^[a-z A-Z . \- 0-9 , ( ) + - _ :]+$').hasMatch( - value!)) { - return "Only: a-z , A-Z , _ , 0-9 , ,(Comma) , ( , ) , + , - , . , :"; - } else { - //eventsStore.currentEvent.label = value; - return ""; // Entered Text is valid - } - }, - ), - const SizedBox(height: 10.0), - DropdownButtonFormField( - value: eventsStore.currentEvent.type, - isExpanded: true, - decoration: const InputDecoration( - border: OutlineInputBorder(), - labelText: 'Event Type', + body: SingleChildScrollView( + child: Container( + margin: const EdgeInsets.symmetric(horizontal: 5.0), + child: + Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: <Widget>[ + const SizedBox(height: 15.0), + TextFormField( + initialValue: eventsStore.currentEvent.label, + autovalidateMode: AutovalidateMode.always, + decoration: const InputDecoration( + border: OutlineInputBorder(), + labelText: 'Label', + ), + onChanged: (value){ + eventsStore.currentEvent.label = value; + setState(() {}); + }, + validator: (value) { + if (!RegExp(r'^[a-z A-Z . \- 0-9 , ( ) + - _ :]+$').hasMatch( + value!)) { + _labelValidate = false; + return "Only: a-z , A-Z , _ , 0-9 , ,(Comma) , ( , ) , + , - , . , :"; + } else { + _labelValidate = true; + //eventsStore.currentEvent.label = value; + return null; // Entered Text is valid + } + }, ), - items: - configuration.eventTypes.map((EventType event) { - return DropdownMenuItem( - value: event.name, - child: Text(event.name), - ); - }).toList(), - onChanged: (value) { - eventsStore.currentEvent.type = value.toString(); - } - ), - const SizedBox(height: 10.0), - DropdownButtonFormField( - value: eventsStore.currentEvent.urn, - isExpanded: true, - decoration: const InputDecoration( - border: OutlineInputBorder(), - labelText: 'URN', + const SizedBox(height: 15.0), + DropdownButtonFormField( + value: eventsStore.currentEvent.type, + isExpanded: true, + decoration: const InputDecoration( + border: OutlineInputBorder(), + labelText: 'Event Type', + ), + items: + configuration.eventTypes.map((EventType event) { + return DropdownMenuItem( + value: event.name, + child: Text(event.name), + ); + }).toList(), + onChanged: (value) { + eventsStore.currentEvent.type = value.toString(); + } ), - items: - configuration.devices.map((Device device) { - return DropdownMenuItem( - value: device.urn, - child: Text(device.urn), - ); - }).toList(), - onChanged: (value) { - eventsStore.currentEvent.urn = value.toString(); - eventsStore.currentEvent.id = - configuration.getDeviceIdFromUrn(value.toString()); - } - ), - const SizedBox(height: 10.0), - TextFormField( - minLines: 3, - maxLines: 3, - initialValue: eventsStore.currentEvent.description, - decoration: const InputDecoration( - border: OutlineInputBorder(), - labelText: 'Description' - ), - onChanged: (value) { - eventsStore.currentEvent.description = value; - }, - ), - const SizedBox(height: 10.0), - Row( - mainAxisSize: MainAxisSize.max, - children: <Widget>[ - Flexible(child: - TextFormField( - controller: TextEditingController( - text: eventsStore.currentEvent.startDate), - readOnly: true, + const SizedBox(height: 15.0), + DropdownButtonFormField( + value: eventsStore.currentEvent.urn, + isExpanded: true, decoration: const InputDecoration( - labelText: 'Timestamp', - //helperText: '', //Adds some space below field border: OutlineInputBorder(), + labelText: 'URN', ), - onTap: () { - DatePicker.showDateTimePicker(context, - showTitleActions: true, - onConfirm: (date) { - //Only one field for start and end date. - eventsStore.currentEvent.startDate = '$date'; - eventsStore.currentEvent.endDate = '$date'; - debugPrint('Date set to : $date'); - setState(() {}); - }, - currentTime: DateTime.now().toUtc(), - locale: LocaleType.en); - }, - ), - ), - ElevatedButton( - onPressed: () { - var date = DateTime.now().toUtc(); - eventsStore.currentEvent.startDate = '$date'; - eventsStore.currentEvent.endDate = '$date'; - debugPrint('Date set to : ' + - eventsStore.currentEvent.endDate.toString()); - setState(() {}); - }, - child: Text('Now'), + items: + configuration.devices.map((Device device) { + return DropdownMenuItem( + value: device.urn, + child: Text(device.urn), + ); + }).toList(), + onChanged: (value) { + eventsStore.currentEvent.urn = value.toString(); + eventsStore.currentEvent.id = + configuration.getDeviceIdFromUrn(value.toString()); + } + ), + const SizedBox(height: 15.0), + TextFormField( + initialValue: eventsStore.currentEvent.description, + autovalidateMode: AutovalidateMode.always, + decoration: const InputDecoration( + border: OutlineInputBorder(), + labelText: 'Description' ), - ] - ), - const SizedBox(height: 10.0), - TextFormField( - readOnly: false, - enabled: !syncGNSSData, - controller: TextEditingController( - text: eventsStore.currentEvent.latitude.toString()), - decoration: const InputDecoration( - labelText: 'Latitude', - border: OutlineInputBorder(), + onChanged: (value){ + eventsStore.currentEvent.description = value; + setState(() {}); + }, + validator: (value) { + if (!RegExp(r'^[a-z A-Z . \- 0-9 , ( ) + - _ :]+$').hasMatch( + value!)) { + _descriptionValidate = false; + return "Only: a-z , A-Z , _ , 0-9 , ,(Comma) , ( , ) , + , - , . , :"; + } else { + _descriptionValidate = true; + //eventsStore.currentEvent.label = value; + return null; // Entered Text is valid + } + }, + ), + const SizedBox(height: 15.0), + Row( + mainAxisSize: MainAxisSize.max, + children: <Widget>[ + Flexible(child: + TextFormField( + controller: TextEditingController( + text: eventsStore.currentEvent.startDate), + readOnly: true, + decoration: const InputDecoration( + labelText: 'Timestamp', + //helperText: '', //Adds some space below field + border: OutlineInputBorder(), + ), + onTap: () { + DatePicker.showDateTimePicker(context, + showTitleActions: true, + onConfirm: (date) { + //Only one field for start and end date. + eventsStore.currentEvent.startDate = '$date'; + eventsStore.currentEvent.endDate = '$date'; + debugPrint('Date set to : $date'); + setState(() {}); + }, + currentTime: DateTime.now().toUtc(), + locale: LocaleType.en); + }, + ), + ), + ElevatedButton( + onPressed: () { + var date = DateTime.now().toUtc(); + eventsStore.currentEvent.startDate = '$date'; + eventsStore.currentEvent.endDate = '$date'; + debugPrint('Date set to : ' + + eventsStore.currentEvent.endDate.toString()); + setState(() {}); + }, + child: const Text('Now'), + ), + ] ), - onChanged: (value) { - eventsStore.currentEvent.latitude = value; - } - ), - const SizedBox(height: 10.0), - TextFormField( - readOnly: false, - enabled: !syncGNSSData, - controller: TextEditingController( - text: eventsStore.currentEvent.longitude.toString()), - decoration: const InputDecoration( - labelText: 'Longitude', - border: OutlineInputBorder(), + const SizedBox(height: 15.0), + TextFormField( + readOnly: false, + enabled: !syncGNSSData, + controller: TextEditingController( + text: eventsStore.currentEvent.latitude.toString()), + decoration: const InputDecoration( + labelText: 'Latitude', + border: OutlineInputBorder(), + ), + onChanged: (value) { + eventsStore.currentEvent.latitude = value; + } + ), + const SizedBox(height: 15.0), + TextFormField( + readOnly: false, + enabled: !syncGNSSData, + controller: TextEditingController( + text: eventsStore.currentEvent.longitude.toString()), + decoration: const InputDecoration( + labelText: 'Longitude', + border: OutlineInputBorder(), + ), + onChanged: (value) { + eventsStore.currentEvent.longitude = value; + } ), - onChanged: (value) { - eventsStore.currentEvent.longitude = value; - } - ), - const SizedBox(height: 10.0), - TextFormField( - readOnly: false, - enabled: !syncGNSSData, - controller: TextEditingController( - text: eventsStore.currentEvent.elevation.toString()), - decoration: const InputDecoration( - labelText: 'Elevation', - border: OutlineInputBorder(), + const SizedBox(height: 15.0), + TextFormField( + readOnly: false, + enabled: !syncGNSSData, + controller: TextEditingController( + text: eventsStore.currentEvent.elevation.toString()), + decoration: const InputDecoration( + labelText: 'Elevation', + border: OutlineInputBorder(), + ), + onChanged: (value) { + eventsStore.currentEvent.elevation = value; + } ), - onChanged: (value) { - eventsStore.currentEvent.elevation = value; - } - ), - ]), + ] + ), + ), ), bottomNavigationBar: Row( mainAxisAlignment: MainAxisAlignment.end, @@ -329,23 +357,33 @@ class _AddEventPageState extends State<AddEvent> { onChanged: (value) { syncGNSSData = value; debugPrint('Switched to:' + syncGNSSData.toString()); - setState(() { //refresh the UI }); }, ), const SizedBox(width: 50), - FloatingActionButton( - heroTag: null, - onPressed: () { - _storeCurrentEvent(); - HapticFeedback.vibrate(); - }, - tooltip: 'Add Event', - child: const Icon(Icons.check), + Container( + margin: const EdgeInsets.symmetric(vertical: 10.0), + child: _validateInput() ? + FloatingActionButton( + onPressed: () { + _storeCurrentEvent(); + HapticFeedback.vibrate(); + }, + tooltip: 'Add Event', + child: const Icon(Icons.check), + ) : + FloatingActionButton( + enableFeedback: false, + backgroundColor: Colors.grey, + onPressed: () { + }, + tooltip: 'Correct Inputs before adding the Event', + //child: const Icon(Icons.check), + ) ), - const SizedBox(width: 20), + const SizedBox(width: 10.0), ], ), ); diff --git a/lib/configuration.dart b/lib/configuration.dart index e5903fd..c02ef08 100644 --- a/lib/configuration.dart +++ b/lib/configuration.dart @@ -258,6 +258,7 @@ class _MyHomePageState extends State<Configuration> { }, ), FloatingActionButton.extended( + heroTag: null, tooltip: 'Select Collection and download corresponding devices', icon: const Icon(Icons.save), -- GitLab