Commit 4464e765 authored by Nicolas Richard Walter Boeckh's avatar Nicolas Richard Walter Boeckh 💬
Browse files

Documentation, overview restructuring and lightening

Added:
- Overview Widgets documentation
- `NetworkHandler` new features documentation.
- `Graph` documetation.

Modified:
- Generalized overview widget elements construction.

Fixed:
- Unknown references in docs
- `DataHandler` pop function removed regardless of whether data was pulled from DH or DB (TODO transition to full db mode).
- Moved battery level to icon function to utils because future use in `MainHeader` as well.
parent b83a909e
{"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-09 00:35:24.671242","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":"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-09 14:34:23.725205","version":"1.22.0-2.0.pre.18"}
\ 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:
......
...@@ -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;
......
...@@ -11,7 +11,7 @@ import 'package:logair_application/logic/data_packet.dart'; ...@@ -11,7 +11,7 @@ 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;
...@@ -39,16 +39,16 @@ class MapDisplayController { ...@@ -39,16 +39,16 @@ class MapDisplayController {
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;
...@@ -106,7 +106,7 @@ class MapDisplayController { ...@@ -106,7 +106,7 @@ class MapDisplayController {
DataPacket latest = DataHandler().getLatestData(); DataPacket latest = DataHandler().getLatestData();
/// 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 +120,7 @@ class MapDisplayController { ...@@ -120,6 +120,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 +137,20 @@ class MapDisplayController { ...@@ -136,20 +137,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;
......
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:flutter/cupertino.dart';
/// @ToDeprecate Describes the contents of the data packets /// @ToDeprecate Describes the contents of the data packets
/// @ReplaceBy Includes the device name and a config_file URL /// @ReplaceBy Includes the device name and a config_file URL
......
...@@ -31,22 +31,23 @@ class DataPacket { ...@@ -31,22 +31,23 @@ 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 => _timestamp;
String deviceId() => _deviceId ?? ''; String get deviceId => _deviceId ?? '';
double latitude() => _latitude; double get latitude => _latitude;
double longitude() => _longitude; double get longitude => _longitude;
int altitude() => _altitude; int get altitude => _altitude;
int heading() => _heading; int get heading => _heading;
double speed() => _speed; double get speed => _speed;
double temperature() => _temperature; double get temperature => _temperature;
double pressure() => _pressure; double get pressure => _pressure;
double relativeHumidity() => _relativeHumidity; double get relativeHumidity => _relativeHumidity;
double pm1() => _pm1; double get pm1 => _pm1;
double pm2_5() => _pm2_5; double get pm2_5 => _pm2_5;
double pm4() => _pm4; double get pm4 => _pm4;
double pm10() => _pm10; double get pm10 => _pm10;
DataPacket(this._data) { DataPacket(this._data) {
_timestamp = DateTime.now().millisecondsSinceEpoch; _timestamp = DateTime.now().millisecondsSinceEpoch;
......
...@@ -3,7 +3,7 @@ import 'dart:async'; ...@@ -3,7 +3,7 @@ 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;
......
...@@ -82,9 +82,9 @@ class DataHandler { ...@@ -82,9 +82,9 @@ class DataHandler {
} }
/// Remove the first element of the [DataPacket]s. Used for surgical removal. /// Remove the first element of the [DataPacket]s. Used for surgical removal.
void pop() { void pop(int timestamp) {
if (_sortedData.isNotEmpty) if (_sortedData.isNotEmpty)
_sortedData.removeAt(0); _sortedData.removeWhere((DataPacket d) => d.timestamp == timestamp);
} }
/// Get the latest [DataPacket] /// Get the latest [DataPacket]
...@@ -98,6 +98,7 @@ class DataHandler { ...@@ -98,6 +98,7 @@ class DataHandler {
} }
} }
@deprecated
Stream<DataPacket> getMockDataStream() async* { Stream<DataPacket> getMockDataStream() async* {
while(true) { while(true) {
yield new DataPacket.fromData(1597957282000, 5, 42, 420, 3.0, 32, 24, 10123, 32, null, 5, null, 9, ""); yield new DataPacket.fromData(1597957282000, 5, 42, 420, 3.0, 32, 24, 10123, 32, null, 5, null, 9, "");
......
...@@ -5,6 +5,7 @@ import 'package:sqflite/sqflite.dart'; ...@@ -5,6 +5,7 @@ import 'package:sqflite/sqflite.dart';
import 'package:tuple/tuple.dart'; import 'package:tuple/tuple.dart';
/// Handler that integrates a mysqli database into the application's workflow. /// Handler that integrates a mysqli database into the application's workflow.
// TODO: Table for data locations
class DatabaseHandler { class DatabaseHandler {
factory DatabaseHandler() => _singleton; factory DatabaseHandler() => _singleton;
...@@ -48,7 +49,7 @@ class DatabaseHandler { ...@@ -48,7 +49,7 @@ class DatabaseHandler {
return this._db; return this._db;
} }
/// Purges the [Database] of all internal. /// Purges the [Database] of all internal data.
Future<void> recreateDB() async { Future<void> recreateDB() async {
final Database database = await _database; final Database database = await _database;
......
...@@ -19,9 +19,11 @@ import 'package:tuple/tuple.dart'; ...@@ -19,9 +19,11 @@ import 'package:tuple/tuple.dart';
class NetworkHandler { class NetworkHandler {
factory NetworkHandler() => _singleton; factory NetworkHandler() => _singleton;
/// [NetworkHandler] initializer that sets up listeners on the [PreferencesHandler].
NetworkHandler._internal() { NetworkHandler._internal() {
this._pushFrequency.listen((value) { this._pushFrequency.listen((value) {
if (value != this._oldPushFrequency) { if (value != this._oldPushFrequency) {
// Resets the timer if the value has changed.
if (this._timer != null) { if (this._timer != null) {
this._timer.cancel(); this._timer.cancel();
} }
...@@ -32,10 +34,13 @@ class NetworkHandler { ...@@ -32,10 +34,13 @@ class NetworkHandler {
} }
}); });
/// Define the interval between attempts to send the data to the server. (default: 1 minute). /// Retrieve the interval between attempts to send the data to the server. (default: 1 minute).
PreferencesHandler().getPreferencesInt(PreferenceKeys.NET__MAX_ITEMS_PER_PUSH.key).then((value) => this._pushAmount.value = value); PreferencesHandler().getPreferencesInt(PreferenceKeys.NET__MAX_ITEMS_PER_PUSH.key).then((value) => this._pushAmount.value = value);
/// Retrieve the interval between attempts to send the data to the server. (default: 1 minute).
PreferencesHandler().getPreferencesInt(PreferenceKeys.NET__TIME_TO_PUSH.key).then((value) => this._pushFrequency.value = value); PreferencesHandler().getPreferencesInt(PreferenceKeys.NET__TIME_TO_PUSH.key).then((value) => this._pushFrequency.value = value);
/// Checks the [PreferencesHandler] every 20 seconds on Preference updates.
new Timer.periodic(Duration(seconds: 20), (Timer t) async { new Timer.periodic(Duration(seconds: 20), (Timer t) async {
this._pushAmount.value = await PreferencesHandler().getPreferencesInt(PreferenceKeys.NET__MAX_ITEMS_PER_PUSH.key); this._pushAmount.value = await PreferencesHandler().getPreferencesInt(PreferenceKeys.NET__MAX_ITEMS_PER_PUSH.key);
this._pushFrequency.value = await PreferencesHandler().getPreferencesInt(PreferenceKeys.NET__TIME_TO_PUSH.key); this._pushFrequency.value = await PreferencesHandler().getPreferencesInt(PreferenceKeys.NET__TIME_TO_PUSH.key);
...@@ -43,6 +48,7 @@ class NetworkHandler { ...@@ -43,6 +48,7 @@ class NetworkHandler {
} }
/// Kills the timer various timers and [BehaviorSubject]s.
@override @override
NetworkHandler.dispose() { NetworkHandler.dispose() {
if (this._timer != null) { if (this._timer != null) {
...@@ -55,16 +61,28 @@ class NetworkHandler { ...@@ -55,16 +61,28 @@ class NetworkHandler {
static final NetworkHandler _singleton = new NetworkHandler._internal(); static final NetworkHandler _singleton = new NetworkHandler._internal();
/// The reference [DateTime] of the last time data was sent to LogAir's servers.
DateTime _lastServerTransmission; DateTime _lastServerTransmission;
int a = 0; /// [BehaviorSubject] concerning the amount of data that should be pushed to the server per attempt.
BehaviorSubject<int> _pushAmount = BehaviorSubject<int>(); BehaviorSubject<int> _pushAmount = BehaviorSubject<int>();
/// [BehaviorSubject] concerning the frequency of attempts to push to the server.
BehaviorSubject<int> _pushFrequency = BehaviorSubject<int>(); BehaviorSubject<int> _pushFrequency = BehaviorSubject<int>();
/// A reference to the old frequency in order to limit updates.
int _oldPushFrequency = -1; int _oldPushFrequency = -1;
/// The frequency of the updates.
Duration _duration; Duration _duration;
Timer _timer;
/// The [Timer] that triggers the attempt to push to the server.
Timer _timer;
/// Proceeds to check whether an attempt to push to the server should be attempted.
///
/// If the user set [PreferenceKeys.NET__USE_MOBILE_NET] is set to true and 3G/4G/5G or Wi-Fi is available, then it will attempt to send data to the server.
/// Else it will only attempt when Wi-Fi is available.
Future<bool> checkNetworkAllowed() async { Future<bool> checkNetworkAllowed() async {
ConnectivityResult connectivity = await Connectivity().checkConnectivity(); ConnectivityResult connectivity = await Connectivity().checkConnectivity();
return !(connectivity == ConnectivityResult.none || return !(connectivity == ConnectivityResult.none ||
...@@ -82,21 +100,23 @@ class NetworkHandler { ...@@ -82,21 +100,23 @@ class NetworkHandler {
/// The default endpoint. /// The default endpoint.
String url = 'https://api.logair.unige.ch/v1/service'; String url = 'https://api.logair.unige.ch/v1/service';
// Send data in a serialized manner (FIFO)
if (await DatabaseHandler().getUnsentPacketsLength().first > 0) { if (await DatabaseHandler().getUnsentPacketsLength().first > 0) {
DataPacket source = (await DatabaseHandler().getUnsent(_pushAmount.value ?? PreferenceKeys.NET__MAX_ITEMS_PER_PUSH.defaultValue))[0].item2; DataPacket source = (await DatabaseHandler().getUnsent(_pushAmount.value ?? PreferenceKeys.NET__MAX_ITEMS_PER_PUSH.defaultValue))[0].item2;
// TODO set url / clean up // TODO set url / clean up
DataHeader().setHeaderFromExisting(deviceId: source.deviceId(), url: ''); DataHeader().setHeaderFromExisting(deviceId: source.deviceId, url: '');
} }
/// Break conditions ([DataHeader] unset or no [DataPacket] available). // Break conditions ([DataHeader] unset or no [DataPacket] available).
else if (!DataHeader().headerSet || DataHandler().getData().length == 0) else if (!DataHeader().headerSet || DataHandler().getData().length == 0)
return; return;
/// Get the map representation of a [DataHeader]. /// The map representation of a [DataHeader].
Map<String, dynamic> headerData = DataHeader().jsonify(); Map<String, dynamic> headerData = DataHeader().jsonify();
/// The indexed [DataPacket]s to be sent (user set or default value @see [PreferenceKeys.NET__MAX_ITEMS_PER_PUSH]).
List<Tuple2<int, DataPacket>> databaseData = await DatabaseHandler().getUnsent(_pushAmount.value ?? PreferenceKeys.NET__MAX_ITEMS_PER_PUSH.defaultValue); List<Tuple2<int, DataPacket>> databaseData = await DatabaseHandler().getUnsent(_pushAmount.value ?? PreferenceKeys.NET__MAX_ITEMS_PER_PUSH.defaultValue);
/// Get all the [DataPacket]s to be sent (maximum 100). /// The [DataPacket]s to be sent.
List<DataPacket> packets = databaseData.map((x) => x.item2).toList(); List<DataPacket> packets = databaseData.map((x) => x.item2).toList();
/// Convert the [DataPacket] list to a [Map] of their [List] representations. /// Convert the [DataPacket] list to a [Map] of their [List] representations.
...@@ -104,7 +124,7 @@ class NetworkHandler { ...@@ -104,7 +124,7 @@ class NetworkHandler {
'data' : LinkedHashSet<List<dynamic>>.from(packets.map((e) => e.jsonify()).toList()).toList() 'data' : LinkedHashSet<List<dynamic>>.from(packets.map((e) => e.jsonify()).toList()).toList()
}; };
/// Merge all of the [Map]s into 1. /// Merge all of the [Map]s.
Map<String, dynamic> postData = new Map<String, dynamic>(); Map<String, dynamic> postData = new Map<String, dynamic>();
postData.addAll(headerData); postData.addAll(headerData);
postData.addAll(packetList); postData.addAll(packetList);
...@@ -117,7 +137,7 @@ class NetworkHandler { ...@@ -117,7 +137,7 @@ class NetworkHandler {
headers: { "accept": "application/json", "content-type": "application/json" }, headers: { "accept": "application/json", "content-type": "application/json" },
body: json.encode(postData) body: json.encode(postData)
); );
/// On error, the error should be ignored and not break the thread. /// On error, the error should be ignored and not hang/break the thread.
} catch (e) { } catch (e) {
print("${e.toString()} COULDN'T CONNECT"); print("${e.toString()} COULDN'T CONNECT");
response = null; response = null;
...@@ -125,9 +145,10 @@ class NetworkHandler { ...@@ -125,9 +145,10 @@ class NetworkHandler {
/// If the response is defined as an instance of [http.Response], check it's status code and remove all of the packets from the log. /// If the response is defined as an instance of [http.Response], check it's status code and remove all of the packets from the log.
if (response != null && response.statusCode == 200) { if (response != null && response.statusCode == 200) {
for (int i = 0; i < packets.length; i++) { /// If the transfer was successful ()
DataHandler().pop(); for (int i = 0; i < packets.length; i++)
} DataHandler().pop(packets[i].timestamp);
await DatabaseHandler().setExported(databaseData.map((x) => x.item1).toList()); await DatabaseHandler().setExported(databaseData.map((x) => x.item1).toList());
print('RESPONSE ${response.statusCode}'); print('RESPONSE ${response.statusCode}');
this._lastServerTransmission = DateTime.now(); this._lastServerTransmission = DateTime.now();
......
import 'package:geolocator/geolocator.dart';
import 'package:logair_application/utils/enums/preference_keys.dart'; import 'package:logair_application/utils/enums/preference_keys.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
...@@ -104,13 +105,14 @@ class PreferencesHandler { ...@@ -104,13 +105,14 @@ class PreferencesHandler {
await setter(pref.key, pref.defaultValue); await setter(pref.key, pref.defaultValue);
} }
/// This is a generic function to reset all preferences to their default values. /// Resets all preferences to their default values.
Future<void> resetAllPreferences() async { Future<void> resetAllPreferences() async {
PreferenceKeys.list.where((PreferenceKeys k) => k != PreferenceKeys.GEN__SHARE).forEach( PreferenceKeys.list.where((PreferenceKeys k) => k != PreferenceKeys.GEN__SHARE).forEach(
(PreferenceKeys e) async => await resetPreference(e.key) (PreferenceKeys e) async => await resetPreference(e.key)
); );
} }
/// Retrieves the [LocationAccuracy] value from the [PreferencesHandler].
Stream<int> get currentDesiredGPSAccuracy async* { Stream<int> get currentDesiredGPSAccuracy async* {
while (true) { while (true) {
yield await getPreferencesInt(PreferenceKeys.GPS__ACCURACY.key); yield await getPreferencesInt(PreferenceKeys.GPS__ACCURACY.key);
......
...@@ -15,28 +15,7 @@ class DataWidget extends StatelessWidget { ...@@ -15,28 +15,7 @@ class DataWidget extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
Widget widget = Center( Widget widget = Center(
child: Column( child: Column(
children: [ children: [
/*Container(
height: 45,
decoration: BoxDecoration(
color: Colors.blue[300],
borderRadius: BorderRadius.all(Radius.circular(5)),
),
child: Row(
children: [
Expanded(
child: Text(
'Current',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 22
),
),
),
],
),
),*/
// Local data (Chart + Data points) // Local data (Chart + Data points)
Graph(), Graph(),
DataTile(stream: DataHandler().getDataStream(), isDistant: false), DataTile(stream: DataHandler().getDataStream(), isDistant: false),
...@@ -61,6 +40,7 @@ class DataWidget extends StatelessWidget { ...@@ -61,6 +40,7 @@ class DataWidget extends StatelessWidget {
), ),
), ),
IconButton( IconButton(
// Open other (Scaffold + Form) with nominatim etc + adds to DB.
onPressed: () => {}, onPressed: () => {},
icon: Icon(Icons.add), icon: Icon(Icons.add),
) )
......
...@@ -5,7 +5,7 @@ import 'package:logair_application/ui/components/body/data/graph/graph_colors.da ...@@ -5,7 +5,7 @@ import 'package:logair_application/ui/components/body/data/graph/graph_colors.da
import 'package:logair_application/ui/components/body/data/graph/graph_controller.dart'; import 'package:logair_application/ui/components/body/data/graph/graph_controller.dart';
import 'package:logair_application/ui/components/body/data/graph/indicator.dart'; import 'package:logair_application/ui/components/body/data/graph/indicator.dart';
/// This graph displays the average quality of the air in 5 second increments. /// This [Graph] displays the average quality of the air in 5 second increments.
class Graph extends StatefulWidget { class Graph extends StatefulWidget {
Graph({Key key}) : super(key: key); Graph({Key key}) : super(key: key);
...@@ -13,6 +13,7 @@ class Graph extends StatefulWidget { ...@@ -13,6 +13,7 @@ class Graph extends StatefulWidget {
State<Graph> createState() => _GraphState(); State<Graph> createState() => _GraphState();
} }
/// The [_GraphState] reacts to changes in time (additional data), and updates it's [List<FlSpot>] accordingly to draw the line chart.
class _GraphState extends State<Graph> { class _GraphState extends State<Graph> {
/// The first registered timestamp. /// The first registered timestamp.
double start; double start;
...@@ -23,9 +24,16 @@ class _GraphState extends State<Graph> { ...@@ -23,9 +24,16 @@ class _GraphState extends State<Graph> {
/// The maximum y-axis coordinate. /// The maximum y-axis coordinate.
double yMax = 0;