diff --git a/lib/configuration.dart b/lib/configuration.dart index 3c2b2a571cffd3a5ce5f4d64aaa7692a29499453..2eba2b9e4cc5a1f98fefee8b088cce070b27f42d 100644 --- a/lib/configuration.dart +++ b/lib/configuration.dart @@ -1,10 +1,10 @@ import 'dart:convert'; - -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'datamodel.dart'; import 'sensorconnector.dart'; +import 'databaseconnector.dart'; +import 'package:shared_preferences/shared_preferences.dart'; class Configuration extends StatefulWidget { const Configuration({Key? key}) : super(key: key); @@ -23,7 +23,67 @@ class _MyHomePageState extends State<Configuration> { SensorConnector connector = SensorConnector(); final ConfigurationStoreInstance configuration = ConfigurationStoreInstance(); - @override + Future<void> updateConfiguration() async { + final EventStoreInstance event = EventStoreInstance(); + + futureAuthToken.then((value){ //NOTE: Counterintuitive async callback function + debugPrint("Login credentials correct! Auth Token: " + value); + + futureDevices.then((value) { + debugPrint("Device List complete"); + configuration.devices = value; + + futureEventTypes.then((value) async { + debugPrint("Event Types List complete"); + configuration.eventTypes = value; + + debugPrint("EventType Json: " + jsonEncode( + configuration.eventTypes[0])); + debugPrint("Device Json: " + jsonEncode( + configuration.devices[0])); + debugPrint("Current Collection Json: " + jsonEncode( + configuration.currentCollection)); + debugPrint("Sensor Login Json: " + jsonEncode( + configuration.loginInformation)); + + try { + //Update id and urn for the add event widget with some initial data + event.currentEvent.id = 0; + event.currentEvent.urnId = configuration.devices[0] + .id; //TODO: fix if devices are an empty list. + event.currentEvent.urn = configuration.devices[0].urn; + event.currentEvent.description = ''; + event.currentEvent.label = ''; + event.currentEvent.type = configuration.eventTypes[0] + .name; + + var date = DateTime.now().toUtc(); + var isoDate = date.toIso8601String(); + event.currentEvent.startDate = isoDate; + event.currentEvent.endDate = isoDate; + configuration.initialized = true; + + //debugPrint (configuration.toMap().toString(), wrapWidth: 512); + + HapticFeedback.vibrate(); + //TODO: display success user feedback + //TODO: store complete "configuration" + } catch (e) { + throw Exception('Something went wrong try again'); + } + + final prefs = await SharedPreferences.getInstance(); + prefs.setString('configuration', jsonEncode(configuration.toMap())); + prefs.setString('currentEvent', jsonEncode(event.toMap())); + debugPrint('Configuration stored!'); + }); + }); + }); + //TODO: display failed as user feedback somehow + } + + + @override void initState() { super.initState(); @@ -147,6 +207,9 @@ class _MyHomePageState extends State<Configuration> { label: const Text('Reset all'), onPressed: () { //events.reset(); //TODO: remove before release! + var db = DatabaseInstance(); + db.delete(); + configuration.reset(); //TODO: remove before release this is not a real use case! }, ), @@ -157,52 +220,7 @@ class _MyHomePageState extends State<Configuration> { icon: const Icon(Icons.save), label: const Text('Store'), onPressed: () { - futureAuthToken.then((value){ //NOTE: Counterintuitive async callback function - debugPrint("Login credentials correct! Auth Token: " + value); - - futureDevices.then((value) { - debugPrint("Device List complete"); - configuration.devices = value; - - futureEventTypes.then((value) { - debugPrint("Event Types List complete"); - configuration.eventTypes = value; - - debugPrint("EventType Json: " + jsonEncode( - configuration.eventTypes[0])); - debugPrint("Device Json: " + jsonEncode( - configuration.devices[0])); - debugPrint("Current Collection Json: " + jsonEncode( - configuration.currentCollection)); - debugPrint("Sensor Login Json: " + jsonEncode( - configuration.loginInformation)); - - try { - //Update id and urn for the add event widget with some initial data - events.currentEvent.id = 0; - events.currentEvent.urnId = configuration.devices[0] - .id; //TODO: fix if devices are an empty list. - events.currentEvent.urn = configuration.devices[0].urn; - events.currentEvent.description = ''; - events.currentEvent.label = ''; - events.currentEvent.type = configuration.eventTypes[0] - .name; - - var date = DateTime.now().toUtc(); - var isoDate = date.toIso8601String(); - events.currentEvent.startDate = isoDate; - events.currentEvent.endDate = isoDate; - configuration.initialized = true; - - HapticFeedback.vibrate(); - //TODO: display success user feedback - //TODO: store complete "configuration" - } catch (e) { - throw Exception('Something went wrong try again'); - } - }); - }); - }); + updateConfiguration(); //TODO: display failed as user feedback somehow }, ), diff --git a/lib/databaseconnector.dart b/lib/databaseconnector.dart index f9b6b1a024cf2619bfea417000602056c224484d..2c80fd86bd7e17d6d47a5c7bce5e047b4f041b69 100644 --- a/lib/databaseconnector.dart +++ b/lib/databaseconnector.dart @@ -12,9 +12,7 @@ class DatabaseInstance extends DatabaseConnector { return _instance; } - DatabaseInstance._internal() { - //connect(); - } + DatabaseInstance._internal(); } @@ -36,11 +34,16 @@ abstract class DatabaseConnector{ ); }, // Set the version. This executes the onCreate function and provides a - // path to perform database upgrades and downgrades. + // path to perform database upgrades and downgrades version: 1, ); } + Future<void> delete() async{ + deleteDatabase(join(await getDatabasesPath(), eventDatabase)); //NOTE: deletes everything. Just use for debug! + await connect(); //Create a new and empty database + } + Future<int> addEvent(Event event) async { int rowId = 0; rowId = await database.insert( diff --git a/lib/datamodel.dart b/lib/datamodel.dart index ad65c305c528f6e88fa2e07f8cba202e2bd55345..4f7975cbd21a43f4d0400b97bed7715e5ed49bc0 100644 --- a/lib/datamodel.dart +++ b/lib/datamodel.dart @@ -1,5 +1,4 @@ - import 'dart:convert'; import 'package:flutter/cupertino.dart'; @@ -31,7 +30,7 @@ class Collection { @override String toString(){ - return collectionName; + return collectionName + ' ' + id.toString() + ' ' + description; } } @@ -256,6 +255,42 @@ abstract class ConfigurationStoreBase { SensorLogin loginInformation = SensorLogin('', ''); bool initialized = false; + Map<String, dynamic> toMap() { + return { + 'collections' : jsonEncode(collections), + 'currentCollection': currentCollection.toJson(), + 'devices': jsonEncode(devices), + 'eventTypes': jsonEncode(eventTypes), + 'loginInformation' : loginInformation.toJson(), + 'initialized' : initialized, + }; + } + + void fromMap(Map<String, dynamic> map) { + List<dynamic> dynList = jsonDecode(map['collections']); + collections = []; + for (var element in dynList){ + collections.add(Collection.fromJson(element)); + } + currentCollection = Collection.fromJson(map['currentCollection']); + + dynList = jsonDecode(map['devices']); + devices = []; + for (var element in dynList){ + devices.add(Device.fromJson(element)); + } + + dynList = jsonDecode(map['eventTypes']); + eventTypes = []; + for (var element in dynList){ + eventTypes.add(EventType.fromJson(element)); + } + + loginInformation = SensorLogin.fromJson(map['loginInformation']); + initialized = map['initialized']; + } + + Collection getCollectionFromName(String name) { for (var collection in collections) { if (collection.collectionName == name) { @@ -283,6 +318,8 @@ abstract class ConfigurationStoreBase { throw Exception('Event with name :' + name + ' was not found.'); } + + void reset(){ collections = []; devices = []; @@ -311,7 +348,6 @@ class ConfigurationStoreInstance extends ConfigurationStoreBase { abstract class EventStoreBase{ - //List<Event> events = []; Event currentEvent = Event( id: 0, urnId:-1, @@ -328,35 +364,35 @@ abstract class EventStoreBase{ elevation: '' ); - /* - int getPendingEventCount(List<Event> events){ - int count = 0; - for (var event in events) { - if (event.status == 'PENDING') { - count++; - } - } - return count; + Map<String, dynamic> toMap() { + return { + 'currentEvent' : currentEvent.toJson() + }; } - */ - //String getEventDump(List<Event> events){ - // String ev = '['; - - // for (var event in events) { - // ev += jsonEncode(event); - // ev += ','; - // } - // ev += ']'; - // return ev; - //} - - //fromEventDump(dump){ - // events = []; - // for (var entry in dump) { - // debugPrint('Added Event from Storage: ' + entry.toString()); - // events.add(Event.fromJson(entry)); - // } - //} + + void fromMap(Map<String, dynamic> map) { + currentEvent = Event.fromJson(map['currentEvent']); + } + + +//String getEventDump(List<Event> events){ +// String ev = '['; + +// for (var event in events) { +// ev += jsonEncode(event); +// ev += ','; +// } +// ev += ']'; +// return ev; +//} + +//fromEventDump(dump){ +// events = []; +// for (var entry in dump) { +// debugPrint('Added Event from Storage: ' + entry.toString()); +// events.add(Event.fromJson(entry)); +// } +//} } @@ -368,7 +404,6 @@ class EventStoreInstance extends EventStoreBase { } EventStoreInstance._internal() { - //events = []; currentEvent = Event( id:0, urnId:-1, @@ -387,7 +422,6 @@ class EventStoreInstance extends EventStoreBase { } void reset(){ - //events = []; currentEvent = Event( id:0, urnId:-1, diff --git a/lib/main.dart b/lib/main.dart index 68ab8a3ef63a3a882e854e2982087b388302f9ac..f68d4208121bc11a5912ed1cfe440f4df44bddcd 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,7 +1,5 @@ -import 'dart:io'; - +import 'dart:convert'; import 'package:flutter/material.dart'; -import 'package:path_provider/path_provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'datamodel.dart'; @@ -11,64 +9,42 @@ import 'overview.dart'; import 'configuration.dart'; import 'databaseconnector.dart'; -Future<void> pathStuff() async { - - - - - //Directory downloadsDirectory = await DownloadsPathProvider.downloadsDirectory; - - //Directory appDocDir = await getApplicationDocumentsDirectory(); - - //debugPrint(appDocDir.path.toString()); - - +Future<void> loadConfiguration() async { + final ConfigurationStoreInstance configuration = ConfigurationStoreInstance(); + final EventStoreInstance event = EventStoreInstance(); WidgetsFlutterBinding.ensureInitialized(); final prefs = await SharedPreferences.getInstance(); - //prefs.setString('events', 'blabla'); - final String? events = prefs.getString('events'); - print('Shared Preferences: ' + events!); + final String? storedConfiguration = prefs.getString('configuration'); + if (storedConfiguration != null){ + debugPrint('Configuration String: ' + storedConfiguration); + configuration.fromMap(jsonDecode(storedConfiguration)); + debugPrint('Configuration loaded from shared preferences'); + }else{ + debugPrint('Failed to load configuration from shared preferences.'); + } - //const storage = FlutterSecureStorage(); + final String? currentEvent = prefs.getString('currentEvent'); + if (currentEvent != null){ + debugPrint('Configuration Current Event String: ' + currentEvent); + event.fromMap(jsonDecode(currentEvent)); + debugPrint('Configuration Current Event loaded from shared preferences'); + }else{ + debugPrint('Failed to load Current Event configuration from shared preferences.'); + } + + + //const storage = FlutterSecureStorage(); //TODO: move login information to secure storage //Map<String, String> allValues = await storage.readAll(); //print('Secure Storage: ' + allValues.toString()); var database = DatabaseInstance(); await database.connect(); //Do once at start of APP! - - Event event = Event.fromJson({"id":0,"urnId":102,"urn":"mooring:f9-12","label":"hggg","type":"Calibration", - "typeId":15,"description":"ggggg","status":"PENDING", - "startDate":"2022-03-28T07:00:02.712112Z", - "endDate":"2022-03-28T07:00:02.712112Z","latitude":"53.5440109", - "longitude":"8.58033187","elevation":"48.7139892578125"}); - - List<Event> tempEvents = []; - - //Update second event in sql database - event.id = 2; - event.description = 'updated description1'; - //database.updateEvent(event); - - - //debugPrint("Add Event to database: " + event.toString()); - //int rowId = await database.addEvent(event); - //debugPrint("Events row Id: " + rowId.toString()); - - tempEvents = await database.getEvents(); - debugPrint("Events in SQL Database: "); - for (var event in tempEvents){ - debugPrint(event.toString()); - } } void main() { - - - pathStuff(); - - - + loadConfiguration(); + EventStoreInstance events = EventStoreInstance(); final ConfigurationStoreInstance configuration = ConfigurationStoreInstance(); @@ -78,32 +54,6 @@ void main() { configuration.loginInformation = SensorLogin.fromJson({"mail":"admin","password":"adminadmin"}); //TODO: replace for productive version. - //Load data from storage: - //events.currentEvent = Event.fromJson({"id":102,"urn":"mooring:f9-12","label":"gg","type":"Calibration","typeId":15,"description":"gvg","status":"EXPORTED","startDate":"2022-03-25T09:24:48.856120Z","endDate":"2022-03-25T09:24:48.856120Z","latitude":"53.54388522","longitude":"8.58144825","elevation":"1.9925537109375"}); - //events.events.add(Event.fromJson({"id":102,"urn":"mooring:f9-12","label":"gg","type":"Calibration","typeId":15,"description":"gvg","status":"EXPORTED","startDate":"2022-03-25T09:24:48.856120Z","endDate":"2022-03-25T09:24:48.856120Z","latitude":"53.54388522","longitude":"8.58144825","elevation":"1.9925537109375"})); - //configuration.devices.add(Device.fromJson({"id":102,"urn":"mooring:f9-12"})); - //configuration.eventTypes.add(EventType.fromJson({"id":15,"name":"Calibration"})); - //configuration.currentCollection = Collection.fromJson({"id":1,"description":"","collectionName":"FRAM"}); - //configuration.initialized = true; - - /* -events.fromEventDump( - [ - {"id":1,"urnId":102,"urn":"mooring:f9-12","label":"hggg","type":"Calibration", - "typeId":15,"description":"ggggg","status":"PENDING", - "startDate":"2022-03-28T07:00:02.712112Z", - "endDate":"2022-03-28T07:00:02.712112Z","latitude":"53.5440109", - "longitude":"8.58033187","elevation":"48.7139892578125"}, - {"id":2,"urnId":102,"urn":"mooring:f9-12","label":"hggg","type":"Calibration", - "typeId":15,"description":"ggggg","status":"PENDING", - "startDate":"2022-03-28T07:00:03.828190Z", - "endDate":"2022-03-28T07:00:03.828190Z","latitude":"53.54401033", - "longitude":"8.58032778","elevation":"48.720947265625"}, - ]); - //events.fromEventDump([{"id":102,"urn":"mooring:f9-12","label":"cf","type":"Calibration","typeId":15,"description":"fd","status":"PENDING","startDate":"2022-03-25T12:47:30.659436Z","endDate":"2022-03-25T12:47:30.659436Z","latitude":"","longitude":"","elevation":""},{"id":102,"urn":"mooring:f9-12","label":"cf","type":"Calibration","typeId":15,"description":"fd","status":"PENDING","startDate":"2022-03-25T12:47:32.136009Z","endDate":"2022-03-25T12:47:32.136009Z","latitude":"","longitude":"","elevation":""}]); - -*/ - runApp(MaterialApp( title: 'Mobile Event Log', theme: ThemeData( diff --git a/lib/viewevents.dart b/lib/viewevents.dart index fde41accab282608dd09f675dc02249659ef83fa..880614c3faa54729b14fa6ede9ee9a0e181dfba3 100644 --- a/lib/viewevents.dart +++ b/lib/viewevents.dart @@ -39,7 +39,6 @@ class _ViewEvents extends State<ViewEvents> { void initState() { _syncStatus = ''; super.initState(); - fetchEventsFromDb(); } @@ -48,42 +47,36 @@ class _ViewEvents extends State<ViewEvents> { SensorConnector connection = SensorConnector(); List<Event> events = await database.getPendingEvents(); + int syncCounter = events.length; debugPrint('Pending Events'); for (var event in events){ debugPrint(event.toString()); } - int syncCounter = events.length; - if(syncCounter > 0) { try { String? token = await connection.getAuthToken( configuration.loginInformation.mail, configuration.loginInformation.password); - - if (token != null) { - debugPrint('Number of Events: ' + events.length.toString()); - debugPrint('Number of Pending Events: ' + syncCounter.toString()); - var index = 0; - for (var event in events) { - debugPrint('Idx: ' + index.toString() + ' ' + - event.toSensorJson().toString()); - index++; - if (await connection.putEvent(event, token) == true) { - //Event has been posted to Sensor. - syncCounter--; - debugPrint( - 'put success, remaining events: ' + syncCounter.toString()); - event.status = 'EXPORTED'; //Update event to export only once - database.updateEvent(event); //Update Event in SQL Database - fetchEventsFromDb(); //update view list //TODO: this is bad performance - setState(() {}); - } else { - throw Exception('Sync for ' + event.urn + 'failed'); - } + var index = 0; + for (var event in events) { + debugPrint('Idx: ' + index.toString() + ' ' + + event.toSensorJson().toString()); + index++; + if (await connection.putEvent(event, token) == true) { + //Event has been posted to Sensor. + syncCounter--; + debugPrint( + 'put success, remaining events: ' + syncCounter.toString()); + event.status = 'EXPORTED'; //Update event to export only once + database.updateEvent(event); //Update Event as exported in SQL Database + fetchEventsFromDb(); //update view list //TODO: this is bad for the sync performance! Consider working with localevent list for the UI! + setState(() {}); + } else { + throw Exception('Sync for ' + event.urn + 'failed'); } - _syncStatus = 'export success'; } + _syncStatus = 'export success'; } on SocketException catch (e) { debugPrint('Exception: $e'); _syncStatus = 'No connection'; @@ -94,13 +87,12 @@ class _ViewEvents extends State<ViewEvents> { setState(() {}); } }else{ - debugPrint('Nothing to export'); + debugPrint('No PENDING event(s)'); } } @override Widget build(BuildContext context) { - return Scaffold( appBar: AppBar( title: const Text("View & Sync"), @@ -269,9 +261,6 @@ class _ViewEvents extends State<ViewEvents> { icon: null, label: const Text('Sync'), onPressed: () { - //debugPrint(_events.getEventDump()); - - syncEvents(); }, ),