Commit cf419147 authored by Nicolas Richard Walter Boeckh's avatar Nicolas Richard Walter Boeckh 💬

Merge branch 'ux-upgrades' into 'main'

Ux upgrades

See merge request !8
parents 8d46dd31 90c4dbfe
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"connectivity","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\connectivity-0.4.9+2\\\\","dependencies":[]},{"name":"flutter_blue","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\flutter_blue-0.7.2\\\\","dependencies":[]},{"name":"geolocator","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\geolocator-5.2.1\\\\","dependencies":["google_api_availability","location_permissions"]},{"name":"google_api_availability","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\google_api_availability-2.0.2\\\\","dependencies":[]},{"name":"location_permissions","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\location_permissions-2.0.4+1\\\\","dependencies":[]},{"name":"path_provider","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\path_provider-1.6.0\\\\","dependencies":[]},{"name":"permission_handler","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\permission_handler-4.2.0+hotfix.3\\\\","dependencies":[]},{"name":"shared_preferences","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\shared_preferences-0.5.7+2\\\\","dependencies":[]},{"name":"sqflite","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\sqflite-1.2.0\\\\","dependencies":[]}],"android":[{"name":"connectivity","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\connectivity-0.4.9+2\\\\","dependencies":[]},{"name":"flutter_blue","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\flutter_blue-0.7.2\\\\","dependencies":[]},{"name":"geolocator","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\geolocator-5.2.1\\\\","dependencies":["google_api_availability","location_permissions"]},{"name":"google_api_availability","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\google_api_availability-2.0.2\\\\","dependencies":[]},{"name":"location_permissions","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\location_permissions-2.0.4+1\\\\","dependencies":[]},{"name":"path_provider","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\path_provider-1.6.0\\\\","dependencies":[]},{"name":"permission_handler","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\permission_handler-4.2.0+hotfix.3\\\\","dependencies":[]},{"name":"shared_preferences","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\shared_preferences-0.5.7+2\\\\","dependencies":[]},{"name":"sqflite","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\sqflite-1.2.0\\\\","dependencies":[]}],"macos":[{"name":"connectivity_macos","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\connectivity_macos-0.1.0+4\\\\","dependencies":[]},{"name":"shared_preferences_macos","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\shared_preferences_macos-0.0.1+8\\\\","dependencies":[]},{"name":"sqflite","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\sqflite-1.2.0\\\\","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"connectivity_for_web","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\connectivity_for_web-0.3.1+2\\\\","dependencies":[]},{"name":"shared_preferences_web","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\shared_preferences_web-0.1.2+5\\\\","dependencies":[]}]},"dependencyGraph":[{"name":"connectivity","dependencies":["connectivity_macos","connectivity_for_web"]},{"name":"connectivity_for_web","dependencies":[]},{"name":"connectivity_macos","dependencies":[]},{"name":"flutter_blue","dependencies":[]},{"name":"geolocator","dependencies":["google_api_availability","location_permissions"]},{"name":"google_api_availability","dependencies":[]},{"name":"location_permissions","dependencies":[]},{"name":"path_provider","dependencies":[]},{"name":"permission_handler","dependencies":[]},{"name":"shared_preferences","dependencies":["shared_preferences_macos","shared_preferences_web"]},{"name":"shared_preferences_macos","dependencies":[]},{"name":"shared_preferences_web","dependencies":[]},{"name":"sqflite","dependencies":[]}],"date_created":"2020-09-07 01:52:18.814120","version":"1.21.0-10.0.pre.193"} {"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"app_settings","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\app_settings-4.0.3\\\\","dependencies":[]},{"name":"connectivity","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\connectivity-0.4.9+2\\\\","dependencies":[]},{"name":"flutter_blue","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\flutter_blue-0.7.2\\\\","dependencies":[]},{"name":"geolocator","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\geolocator-5.2.1\\\\","dependencies":["google_api_availability","location_permissions"]},{"name":"google_api_availability","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\google_api_availability-2.0.2\\\\","dependencies":[]},{"name":"location_permissions","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\location_permissions-2.0.4+1\\\\","dependencies":[]},{"name":"path_provider","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\path_provider-1.6.0\\\\","dependencies":[]},{"name":"permission_handler","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\permission_handler-4.2.0+hotfix.3\\\\","dependencies":[]},{"name":"shared_preferences","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\shared_preferences-0.5.7+2\\\\","dependencies":[]},{"name":"sqflite","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\sqflite-1.2.0\\\\","dependencies":[]}],"android":[{"name":"app_settings","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\app_settings-4.0.3\\\\","dependencies":[]},{"name":"connectivity","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\connectivity-0.4.9+2\\\\","dependencies":[]},{"name":"flutter_blue","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\flutter_blue-0.7.2\\\\","dependencies":[]},{"name":"geolocator","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\geolocator-5.2.1\\\\","dependencies":["google_api_availability","location_permissions"]},{"name":"google_api_availability","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\google_api_availability-2.0.2\\\\","dependencies":[]},{"name":"location_permissions","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\location_permissions-2.0.4+1\\\\","dependencies":[]},{"name":"path_provider","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\path_provider-1.6.0\\\\","dependencies":[]},{"name":"permission_handler","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\permission_handler-4.2.0+hotfix.3\\\\","dependencies":[]},{"name":"shared_preferences","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\shared_preferences-0.5.7+2\\\\","dependencies":[]},{"name":"sqflite","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\sqflite-1.2.0\\\\","dependencies":[]}],"macos":[{"name":"connectivity_macos","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\connectivity_macos-0.1.0+4\\\\","dependencies":[]},{"name":"shared_preferences_macos","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\shared_preferences_macos-0.0.1+8\\\\","dependencies":[]},{"name":"sqflite","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\sqflite-1.2.0\\\\","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"connectivity_for_web","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\connectivity_for_web-0.3.1+2\\\\","dependencies":[]},{"name":"shared_preferences_web","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\shared_preferences_web-0.1.2+5\\\\","dependencies":[]}]},"dependencyGraph":[{"name":"app_settings","dependencies":[]},{"name":"connectivity","dependencies":["connectivity_macos","connectivity_for_web"]},{"name":"connectivity_for_web","dependencies":[]},{"name":"connectivity_macos","dependencies":[]},{"name":"flutter_blue","dependencies":[]},{"name":"geolocator","dependencies":["google_api_availability","location_permissions"]},{"name":"google_api_availability","dependencies":[]},{"name":"location_permissions","dependencies":[]},{"name":"path_provider","dependencies":[]},{"name":"permission_handler","dependencies":[]},{"name":"shared_preferences","dependencies":["shared_preferences_macos","shared_preferences_web"]},{"name":"shared_preferences_macos","dependencies":[]},{"name":"shared_preferences_web","dependencies":[]},{"name":"sqflite","dependencies":[]}],"date_created":"2020-09-14 03:13:52.288184","version":"1.21.0-10.0.pre.193"}
\ No newline at end of file \ No newline at end of file
...@@ -15,6 +15,25 @@ flutter pub pub run intl_translation:extract_to_arb --output-dir=lib/localizatio ...@@ -15,6 +15,25 @@ flutter pub pub run intl_translation:extract_to_arb --output-dir=lib/localizatio
flutter pub pub run intl_translation:generate_from_arb --output-dir=lib/localization/l10n --no-use-deferred-loading lib/localization/localization.dart lib/localization/l10n/intl_en.arb lib/localization/l10n/intl_fr.arb flutter pub pub run intl_translation:generate_from_arb --output-dir=lib/localization/l10n --no-use-deferred-loading lib/localization/localization.dart lib/localization/l10n/intl_en.arb lib/localization/l10n/intl_fr.arb
``` ```
## Documentation
You can generate the application documentation yourself using the following command :
```bash
dartdoc
```
<details>
<summary>In case of "dartdoc failed: Invalid argument(s): join(null, "bin", "cache", "dart-sdk")"</summary>
Set the following environment variable:
```bash
FLUTTER_ROOT=<path_to_flutter_root_folder>
```
</details>
## File Structure ## File Structure
The project is divided in multiple components: The project is divided in multiple components:
......
...@@ -6,6 +6,9 @@ ...@@ -6,6 +6,9 @@
additional functionality it is fine to subclass or reimplement additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. --> FlutterApplication and put your custom class here. -->
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<application <application
android:name="io.flutter.app.FlutterApplication" android:name="io.flutter.app.FlutterApplication"
android:label="logair.io" android:label="logair.io"
......
...@@ -12,7 +12,7 @@ class AppLocalizationDelegate extends LocalizationsDelegate<AppLocalization> { ...@@ -12,7 +12,7 @@ class AppLocalizationDelegate extends LocalizationsDelegate<AppLocalization> {
'fr' 'fr'
].contains(locale.languageCode); ].contains(locale.languageCode);
/// Delegates the loading of [Locale] to an [async] task, which enables it to be done in the background. /// Delegates the loading of [Locale] to an async task, which enables it to be done in the background.
@override @override
Future<AppLocalization> load(Locale locale) => AppLocalization.load(locale); Future<AppLocalization> load(Locale locale) => AppLocalization.load(locale);
......
...@@ -16,6 +16,7 @@ class HomeController { ...@@ -16,6 +16,7 @@ class HomeController {
factory HomeController() => _singleton; factory HomeController() => _singleton;
/// [HomeController] initializer that sets the default initial values.
HomeController._internal() { HomeController._internal() {
this._currentPage = 0; this._currentPage = 0;
this._previousPage = 0; this._previousPage = 0;
......
...@@ -4,14 +4,14 @@ import 'package:flutter/material.dart'; ...@@ -4,14 +4,14 @@ import 'package:flutter/material.dart';
import 'package:flutter_map/plugin_api.dart'; import 'package:flutter_map/plugin_api.dart';
import 'package:latlong/latlong.dart'; import 'package:latlong/latlong.dart';
import 'package:logair_application/logic/handlers/data_handler.dart'; import 'package:logair_application/logic/handlers/data_handler.dart';
import 'package:logair_application/logic/handlers/database_handler.dart'; import 'package:logair_application/logic/handlers/main_database_handler.dart';
import 'package:logair_application/logic/handlers/network_handler.dart'; import 'package:logair_application/logic/handlers/network_handler.dart';
import 'package:logair_application/logic/data_header.dart'; import 'package:logair_application/logic/data_header.dart';
import 'package:logair_application/logic/data_packet.dart'; import 'package:logair_application/logic/data_packet.dart';
import 'package:logair_application/logic/handlers/position_handler.dart'; import 'package:logair_application/logic/handlers/position_handler.dart';
import 'package:logair_application/utils/enums/pm_symbol.dart'; import 'package:logair_application/utils/enums/pm_symbol.dart';
/// The [MapDisplayController] is a [Singleton] that handles the mapping of information. /// The [MapDisplayController] is a singleton that handles the mapping of information.
class MapDisplayController { class MapDisplayController {
/// Whether or not the user has assumed manual control of the [FlutterMap], /// Whether or not the user has assumed manual control of the [FlutterMap],
bool _manualMotion = false; bool _manualMotion = false;
...@@ -35,20 +35,20 @@ class MapDisplayController { ...@@ -35,20 +35,20 @@ class MapDisplayController {
Marker _marker; Marker _marker;
Future<void> _rebuildMarkers() async { Future<void> _rebuildMarkers() async {
List<DataPacket> packets = await DatabaseHandler().getLastPackets(200); List<DataPacket> packets = await MainDatabaseHandler().getLastPackets(200);
packets.forEach((DataPacket packet) { packets.forEach((DataPacket packet) {
switch (_pmSymbol) { switch (_pmSymbol) {
case PMSymbol.PM1: case PMSymbol.PM1:
this.addToList(this._currentPos, packet.pm1(), 200); this.addToList(this._currentPos, packet.pm1, 200);
break; break;
case PMSymbol.PM1: case PMSymbol.PM1:
this.addToList(this._currentPos, packet.pm2_5(), 200); this.addToList(this._currentPos, packet.pm2_5, 200);
break; break;
case PMSymbol.PM4: case PMSymbol.PM4:
this.addToList(this._currentPos, packet.pm4(), 200); this.addToList(this._currentPos, packet.pm4, 200);
break; break;
case PMSymbol.PM10: case PMSymbol.PM10:
this.addToList(this._currentPos, packet.pm10(), 200); this.addToList(this._currentPos, packet.pm10, 200);
break; break;
default: default:
break; break;
...@@ -90,7 +90,7 @@ class MapDisplayController { ...@@ -90,7 +90,7 @@ class MapDisplayController {
} }
/// This function is executed on first initialization of the [MapDisplayController] /// This function is executed on first initialization of the [MapDisplayController]
/// TODO: Throttle to 1 in 5 updates for efficiency ? // TODO: Throttle to 1 in 5 updates for efficiency ?
MapDisplayController._internal() { MapDisplayController._internal() {
/// A new [MapController] is used as the global Controller. /// A new [MapController] is used as the global Controller.
/// This avoids Garbage Collection rules and enables the [FlutterMap] to survive [State] changes, and other such events. /// This avoids Garbage Collection rules and enables the [FlutterMap] to survive [State] changes, and other such events.
...@@ -103,10 +103,9 @@ class MapDisplayController { ...@@ -103,10 +103,9 @@ class MapDisplayController {
return; return;
/// If a [BluetoothDevice] is connected, then the [DataHandler] will have a [DataPacket] available. /// If a [BluetoothDevice] is connected, then the [DataHandler] will have a [DataPacket] available.
DataPacket latest = DataHandler().getLatestData(); DataPacket latest = null;
/// If the [DataPacket] is older than 5 seconds we invalidate it. /// If the [DataPacket] is older than 5 seconds we invalidate it.
if (latest != null && latest.timestamp() <= (DateTime.now().millisecondsSinceEpoch - 5000)) if (latest != null && latest.timestamp <= (DateTime.now().millisecondsSinceEpoch - 5000))
latest = null; latest = null;
/// Keep track of the last [Position] to draw [Polyline]s. /// Keep track of the last [Position] to draw [Polyline]s.
...@@ -120,6 +119,7 @@ class MapDisplayController { ...@@ -120,6 +119,7 @@ class MapDisplayController {
this._controller.move(this._currentPos, this._zoom); this._controller.move(this._currentPos, this._zoom);
/// Move the [Marker] to the current [Position]. /// Move the [Marker] to the current [Position].
// TODO: Use StreamBuilder in Map.
this._marker = this._buildLocationMarker(this._currentPos); this._marker = this._buildLocationMarker(this._currentPos);
if ((this._lastPos != null && this._currentPos != null)) {// && this._distance.as(LengthUnit.Meter, this._lastPos, this._currentPos) >= 2)) { if ((this._lastPos != null && this._currentPos != null)) {// && this._distance.as(LengthUnit.Meter, this._lastPos, this._currentPos) >= 2)) {
...@@ -136,20 +136,20 @@ class MapDisplayController { ...@@ -136,20 +136,20 @@ class MapDisplayController {
if (latest != null) { if (latest != null) {
switch (_pmSymbol) { switch (_pmSymbol) {
case PMSymbol.PM1: case PMSymbol.PM1:
if (latest.pm1() != null) if (latest.pm1 != null)
this.addToList(this._currentPos, latest.pm1(), 200); this.addToList(this._currentPos, latest.pm1, 200);
break; break;
case PMSymbol.PM2_5: case PMSymbol.PM2_5:
if (latest.pm2_5() != null) if (latest.pm2_5 != null)
this.addToList(this._currentPos, latest.pm2_5(), 200); this.addToList(this._currentPos, latest.pm2_5, 200);
break; break;
case PMSymbol.PM4: case PMSymbol.PM4:
if (latest.pm4() != null) if (latest.pm4 != null)
this.addToList(this._currentPos, latest.pm4(), 200); this.addToList(this._currentPos, latest.pm4, 200);
break; break;
case PMSymbol.PM10: case PMSymbol.PM10:
if (latest.pm10() != null) if (latest.pm10 != null)
this.addToList(this._currentPos, latest.pm10(), 200); this.addToList(this._currentPos, latest.pm10, 200);
break; break;
default: default:
break; break;
...@@ -161,7 +161,7 @@ class MapDisplayController { ...@@ -161,7 +161,7 @@ class MapDisplayController {
new Timer.periodic(Duration(minutes: 1), (Timer t) { new Timer.periodic(Duration(minutes: 1), (Timer t) {
if (this._controller != null && this._controller.bounds != null) { if (this._controller != null && this._controller.bounds != null) {
//print('${this._controller.bounds.southWest}, ${this._controller.bounds.northEast}'); //print('${this._controller.bounds.southWest}, ${this._controller.bounds.northEast}');
NetworkHandler().getProximityPoints(DataHeader().deviceID, this._controller.bounds); NetworkHandler().getProximityPoints(DataHeader().deviceId, this._controller.bounds);
} }
}); });
} }
......
...@@ -19,19 +19,28 @@ class DataHeader { ...@@ -19,19 +19,28 @@ class DataHeader {
bool _headerSet; bool _headerSet;
String _deviceId;
String _url;
void setHeader(List<int> header) { void setHeader(List<int> header) {
this._headerData = String.fromCharCodes(header.sublist(1, header.length - 1)).split(','); this._headerData = String.fromCharCodes(header.sublist(1, header.length - 1)).split(',');
this._deviceId = this._headerData[0];
this._url = this._headerData[1];
this._headerSet = true; this._headerSet = true;
} }
void setHeaderFromExisting({String deviceId = '', String url = ''}) { void setHeaderFromExisting({@required String deviceId, @required String url}) {
this._headerData = [deviceID, url]; this._headerData = [deviceId, url];
this._deviceId = deviceId;
this._url = url;
this._headerSet = true; this._headerSet = true;
} }
/// Retrieve the deviceID from the header /// Retrieve the deviceID from the header
String get deviceID => (this._headerData != null && this._headerData.length > 0) ? this._headerData[0] : ''; String get deviceId => (this._headerSet && this._deviceId != null) ? this._deviceId : '';
String get url => (this._headerData != null && this._headerData.length > 0) ? this._headerData[1] : ''; String get url => (this._headerSet && this._url != null) ? this._url : '';
/// @Getter for _headerSet; /// @Getter for _headerSet;
bool get headerSet => this._headerSet; bool get headerSet => this._headerSet;
...@@ -46,7 +55,7 @@ class DataHeader { ...@@ -46,7 +55,7 @@ class DataHeader {
bool isEqual(List<int> that) => ListEquality().equals(_headerData, that); bool isEqual(List<int> that) => ListEquality().equals(_headerData, that);
// TODO // TODO
Map<String, dynamic> jsonify() => { 'device_id' : this._headerData[0], 'url': '000000000000' }; Map<String, dynamic> jsonify() => { 'device_id' : this.deviceId, 'url': this.url };
void dispose() { void dispose() {
this._headerSet = false; this._headerSet = false;
...@@ -55,7 +64,7 @@ class DataHeader { ...@@ -55,7 +64,7 @@ class DataHeader {
Stream<String> deviceIdStream() async* { Stream<String> deviceIdStream() async* {
while(true) { while(true) {
yield this.deviceID; yield this._deviceId;
await Future.delayed(Duration(seconds: 1)); await Future.delayed(Duration(seconds: 1));
} }
} }
......
...@@ -11,6 +11,7 @@ class DataPacket { ...@@ -11,6 +11,7 @@ class DataPacket {
List<int> _data; List<int> _data;
int _timestamp; int _timestamp;
String _deviceId; String _deviceId;
String _url;
/* Location variables */ /* Location variables */
double _latitude; double _latitude;
...@@ -31,26 +32,32 @@ class DataPacket { ...@@ -31,26 +32,32 @@ class DataPacket {
double _pm10; double _pm10;
// TODO Firmware v2 // TODO Firmware v2
// ignore: unused_field
String _extraData; String _extraData;
int timestamp() => _timestamp; int get timestamp => this._timestamp;
String deviceId() => _deviceId ?? ''; String get deviceId => this._deviceId ?? '';
double latitude() => _latitude; String get url => this._url ?? '';
double longitude() => _longitude; double get latitude => this._latitude;
int altitude() => _altitude; double get longitude => this._longitude;
int heading() => _heading; int get altitude => this._altitude;
double speed() => _speed; int get heading => this._heading;
double temperature() => _temperature; double get speed => this._speed;
double pressure() => _pressure; double get temperature => this._temperature;
double relativeHumidity() => _relativeHumidity; double get pressure => this._pressure;
double pm1() => _pm1; double get relativeHumidity => this._relativeHumidity;
double pm2_5() => _pm2_5; double get pm1 => this._pm1;
double pm4() => _pm4; double get pm2_5 => this._pm2_5;
double pm10() => _pm10; double get pm4 => this._pm4;
double get pm10 => this._pm10;
set deviceId(String newId) => this._deviceId = newId;
set url(String newUrl) => this._url = newUrl;
DataPacket(this._data) { DataPacket(this._data) {
_timestamp = DateTime.now().millisecondsSinceEpoch; _timestamp = DateTime.now().millisecondsSinceEpoch;
List<String> acquiredData = String.fromCharCodes(this._data.sublist(1, this._data.length - 1)).split(','); List<String> acquiredData = String.fromCharCodes(this._data.sublist(1, this._data.length - 1)).split(',');
this._latitude = (acquiredData[0] != '') ? parseDoubleWrapper(acquiredData[0]) : null; this._latitude = (acquiredData[0] != '') ? parseDoubleWrapper(acquiredData[0]) : null;
this._longitude = (acquiredData[1] != '') ? parseDoubleWrapper(acquiredData[1]) : null; this._longitude = (acquiredData[1] != '') ? parseDoubleWrapper(acquiredData[1]) : null;
this._altitude = (acquiredData[2] != '') ? int.tryParse(acquiredData[2]) : null; this._altitude = (acquiredData[2] != '') ? int.tryParse(acquiredData[2]) : null;
...@@ -80,9 +87,15 @@ class DataPacket { ...@@ -80,9 +87,15 @@ class DataPacket {
DataPacket.fromData(this._timestamp, this._latitude, this._longitude, this._altitude, this._speed, this._heading, this._temperature, this._pressure, this._relativeHumidity, this._pm1, this._pm2_5, this._pm4, this._pm10, this._extraData); DataPacket.fromData(this._timestamp, this._latitude, this._longitude, this._altitude, this._speed, this._heading, this._temperature, this._pressure, this._relativeHumidity, this._pm1, this._pm2_5, this._pm4, this._pm10, this._extraData);
// TODO Guard clause
DataPacket.fromMappedData(Map<String, dynamic> data) { DataPacket.fromMappedData(Map<String, dynamic> data) {
List<String> guardSet = ['device_id', 'url', 'timestamp_nix', 'latitude', 'longitude', 'altitude', 'speed', 'heading', 'temperature', 'pressure', 'relative_humidity', 'pm_1', 'pm_2_5', 'pm_4', 'pm_10', 'extra'];
if(data.keys.toList().where((String key) => guardSet.contains(key)).length < guardSet.length) {
throw Exception('Mapped Data Error');
}
this._deviceId = data['device_id']; this._deviceId = data['device_id'];
this._url = data['url'];
this._timestamp = data['timestamp_nix']; this._timestamp = data['timestamp_nix'];
this._latitude = data['latitude']; this._latitude = data['latitude'];
this._longitude = data['longitude']; this._longitude = data['longitude'];
...@@ -90,8 +103,8 @@ class DataPacket { ...@@ -90,8 +103,8 @@ class DataPacket {
this._speed = data['speed']; this._speed = data['speed'];
this._heading = data['heading']; this._heading = data['heading'];
this._temperature = data['temperature']; this._temperature = data['temperature'];
this._relativeHumidity = data['relative_humidity'];
this._pressure = data['pressure']; this._pressure = data['pressure'];
this._relativeHumidity = data['relative_humidity'];
this._pm1 = data['pm_1']; this._pm1 = data['pm_1'];
this._pm2_5 = data['pm_2_5']; this._pm2_5 = data['pm_2_5'];
this._pm4 = data['pm_4']; this._pm4 = data['pm_4'];
...@@ -117,6 +130,7 @@ class DataPacket { ...@@ -117,6 +130,7 @@ class DataPacket {
this._pm10 this._pm10
]; ];
/// Retrieves the DB insertable reference to this packet.
Map<String, dynamic> toMap() { Map<String, dynamic> toMap() {
return { return {
'timestamp_nix': this._timestamp, 'timestamp_nix': this._timestamp,
...@@ -126,13 +140,16 @@ class DataPacket { ...@@ -126,13 +140,16 @@ class DataPacket {
'speed': this._speed, 'speed': this._speed,
'heading': this._heading, 'heading': this._heading,
'temperature': this._temperature, 'temperature': this._temperature,
'relative_humidity': this._temperature, 'relative_humidity': this.relativeHumidity,
'pressure': this._pressure, 'pressure': this._pressure,
'pm_1': this._pm1, 'pm_1': this._pm1,
'pm_2_5': this._pm2_5, 'pm_2_5': this._pm2_5,
'pm_4': this._pm4, 'pm_4': this._pm4,
'pm_10': this._pm10, 'pm_10': this._pm10,
'extra': '' 'extra': '',
'device_id': this._deviceId,
'url': this._url,
}; };
} }
......
...@@ -6,11 +6,12 @@ import 'package:flutter_blue/flutter_blue.dart'; ...@@ -6,11 +6,12 @@ import 'package:flutter_blue/flutter_blue.dart';
import 'package:kotlin_flavor/scope_functions.dart'; import 'package:kotlin_flavor/scope_functions.dart';
import 'package:logair_application/logic/handlers/bluetooth_wake_handler.dart'; import 'package:logair_application/logic/handlers/bluetooth_wake_handler.dart';
import 'package:logair_application/logic/handlers/preference_handler.dart'; import 'package:logair_application/logic/handlers/preference_handler.dart';
import 'package:logair_application/services/wake_service.dart';
import 'package:logair_application/utils/enums/bluetooth_connection_status.dart'; import 'package:logair_application/utils/enums/bluetooth_connection_status.dart';
import 'package:logair_application/logic/handlers/data_handler.dart'; import 'package:logair_application/logic/handlers/data_handler.dart';
import 'package:logair_application/utils/enums/preference_keys.dart'; import 'package:logair_application/utils/enums/preference_keys.dart';
// TODO Attempt reacquiring device after 5 seconds inactivity.
/// Serves as a wrapper class around [FlutterBlue], and helps integrate it into the application with extensions /// Serves as a wrapper class around [FlutterBlue], and helps integrate it into the application with extensions
class BTLEHandler { class BTLEHandler {
/// [Singleton]() instantiation factory. /// [Singleton]() instantiation factory.
...@@ -60,7 +61,7 @@ class BTLEHandler { ...@@ -60,7 +61,7 @@ class BTLEHandler {
Stream<BluetoothConnectionStatus> getConnectionStatus() async* { Stream<BluetoothConnectionStatus> getConnectionStatus() async* {
while (true) { while (true) {
yield _bluetoothConnectionStatus; yield _bluetoothConnectionStatus;
await Future.delayed(Duration(seconds: 2)); await Future.delayed(Duration(milliseconds: 250));
} }
} }
......
import 'dart:async';
import 'package:logair_application/services/wake_service.dart'; import 'package:logair_application/services/wake_service.dart';
/// Handler that wraps the [WakeService] /// Handler that wraps the [WakeService]
/// TODO flutter_blue seems to do so already, needs testing and iOS solution // TODO: Relative end / start -> Start and end with guard instead of switch.
class BTWakeHandler { class BTWakeHandler {
factory BTWakeHandler() => _singleton; factory BTWakeHandler() => _singleton;
......
import 'package:logair_application/logic/handlers/bluetooth_le_handler.dart'; import 'package:logair_application/logic/handlers/bluetooth_le_handler.dart';
import 'package:logair_application/logic/data_header.dart'; import 'package:logair_application/logic/data_header.dart';
import 'package:logair_application/logic/data_packet.dart'; import 'package:logair_application/logic/data_packet.dart';
import 'package:logair_application/logic/handlers/database_handler.dart'; import 'package:logair_application/logic/handlers/main_database_handler.dart';
import 'package:logair_application/logic/handlers/network_handler.dart'; import 'package:logair_application/logic/handlers/network_handler.dart';
class DataHandler { class DataHandler {
...@@ -57,53 +57,56 @@ class DataHandler { ...@@ -57,53 +57,56 @@ class DataHandler {
bool wasSet = DataHeader().headerSet; bool wasSet = DataHeader().headerSet;
DataHeader().setHeader(packet); DataHeader().setHeader(packet);
/// Retroactively add all previous packets /// Retroactively add all previous packets
if (!wasSet && DataHeader().headerSet) if (!wasSet && DataHeader().headerSet) {
_sortedData.forEach((packet) => DatabaseHandler().insertData(packet, DataHeader().deviceID, DataHeader().url)); _sortedData.forEach((dataPacket) {
dataPacket.deviceId = DataHeader().deviceId;
dataPacket.url = DataHeader().url;
MainDatabaseHandler().insertData(dataPacket);
});
}
/// Or if it is a [DataPacket] instance. /// Or if it is a [DataPacket] instance.
} else if (packet[0] == 91) { } else if (packet[0] == 91) {
_sortedData.add(DataPacket(packet));
print('PACKET ${String.fromCharCodes(packet)}'); print('PACKET ${String.fromCharCodes(packet)}');
if (DataHeader().headerSet) DataPacket dataPacket = DataPacket(packet);
DatabaseHandler().insertData(_sortedData.last, DataHeader().deviceID, DataHeader().url); if (DataHeader().headerSet) {
dataPacket.deviceId = DataHeader().deviceId;
dataPacket.url = DataHeader().url;
MainDatabaseHandler().insertData(dataPacket);
} else
_sortedData.add(dataPacket);
} }
} }
/// TODO Used for debugging, later
void printLatest() {
print(_sortedData.last);
}
/// Get the entirety of the [DataPacket]s. /// Get the entirety of the [DataPacket]s.
@deprecated
List<DataPacket> getData() => _sortedData; List<DataPacket> getData() => _sortedData;
/// Remove the entirety of the acquired data. /// Remove the entirety of the acquired data.
@deprecated