Skip to content
Snippets Groups Projects
Commit 2c04e441 authored by Maximilian Betz's avatar Maximilian Betz
Browse files

properlly closing the GNSS data stream when leaving add event widget

parent c8807576
No related branches found
No related tags found
No related merge requests found
......@@ -15,47 +15,19 @@ class AddEvent extends StatefulWidget {
class _AddEventPageState extends State<AddEvent> {
bool syncGNSSData = true;
late LocationPermission permission;
late Position position;
late String long = "";
late String lat = "";
late String alt = "";
late double accuracy = 0.0;
late StreamSubscription<Position> positionStream;
LocationSettings locationSettings = const LocationSettings(
accuracy: LocationAccuracy.high,
distanceFilter: 0,
);
late StreamSubscription<Position> streamHandler;
getLocation() async {
StreamSubscription<Position> positionStream = Geolocator.getPositionStream(
locationSettings: locationSettings).listen((Position position) {
debugPrint('Get Location: Lat:' + position.latitude.toString() +
' Long:' + position.longitude.toString() +
' Alt:' + position.altitude.toString());
long = position.longitude.toString();
lat = position.latitude.toString();
alt = position.altitude.toString();
accuracy = position.accuracy;
if (syncGNSSData == true) {
if(mounted){
setState(() {
//refresh UI on update
});}
};
});
}
startGNSS() async {
Future startGNSS() async {
debugPrint("Check Location Permission");
bool serviceStatus = false;
bool hasPermission = false;
serviceStatus = await Geolocator.isLocationServiceEnabled();
if(serviceStatus){
permission = await Geolocator.checkPermission();
LocationPermission permission = await Geolocator.checkPermission();
if (permission == LocationPermission.denied) {
permission = await Geolocator.requestPermission();
......@@ -69,15 +41,34 @@ class _AddEventPageState extends State<AddEvent> {
}else{
hasPermission = true;
}
if(hasPermission){
debugPrint('Location permissions granted');
if(mounted){
setState(() {
//refresh the UI
});};
});}
debugPrint('Starting location stream');
streamHandler = Geolocator.getPositionStream(
locationSettings: const LocationSettings(
accuracy: LocationAccuracy.high,
distanceFilter: 0,
)).listen((Position position) {
debugPrint('Get Location: Lat:' + position.latitude.toString() +
' Long:' + position.longitude.toString() +
' Alt:' + position.altitude.toString());
long = position.longitude.toString();
lat = position.latitude.toString();
alt = position.altitude.toString();
accuracy = position.accuracy;
getLocation();
if (syncGNSSData == true) {
if(mounted){
setState(() {
//refresh UI on update
});}
}
});
}
}else{
debugPrint("GPS Service is not enabled, turn on GPS location");
......@@ -91,9 +82,24 @@ class _AddEventPageState extends State<AddEvent> {
@override
void initState() {
startGNSS();
super.initState();
}
@override
void dispose() {
try {
streamHandler.cancel();
debugPrint('Cancel location stream');
}catch(e){
debugPrint('Canceling location stream failed');
}
super.dispose();
//TODO: only if initialized positionStream.cancel();
}
void _storeCurrentEvent() {
final EventStoreInstance eventsStore = EventStoreInstance();
eventsStore.currentEvent.status = "PENDING";
......@@ -122,8 +128,6 @@ class _AddEventPageState extends State<AddEvent> {
final ConfigurationStoreInstance configuration = ConfigurationStoreInstance();
String gnssStatusText = "";
final formKey = GlobalKey<FormState>(); //key for form
if (true == syncGNSSData){
// Update current event coordinates from GNSS stream
......@@ -146,183 +150,205 @@ class _AddEventPageState extends State<AddEvent> {
gnssStatusText = "GNSS Disabled"; // Just display existing event coordinates
}
return Scaffold(
appBar: AppBar(title: const Text("Add Event")),
body:
Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
TextFormField(
initialValue: eventsStore.currentEvent.label,
autovalidateMode: AutovalidateMode.onUserInteraction,
decoration: const InputDecoration(
labelText: 'Label',
errorText: 'Only: a-z , A-Z , _ , 0-9 , ,(Comma) , ( , ) , + , - , . , :'
),
onChanged: (value) {
eventsStore.currentEvent.label = value;
},
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
}
},
),
DropdownButtonFormField(
value: eventsStore.currentEvent.type,
if (configuration.initialized == true) {
return Scaffold(
appBar: AppBar(title: const Text("Add Event")),
body:
Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
TextFormField(
initialValue: eventsStore.currentEvent.label,
autovalidateMode: AutovalidateMode.onUserInteraction,
decoration: const InputDecoration(
labelText: 'Event Type',
labelText: 'Label',
errorText: 'Only: a-z , A-Z , _ , 0-9 , ,(Comma) , ( , ) , + , - , . , :'
),
items:
configuration.eventTypes.map((EventType event) {
return DropdownMenuItem(
value: event.name,
child: Text(event.name),
);
}).toList(),
onChanged: (value) {
eventsStore.currentEvent.type = value.toString();
}
),
DropdownButtonFormField(
value: eventsStore.currentEvent.urn,
eventsStore.currentEvent.label = value;
},
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
}
},
),
DropdownButtonFormField(
value: eventsStore.currentEvent.type,
isExpanded: true,
decoration: const InputDecoration(
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();
}
),
DropdownButtonFormField(
value: eventsStore.currentEvent.urn,
isExpanded: true,
decoration: const InputDecoration(
labelText: 'URN',
),
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());
}
),
TextFormField(
initialValue: eventsStore.currentEvent.description,
decoration: const InputDecoration(
labelText: 'URN',
labelText: 'Description'
),
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());
}
),
TextFormField(
initialValue: eventsStore.currentEvent.description,
decoration: const InputDecoration(
labelText: 'Description'
eventsStore.currentEvent.description = value;
},
),
onChanged: (value) {
eventsStore.currentEvent.description = value;
},
),
Row(
mainAxisSize: MainAxisSize.min,
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(),
Row(
mainAxisSize: MainAxisSize.min,
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: Text('Now'),
),
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);
},
]
),
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;
}
),
TextFormField(
readOnly: false,
enabled: !syncGNSSData,
controller: TextEditingController(
text: eventsStore.currentEvent.longitude.toString()),
decoration: const InputDecoration(
labelText: 'Longitude',
border: OutlineInputBorder(),
),
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'),
onChanged: (value) {
eventsStore.currentEvent.longitude = value;
}
),
TextFormField(
readOnly: false,
enabled: !syncGNSSData,
controller: TextEditingController(
text: eventsStore.currentEvent.elevation.toString()),
decoration: const InputDecoration(
labelText: 'Elevation',
border: OutlineInputBorder(),
),
]
),
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;
}
),
TextFormField(
readOnly: false,
enabled: !syncGNSSData,
controller: TextEditingController(text: eventsStore.currentEvent.longitude.toString()),
decoration: const InputDecoration(
labelText: 'Longitude',
border: OutlineInputBorder(),
onChanged: (value) {
eventsStore.currentEvent.elevation = value;
}
),
]),
bottomNavigationBar: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text(gnssStatusText),
const SizedBox(width: 10),
Switch(
value: syncGNSSData,
onChanged: (value) {
syncGNSSData = value;
debugPrint('Switched to:' + syncGNSSData.toString());
),
onChanged: (value) {
eventsStore.currentEvent.longitude = value;
}
setState(() {
//refresh the UI
});
},
),
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;
}
const SizedBox(width: 50),
FloatingActionButton(
heroTag: null,
onPressed: () {
_storeCurrentEvent();
HapticFeedback.vibrate();
},
tooltip: 'Add Event',
child: const Icon(Icons.check),
),
]),
bottomNavigationBar: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text(gnssStatusText),
const SizedBox(width: 10),
Switch(
value: syncGNSSData,
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),
),
const SizedBox(width: 20),
],
),
);
const SizedBox(width: 20),
],
),
);
}else {
return Scaffold(
appBar: AppBar(title: const Text("Add Event")),
body: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.end,
children: const <Widget>[
Text(
' Visit Configuration first.',
style: TextStyle(fontSize: 20)
),
],
),
);
}
}
}
......@@ -50,7 +50,7 @@ Future<List<Device>> updateDevices(int collectionId) async {
String url = 'https://sandbox.sensor.awi.de/rest/sensors/collections/getItemsOfCollection/' + collectionId.toString();
// Get Access to local device and current event store.
EventStoreInstance eventsStore = EventStoreInstance();
EventStoreInstance events = EventStoreInstance();
ConfigurationStoreInstance configuration = ConfigurationStoreInstance();
List<Device> collectionDevices = [];
......@@ -72,8 +72,17 @@ Future<List<Device>> updateDevices(int collectionId) async {
/*Update to local device store*/
configuration.devices = collectionDevices;
//Update id and urn for the add event widget
eventsStore.currentEvent.id = collectionDevices[0].id;
eventsStore.currentEvent.urn = collectionDevices[0].urn;
events.currentEvent.id = collectionDevices[0].id;
events.currentEvent.urn = collectionDevices[0].urn;
events.currentEvent.description = '';
events.currentEvent.label = '';
events.currentEvent.type = configuration.eventTypes[0].name;
var date = DateTime.now().toUtc();
events.currentEvent.startDate = '$date';
events.currentEvent.endDate = '$date';
configuration.initialized = true;
return collectionDevices;
} else {
throw Exception('Failed to load Collection');
......@@ -155,6 +164,7 @@ class _MyHomePageState extends State<Configuration> {
Widget build(BuildContext context) {
final ConfigurationStoreInstance configuration = ConfigurationStoreInstance();
final EventStoreInstance events = EventStoreInstance();
return Scaffold(
appBar: AppBar(
......@@ -235,17 +245,27 @@ class _MyHomePageState extends State<Configuration> {
),
),
bottomNavigationBar: Row(
mainAxisAlignment: MainAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
FloatingActionButton.extended(
heroTag: null,
tooltip: 'Reset all data',
icon: const Icon(Icons.cancel),
label: const Text('Reset all'),
onPressed: () {
events.reset();
configuration.reset();
},
),
FloatingActionButton.extended(
heroTag: null,
tooltip: 'Select Collection and download corresponding devices',
icon: const Icon(Icons.save),
label: const Text('Store'),
onPressed: () {
updateDevices(configuration.currentCollection.id);
login();
fetchEventTypes();
updateDevices(configuration.currentCollection.id);
HapticFeedback.vibrate();
},
),
......
......@@ -146,6 +146,7 @@ abstract class ConfigurationStoreBase {
List<Device> devices = [];
List<EventType> eventTypes = [];
SensorLogin loginInformation = SensorLogin('', '', '');
bool initialized = false;
Collection getCollectionFromName(String name) {
for (var collection in collections) {
......@@ -179,7 +180,8 @@ abstract class ConfigurationStoreBase {
devices = [];
eventTypes = [];
currentCollection = Collection(id: -1, description: '', collectionName: '');
loginInformation = SensorLogin('', '', '');
loginInformation = SensorLogin('admin', 'adminadmin', '');
initialized = false;
}
}
......
......@@ -23,19 +23,19 @@ void main() {
// Add some dummy devices
// TODO: load from shared preferences.
// TODO: this shall be requested from sensor.awi.de after selecting a collection in configuration.
configuration.devices.add(Device.fromJson({'id': 8311, 'urn':'station:neumayer_iii:awi_snow_sampler_1'}));
configuration.devices.add(Device.fromJson({'id': 4086, 'urn':'acoustic_backscatter_sensor:test'}));
configuration.devices.add(Device.fromJson({'id': 1393, 'urn':'vessel:polarstern:hydrosweep_ds3'}));
//configuration.devices.add(Device.fromJson({'id': 8311, 'urn':'station:neumayer_iii:awi_snow_sampler_1'}));
//configuration.devices.add(Device.fromJson({'id': 4086, 'urn':'acoustic_backscatter_sensor:test'}));
//configuration.devices.add(Device.fromJson({'id': 1393, 'urn':'vessel:polarstern:hydrosweep_ds3'}));
// Fill the textboxes in addevent with some usefull data.
// TODO: store this in shared preferences so that last entered data reappears when restarting the app.
events.currentEvent.urn = 'acoustic_backscatter_sensor:test';
events.currentEvent.id = 4086;
events.currentEvent.description = 'blabla';
events.currentEvent.label = 'PS129_ABC';
events.currentEvent.type = 'Deployment';
events.currentEvent.startDate = '2022-03-09 15:06:00.000Z';
events.currentEvent.endDate = '2022-03-09 15:08:00.000Z';
//events.currentEvent.urn = 'vessel:polarstern:hydrosweep_ds3';
//events.currentEvent.id = -1;
//events.currentEvent.description = '';
//events.currentEvent.label = '';
//events.currentEvent.type = 'Configuration';
//events.currentEvent.startDate = '2022-03-09 15:06:00.000Z';
//events.currentEvent.endDate = '2022-03-09 15:08:00.000Z';
//Add some dummy events to event store. Just development purpose. TODO: Remove after development.
......@@ -83,11 +83,11 @@ void main() {
//Add some dummy eventtypes.
// TODO: loard from shared preferences.
// TODO: request from https://sensor.awi.de/rest/sensors/events/getAllEventTypes in configuration widget.
configuration.eventTypes.add(EventType.fromJson({'id': 317, 'name':'Configuration'}));
configuration.eventTypes.add(EventType.fromJson({'id': 216, 'name':'Decommissioned'}));
configuration.eventTypes.add(EventType.fromJson({'id': 187, 'name':'Deployment'}));
configuration.eventTypes.add(EventType.fromJson({'id': 50, 'name':'Information'}));
configuration.eventTypes.add(EventType.fromJson({'id': 16, 'name':'Maintenance'}));
//configuration.eventTypes.add(EventType.fromJson({'id': 317, 'generalName':'Configuration'}));
//configuration.eventTypes.add(EventType.fromJson({'id': 216, 'generalName':'Decommissioned'}));
//configuration.eventTypes.add(EventType.fromJson({'id': 187, 'generalName':'Deployment'}));
//configuration.eventTypes.add(EventType.fromJson({'id': 50, 'generalName':'Information'}));
//configuration.eventTypes.add(EventType.fromJson({'id': 16, 'generalName':'Maintenance'}));
runApp(MaterialApp(
title: 'Mobile Event Log',
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment