import 'dart:convert'; import 'package:flutter/cupertino.dart'; import 'package:flutter/services.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:package_info_plus/package_info_plus.dart'; class Collection { int id; String description; String collectionName; Collection({ required this.id, required this.description, required this.collectionName, }); factory Collection.fromJson(Map<String, dynamic> json) { return Collection( id: json['id'], description: json['description'], collectionName: json['collectionName'], ); } Map<String, dynamic> toJson() => { 'id': id, 'description': description, 'collectionName' : collectionName }; @override String toString(){ return collectionName + ' ' + id.toString() + ' ' + description; } } class Device{ int id; String urn; Device(this.id, this.urn); factory Device.fromJson(Map<String, dynamic> json){ return Device( json['id'] as int, json['urn'] as String); } Map<String, dynamic> toJson() => { 'id': id, 'urn': urn }; @override String toString(){ return urn; } } class Event{ int id; //This shall be the mysql primary key database id int urnId; String urn; String label; String type; // Event type name TODO: this should be an EventType variable int typeId; String description; String status; String startDate; String endDate; String latitude; String longitude; String elevation; Event({ required this.id, required this.urnId, required this.urn, required this.label, required this.type, required this.typeId, required this.description, required this.status, required this.startDate, required this.endDate, required this.latitude, required this.longitude, required this.elevation, }); factory Event.fromEvent(Event event){ return Event( id: event.id, urnId: event.urnId, urn: event.urn, label: event.label, type: event.type, typeId: event.typeId, description: event.description, status: event.status, startDate: event.startDate, endDate: event.endDate, latitude: event.latitude, longitude: event.longitude, elevation: event.elevation, ); } factory Event.fromJson(Map<String, dynamic> json){ return Event( id: json['id'], urnId: json['urnId'], urn: json['urn'], label: json['label'], type: json['type'], typeId: json['typeId'], description: json['description'], status: json['status'], startDate: json['startDate'], endDate: json['endDate'], latitude: json['latitude'], longitude: json['longitude'], elevation: json['elevation'], ); } Map<String, dynamic> toMap() { return { 'id' : id, 'urnId': urnId, 'urn': urn, 'label': label, 'type' : type, 'typeId' : typeId, 'description' : description, 'status' : status, 'startDate' : startDate, 'endDate' : endDate, 'latitude' : latitude, 'longitude' : longitude, 'elevation' : elevation }; } Map<String, dynamic> toMapNoId() { return { 'urnId': urnId, 'urn': urn, 'label': label, 'type' : type, 'typeId' : typeId, 'description' : description, 'status' : status, 'startDate' : startDate, 'endDate' : endDate, 'latitude' : latitude, 'longitude' : longitude, 'elevation' : elevation }; } Map<String, dynamic> toJson() => { 'id' : id, 'urnId': urnId, 'urn': urn, 'label': label, 'type' : type, 'typeId' : typeId, 'description' : description, 'status' : status, 'startDate' : startDate, 'endDate' : endDate, 'latitude' : latitude, 'longitude' : longitude, 'elevation' : elevation }; Map<String, dynamic> toSensorJson() { return { "\"itemID\"":"\"$urnId\"", "\"inheritToAllChildren\"":"\"false\"", "\"inheritToChildren\"":[], "\"event\"":{ "\"startDate\"":"\"$startDate\"", "\"endDate\"":"\"$endDate\"", "\"label\"":"\"$label\"", "\"description\"":"\"$description\"", "\"eventType\"":"\"$typeId\"", "\"latitude\"":"\"$latitude\"", "\"longitude\"":"\"$longitude\"", "\"elevationInMeter\"":"\"$elevation\"", "\"id\"":"\"0\"" } }; } @override String toString(){ return '{ ' '${this.id}, ' '${this.urnId}, ' '${this.urn}, ' '${this.label}, ' '${this.type}, ' '${this.description}, ' '${this.startDate}, ' '${this.endDate}, ' '${this.latitude},' '${this.longitude},' '${this.elevation},' '${this.status} }'; } } class EventType{ int id; String name; EventType({ required this.id, required this.name }); EventType.fromSensorJson(Map<String, dynamic> json) : id = json['id'], name = json['generalName']; EventType.fromJson(Map<String, dynamic> json) : id = json['id'], name = json['name']; Map<String, dynamic> toJson() => { 'id': id, 'name': name, }; @override String toString(){ return name; } } class LabelConfiguration{ int cnt; String prefix; LabelConfiguration( this.cnt, this.prefix ); Map<String, dynamic> toJson() => { "prefix": prefix, "cnt": cnt }; LabelConfiguration.fromJson(Map<String, dynamic> json) : prefix = json['prefix'], cnt = json['cnt']; } class SensorLogin{ String mail; String password; SensorLogin( this.mail, this.password, ); Map<String, dynamic> toJson() => { "mail": mail, "password": password }; SensorLogin.fromJson(Map<String, dynamic> json) : mail = json['mail'], password = json['password']; } // Storage classes // ConfigurationStoreBase for Collection, devices, event types, login information // EventStoreBase for created event information. abstract class ConfigurationStoreBase { List<Collection> collections = []; Collection currentCollection = Collection(id: -1, description: '', collectionName: ''); List<Device> devices = []; List<EventType> eventTypes = []; SensorLogin loginInformation = SensorLogin('', ''); LabelConfiguration labelConfig = LabelConfiguration(0, ''); String restRequestUrl = ''; bool initialized = false; Map<String, dynamic> toMap() { return { 'collections' : jsonEncode(collections), 'currentCollection': currentCollection.toJson(), 'devices': jsonEncode(devices), 'eventTypes': jsonEncode(eventTypes), 'initialized' : initialized, 'labelConfiguration' : jsonEncode(labelConfig), 'restRequestUrl' : restRequestUrl, }; } Map<String, dynamic> loginDataToMap() { return { 'loginInformation' : loginInformation.toJson(), }; } void loginDataFromMap(Map<String, dynamic> map){ loginInformation = SensorLogin.fromJson(map['loginInformation']); } 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)); } labelConfig = LabelConfiguration.fromJson(map['labelConfiguration']); restRequestUrl = map['restRequestUrl']; initialized = map['initialized']; } Collection getCollectionFromName(String name) { for (var collection in collections) { if (collection.collectionName == name) { return collection; } } throw Exception('Event with name :' + name + ' was not found.'); } int getDeviceIdFromUrn(String urn) { for (var device in devices) { if (device.urn == urn) { return device.id; } } throw Exception('Device with urn:' + urn + ' was not found.'); } int getEventIdFromName(String name) { for (var eventType in eventTypes) { if (eventType.name == name) { return eventType.id; } } throw Exception('Event with name :' + name + ' was not found.'); } void reset(){ collections = []; devices = []; eventTypes = []; currentCollection = Collection(id: -1, description: '', collectionName: ''); loginInformation = SensorLogin('', ''); initialized = false; } } class ConfigurationStoreInstance extends ConfigurationStoreBase { static final ConfigurationStoreInstance _instance = ConfigurationStoreInstance ._internal(); @override void reset(){ super.reset(); deleteSharedPrefs(); } Future<void> storeToSharedPrefs() async { const secureStorage = FlutterSecureStorage(); var writeData = await secureStorage.write(key: 'login', value: jsonEncode(loginDataToMap())); final prefs = await SharedPreferences.getInstance(); prefs.setString('configuration', jsonEncode(toMap())); debugPrint('Stored current configuration to shared prefs'); } Future<void> loadFromSharedPrefs() async { const secureStorage = FlutterSecureStorage(); final String? readData = await secureStorage.read(key: 'login'); if (readData != null) { loginDataFromMap(jsonDecode(readData)); debugPrint('Login loaded from secure storage'); }else{ debugPrint('Failed to load login details from secure storage'); } final prefs = await SharedPreferences.getInstance(); final String? configuration = prefs.getString('configuration'); if (configuration != null){ debugPrint('Configuration String: ' + configuration); fromMap(jsonDecode(configuration)); debugPrint('Configuration loaded from shared preferences'); }else{ debugPrint('Failed to load configuration from shared preferences.'); } } Future<void> deleteSharedPrefs() async { final prefs = await SharedPreferences.getInstance(); prefs.clear(); await prefs.remove('configuration'); const secureStorage = FlutterSecureStorage(); secureStorage.delete(key: 'login'); } factory ConfigurationStoreInstance() { return _instance; } ConfigurationStoreInstance._internal() { collections = []; devices = []; eventTypes = []; } } abstract class EventStoreBase{ bool gnssSync = true; bool showAllEvents = false; Event currentEvent = Event( id: 0, urnId:-1, urn:'urn0', label:'', type:'', typeId:-1, description:'', status:'PENDING', startDate:'', endDate: '', latitude: '', longitude: '', elevation: '' ); Map<String, dynamic> toMap() { return { 'currentEvent' : currentEvent.toJson(), 'gnssSync' : gnssSync, 'showAllEvents' : showAllEvents }; } void fromMap(Map<String, dynamic> map) { currentEvent = Event.fromJson(map['currentEvent']); gnssSync = map['gnssSync']; showAllEvents = map['showAllEvents']; } } class EventStoreInstance extends EventStoreBase { static final EventStoreInstance _instance = EventStoreInstance._internal(); Future<void> storeToSharedPrefs() async { final prefs = await SharedPreferences.getInstance(); prefs.setString('currentEvent', jsonEncode(toMap())); debugPrint('Stored current event to shared prefs'); } Future<void> loadFromSharedPrefs() async { final prefs = await SharedPreferences.getInstance(); final String? currentEvent = prefs.getString('currentEvent'); if (currentEvent != null){ debugPrint('Configuration Current Event String: ' + currentEvent); fromMap(jsonDecode(currentEvent)); debugPrint('Configuration Current Event loaded from shared preferences'); }else{ debugPrint('Failed to load Current Event configuration from shared preferences.'); } } Future<void> deleteSharedPrefs() async { final prefs = await SharedPreferences.getInstance(); await prefs.remove('currentEvent'); } factory EventStoreInstance() { return _instance; } EventStoreInstance._internal() { currentEvent = Event( id:0, urnId:-1, urn:'urn0', label:'', type:'', typeId:-1, description:'', status:'PENDING', startDate:'', endDate: '', latitude: '', longitude: '', elevation: '' );; } void reset(){ gnssSync = true; showAllEvents = false; currentEvent = Event( id:0, urnId:-1, urn:'urn0', label:'', type:'', typeId:-1, description:'', status:'PENDING', startDate:'', endDate: '', latitude: '', longitude: '', elevation: '' ); deleteSharedPrefs(); } } String versionNumber = ''; String buildNumber = ''; Future<void> loadVersionInfo() async { PackageInfo packageInfo = await PackageInfo.fromPlatform(); versionNumber = packageInfo.version; buildNumber = packageInfo.buildNumber; } String getVersion(){ return versionNumber; } String getBuildNumber(){ return buildNumber; }