Commit 0411bb37 authored by Nicolas Richard Walter Boeckh's avatar Nicolas Richard Walter Boeckh 💬

Merge branch 'ui-final-layout' into 'master'

UI Advances

See merge request !3
parents f9f3f9f3 04f3929c
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"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":"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":"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":"shared_preferences_web","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\shared_preferences_web-0.1.2+5\\\\","dependencies":[]}]},"dependencyGraph":[{"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-05-15 10:37:30.582661","version":"1.19.0-2.0.pre.71"}
\ No newline at end of file
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"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":"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":"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":"shared_preferences_web","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\shared_preferences_web-0.1.2+5\\\\","dependencies":[]}]},"dependencyGraph":[{"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-07-13 03:41:01.914636","version":"1.19.0-2.0.pre.49"}
\ No newline at end of file
......@@ -46,6 +46,10 @@ Integrated Geolocation to the app and visualization on the app.
### [0.0.6] Added
- (UI) Map
- (UI) Settings
- ()
### [0.0.6] Changed
- `BTLEHandler`
......
......@@ -29,8 +29,20 @@ class DataHeader {
/// @Getter for _headerSet;
bool get headerSet => this._headerSet;
Stream<bool> getWhenHeaderSet() async* {
while (true) {
yield this._headerSet;
await Future.delayed(Duration(seconds: 1));
}
}
bool isEqual(List<int> that) => ListEquality().equals(_headerData, that);
// TODO
Map<String, dynamic> jsonify() => { 'device_id' : this._headerData[0], 'url': '000000000000' };
void dispose() {
this._headerSet = false;
this._headerData = [];
}
}
\ No newline at end of file
......@@ -6,6 +6,7 @@ import 'package:logair_application/utils/utils.dart';
/// and contains methods for:
/// quick lookup,
/// conversion to POST format,
// TODO Firmware@v2 : Extra data
class DataPacket {
List<int> _data;
int _timestamp;
......@@ -14,7 +15,7 @@ class DataPacket {
double _latitude;
double _longitude;
int _altitude;
double _heading;
int _heading;
double _speed;
/* Ambient metrics */
......@@ -28,11 +29,14 @@ class DataPacket {
double _pm4;
double _pm10;
// TODO Firmware v2
String _extraData;
int timestamp() => _timestamp;
double latitude() => _latitude;
double longitude() => _longitude;
int altitude() => _altitude;
double heading() => _heading;
int heading() => _heading;
double speed() => _speed;
double temperature() => _temperature;
double pressure() => _pressure;
......@@ -48,7 +52,7 @@ class DataPacket {
this._latitude = (acquiredData[0] != '') ? parseDoubleWrapper(acquiredData[0]) : null;
this._longitude = (acquiredData[1] != '') ? parseDoubleWrapper(acquiredData[1]) : null;
this._altitude = (acquiredData[2] != '') ? int.tryParse(acquiredData[2]) : null;
this._heading = (acquiredData[3] != '') ? parseDoubleWrapper(acquiredData[3]) : null;
this._heading = (acquiredData[3] != '') ? int.tryParse(acquiredData[3]) : null;
this._speed = (acquiredData[4] != '') ? parseDoubleWrapper(acquiredData[4]) : null;
this._temperature = (acquiredData[5] != '') ? parseDoubleWrapper(acquiredData[5]) : null;
......@@ -66,11 +70,30 @@ class DataPacket {
this._latitude = position.latitude;
this._longitude = position.longitude;
this._altitude = position.altitude.toInt();
this._heading = position.heading;
this._heading = position.heading.round() % 360;
this._speed = position.speed;
}
}
}
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) {
this._timestamp = data['timestamp_nix'];
this._latitude = data['latitude'];
this._longitude = data['longitude'];
this._altitude = data['altitude'];
this._speed = data['speed'];
this._heading = data['heading'];
this._temperature = data['temperature'];
this._relativeHumidity = data['relative_humidity'];
this._pressure = data['pressure'];
this._pm1 = data['pm_1'];
this._pm2_5 = data['pm_2_5'];
this._pm4 = data['pm_4'];
this._pm10 = data['pm_10'];
this._extraData = data['extra'];
}
String stringify() => '${this._latitude}, ${this._longitude}, ${this._temperature}, ${this._pressure}, ${this._relativeHumidity}, ${this._pm2_5}, ${this._pm10}';
......@@ -90,4 +113,28 @@ class DataPacket {
this._pm4,
this._pm10
];
Map<String, dynamic> toMap() {
return {
'timestamp_nix': this._timestamp,
'latitude': this._latitude,
'longitude': this._longitude,
'altitude': this._altitude,
'speed': this._speed,
'heading': this._heading,
'temperature': this._temperature,
'relative_humidity': this._temperature,
'pressure': this._pressure,
'pm_1': this._pm1,
'pm_2_5': this._pm2_5,
'pm_4': this._pm4,
'pm_10': this._pm10,
'extra': ''
};
}
@override
String toString() {
return 'DataPacket{time: $_timestamp, lat: $_latitude, long: $_longitude, pm1: $_pm1, pm2.5: $_pm2_5, pm4: $_pm4, pm10: $_pm10}';
}
}
\ No newline at end of file
......@@ -80,7 +80,7 @@ class BTLEHandler {
_characteristic = null;
_device = null;
_bluetoothConnectionStatus = BluetoothConnectionStatus.BTSTATUS_NOT_STREAMING;
DataHandler().dispose();
return it.disconnect();
});
......
import 'package:logair_application/logic/handlers/bluetooth_le_handler.dart';
import 'package:logair_application/logic/data_header.dart';
import 'package:logair_application/logic/data_packet.dart';
import 'package:logair_application/logic/handlers/database_handler.dart';
class DataHandler {
factory DataHandler() => _singleton;
......@@ -8,7 +9,7 @@ class DataHandler {
DataHandler._internal();
static const HEADER_SIZE = 11;
static final DataHandler _singleton = new DataHandler._internal();
static final DataHandler _singleton = new DataHandler._internal();
/// [List] containing all of the data received by this.
List<int> _data = [];
......@@ -49,11 +50,18 @@ class DataHandler {
/// If it's a [DataHeader] instance.
if (packet[0] == 123) {
print('HEADER ${String.fromCharCodes(packet)}');
bool wasSet = DataHeader().headerSet;
DataHeader().setHeader(packet);
/// Retroactively add all previous packets
if (!wasSet && DataHeader().headerSet)
_sortedData.forEach((packet) => DatabaseHandler().insertData(packet, DataHeader().deviceID));
/// Or if it is a [DataPacket] instance.
} else if (packet[0] == 91) {
_sortedData.add(DataPacket(packet));
print('PACKET ${String.fromCharCodes(packet)}');
if (DataHeader().headerSet)
DatabaseHandler().insertData(_sortedData.last, DataHeader().deviceID);
}
}
/// TODO Used for debugging, later
......@@ -89,11 +97,13 @@ class DataHandler {
}
}
@deprecated
/// Used to monitor the amount of unsent [DataPacket]s.
Stream<int> getUnsentPacketsLength() async* {
while (true) {
yield (_sortedData.length);
await Future.delayed(Duration(seconds: 1));
}
}
void dispose() {
DataHeader().dispose();
this._data.removeWhere((element) => true);
}
}
\ No newline at end of file
import 'package:logair_application/logic/data_header.dart';
import 'package:logair_application/logic/data_packet.dart';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
import 'package:tuple/tuple.dart';
class DatabaseHandler {
factory DatabaseHandler() => _singleton;
Future<Database> _db;
bool shouldCache;
Future<Database> get _database async {
if (_db == null)
this._db = openDatabase(
join((await getDatabasesPath()), 'logair_data.db'),
version: 1,
onCreate: (db, version) => db.execute('''CREATE TABLE data(
id INTEGER PRIMARY KEY AUTOINCREMENT,
device_id TEXT,
timestamp_nix INTEGER,
latitude REAL,
longitude REAL,
altitude INTEGER,
speed REAL,
heading INTEGER,
temperature FLOAT,
relative_humidity FLOAT,
pressure FLOAT,
pm_1 FLOAT,
pm_2_5 FLOAT,
pm_4 FLOAT,
pm_10 FLOAT,
extra TEXT,
exported TINYINT DEFAULT 0
)''')
);
return this._db;
}
// TODO REMOVE !
Future<void> recreateDB() async {
final Database database = await _database;
await database.rawQuery('DROP TABLE IF EXISTS data');
await database.rawQuery('''CREATE TABLE data(
id INTEGER PRIMARY KEY AUTOINCREMENT,
device_id TEXT,
timestamp_nix INTEGER,
latitude REAL,
longitude REAL,
altitude INTEGER,
speed REAL,
heading INTEGER,
temperature FLOAT,
relative_humidity FLOAT,
pressure FLOAT,
pm_1 FLOAT,
pm_2_5 FLOAT,
pm_4 FLOAT,
pm_10 FLOAT,
extra TEXT,
exported TINYINT DEFAULT 0
)''');
}
DatabaseHandler._internal();
static final DatabaseHandler _singleton = new DatabaseHandler._internal();
Future<void> insertData(DataPacket packet, String deviceId) async {
final Database database = await _database;
Map<String, dynamic> insert = packet.toMap();
insert['device_id'] = deviceId;
await database.insert(
'data',
insert,
conflictAlgorithm: ConflictAlgorithm.replace
);
}
Future<List<DataPacket>> get data async {
final Database database = await _database;
final List<Map<String, dynamic>> data = await database.query('data');
return List.generate(data.length, (i) => DataPacket.fromMappedData(data[i]));
}
Future<int> deleteAll() async => await (await this._database).delete('data');
Future<void> close() async => (await this._database).close();
Stream<int> getDBSize() async* {
final Database database = await _database;
while (true) {
final List<Map<String, dynamic>> data = await database.rawQuery('SELECT COUNT(*) AS count FROM data');
yield data[0]['count'] ?? 0;
await Future.delayed(Duration(seconds: 5));
}
}
Future<List<Tuple2<int, DataPacket>>> getUnsent(int limit) async {
final Database database = await _database;
final List<Map<String, dynamic>> data = await database.query('data',
where: 'exported = ?',
whereArgs: [0],
limit: limit,
orderBy: 'timestamp_nix ASC'
);
print(data);
return List.generate(data.length, (i) => Tuple2(data[i]['id'], DataPacket.fromMappedData(data[i])));
}
Future<void> setExported(List<int> ids) async {
final Database database = await _database;
print('UPDATE data SET exported = 1 WHERE id IN (${ids.join(', ')})');
int count = await database.rawUpdate('UPDATE data SET exported = 1 WHERE id IN (${ids.join(', ')})');
print('Exported $count');
}
/// Used to monitor the amount of unsent [DataPacket]s.
Stream<int> getUnsentPacketsLength() async* {
final Database database = await _database;
while (true) {
final List<Map<String, dynamic>> data = await database.rawQuery('SELECT COUNT(*) AS count FROM data WHERE exported = 0');
yield data[0]['count'] ?? 0;
await Future.delayed(Duration(seconds: 1));
}
}
Stream<Map<String, dynamic>> getLatest() async* {
final Database database = await _database;
while (true) {
final List<Map<String, dynamic>> data = await database.rawQuery('SELECT MIN(timestamp_nix) AS start, AVG(pm_1) AS pm_1, AVG(pm_2_5) AS pm_2_5, AVG(pm_4) AS pm_4, AVG(pm_10) AS pm_10 FROM (SELECT * FROM data ORDER BY id DESC LIMIT 5)');
yield data[0] ?? Map();
await Future.delayed(Duration(seconds: 5));
}
}
}
\ No newline at end of file
......@@ -3,13 +3,13 @@ import 'dart:convert';
import 'dart:collection';
import 'package:flutter_map/flutter_map.dart';
import 'package:geolocator/geolocator.dart';
import 'package:http/http.dart' as http;
import 'package:latlong/latlong.dart';
import 'package:logair_application/logic/data_header.dart';
import 'package:logair_application/logic/data_packet.dart';
import 'package:logair_application/logic/handlers/data_handler.dart';
import 'package:logair_application/logic/handlers/database_handler.dart';
import 'package:tuple/tuple.dart';
/// Singleton data structure that contains services enabling the application to send data to a webserver.
/// TODO Make URL user configurable.
......@@ -17,6 +17,7 @@ class NetworkHandler {
factory NetworkHandler() => _singleton;
NetworkHandler._internal() {
// TODO Preferences
/// Define the interval between attempts to send the data to the server. (default: 1 minute).
const duration = const Duration(minutes: 1);
new Timer.periodic(duration, (Timer t) => this._sendDataToServer());
......@@ -28,6 +29,7 @@ class NetworkHandler {
/// Method to send acquired data packets by using a POST requests.
void _sendDataToServer() async {
// TODO Preferences
/// The default endpoint.
String url = 'https://api.logair.unige.ch/v1/service';
......@@ -38,8 +40,10 @@ class NetworkHandler {
/// Get the map representation of a [DataHeader].
Map<String, dynamic> headerData = DataHeader().jsonify();
List<Tuple2<int, DataPacket>> databaseData = await DatabaseHandler().getUnsent(100);
/// Get all the [DataPacket]s to be sent (maximum 100).
List<DataPacket> packets = DataHandler().getDataRange(100);
List<DataPacket> packets = databaseData.map((x) => x.item2).toList();
/// Convert the [DataPacket] list to a [Map] of their [List] representations.
Map<String, List<List<dynamic>>> packetList = {
......@@ -64,7 +68,8 @@ class NetworkHandler {
if (response != null && response.statusCode == 200) {
for (int i = 0; i < packets.length; i++) {
DataHandler().pop();
}
}
await DatabaseHandler().setExported(databaseData.map((x) => x.item1).toList());
print('RESPONSE ${response.statusCode}');
this._lastServerTransmission = DateTime.now();
}
......
import 'package:shared_preferences/shared_preferences.dart';
import 'package:tuple/tuple.dart';
/// Handler enabling the storage and use of preferences.
class PreferencesHandler {
Map<String, Tuple2<dynamic, dynamic>> _defaultValues = {
'BT.USING_ADVANCED': Tuple2(bool, false),
'BT.FREQUENT': Tuple2(String, '[ ]'),
'BT.SERVICE_UUID': Tuple2(String, '0000ffe0-0000-1000-8000-00805f9b34fb'),
'BT.CHARACTERISTIC_UUID': Tuple2(String, '0000ffe1-0000-1000-8000-00805f9b34fb'),
'MAP.USING_ADVANCED': Tuple2(bool, false),
'MAP.PROX.MAX_PER_QUERY': Tuple2(int, 200),
'MAP.PROX.MAX_AGE_SECONDS': Tuple2(int, 200)
};
static final PreferencesHandler _singleton = new PreferencesHandler._internal();
SharedPreferences _sharedPreferences;
SharedPreferences _sharedPreferencesInternal;
PreferencesHandler._internal() {
SharedPreferences.getInstance().then((SharedPreferences prefs) {
this._sharedPreferences = prefs;
Future<SharedPreferences> get _sharedPreferences async {
if (_sharedPreferencesInternal == null) {
this._sharedPreferencesInternal = await SharedPreferences.getInstance();
/// Initial Setup
if (!prefs.containsKey('BT.USING_ADVANCED')) prefs.setBool('BT.USING_ADVANCED', false);
if (!prefs.containsKey('BT.USING_ADVANCED_DEFAULT')) prefs.setBool('BT.USING_ADVANCED_DEFAULT', false);
if (!prefs.containsKey('BT.FREQUENT')) prefs.setString('BT.FREQUENT', '[ ]');
if (!prefs.containsKey('BT.FREQUENT_DEFAULT')) prefs.setString('BT.FREQUENT_DEFAULT', '[ ]');
_defaultValues.forEach((key, value) {
Function setter;
switch (value.item1) {
case int:
setter = this._sharedPreferencesInternal.setInt;
break;
case bool:
setter = this._sharedPreferencesInternal.setBool;
break;
case String:
setter = this._sharedPreferencesInternal.setString;
break;
default:
throw ArgumentError('Unexpected property type');
}
if (!this._sharedPreferencesInternal.containsKey(key)) {
setter(key, value.item2);
setter(key + '_DEFAULT', value.item2);
}
});
print('Setup preferences \n ${List.generate(this._sharedPreferencesInternal.getKeys().length, (i) => this._sharedPreferencesInternal.getKeys().elementAt(i) + ' => ' + this._sharedPreferencesInternal.get(this._sharedPreferencesInternal.getKeys().elementAt(i)).toString()).join("\n")}');
}
if (!prefs.containsKey('BT.SERVICE_UUID')) prefs.setString('BT.SERVICE_UUID', '0000ffe0-0000-1000-8000-00805f9b34fb');
if (!prefs.containsKey('BT.SERVICE_UUID_DEFAULT')) prefs.setString('BT.SERVICE_UUID_DEFAULT', '0000ffe0-0000-1000-8000-00805f9b34fb');
return this._sharedPreferencesInternal;
}
if (!prefs.containsKey('BT.CHARACTERISTIC_UUID')) prefs.setString('BT.CHARACTERISTIC_UUID', '0000ffe1-0000-1000-8000-00805f9b34fb');
if (!prefs.containsKey('BT.CHARACTERISTIC_UUID_DEFAULT')) prefs.setString('BT.CHARACTERISTIC_UUID_DEFAULT', '0000ffe1-0000-1000-8000-00805f9b34fb');
PreferencesHandler._internal();
if (!prefs.containsKey('MAP.USING_ADVANCED')) prefs.setBool('MAP.USING_ADVANCED', false);
if (!prefs.containsKey('MAP.USING_ADVANCED_DEFAULT')) prefs.setBool('MAP.USING_ADVANCED_DEFAULT', false);
Future<int> getPreferencesInt(String key) async => (await this._sharedPreferences).getInt(key);
Future<String> getPreferencesString(String key) async => (await this._sharedPreferences).getString(key);
Future<bool> getPreferencesBool(String key) async => (await this._sharedPreferences).getBool(key);
if (!prefs.containsKey('MAP.PROX.MAX_PER_QUERY')) prefs.setInt('MAP.PROX.MAX_PER_QUERY', 200);
if (!prefs.containsKey('MAP.PROX.MAX_PER_QUERY_DEFAULT')) prefs.setInt('MAP.PROX.MAX_PER_QUERY_DEFAULT', 200);
Future<dynamic> getPreferences(String key) async => (await this._sharedPreferences).get(key);
if (!prefs.containsKey('MAP.PROX.MAX_AGE_SECONDS')) prefs.setInt('MAP.PROX.MAX_AGE_SECONDS', 200);
if (!prefs.containsKey('MAP.PROX.MAX_AGE_SECONDS_DEFAULT')) prefs.setInt('MAP.PROX.MAX_AGE_SECONDS_DEFAULT', 200);
Future<void> setPreferencesInt(String key, int value) async => (await this._sharedPreferences).setInt(key, value);
Future<void> setPreferencesString(String key, String value) async => (await this._sharedPreferences).setString(key, value);
Future<void> setPreferencesBool(String key, bool value) async => (await this._sharedPreferences).setBool(key, value);
Future<void> resetPreferences<T>(String key) async {
Function getter, setter;
switch (T) {
case int:
getter = getPreferencesInt;
setter = setPreferencesInt;
break;
case bool:
getter = getPreferencesBool;
setter = setPreferencesBool;
break;
case String:
getter = getPreferencesString;
setter = setPreferencesString;
}
print('Setup Prefs ${prefs.getKeys()}');
});
T value = await getter(key + '_DEFAULT');
await setter(key, value);
}
int getPreferencesInt(String key) => this._sharedPreferences.getInt(key);
String getPreferencesString(String key) => this._sharedPreferences.getString(key);
bool getPreferencesBool(String key) => this._sharedPreferences.getBool(key);
void setPreferencesInt(String key, int value) => this._sharedPreferences.setInt(key, value);
void setPreferencesString(String key, String value) => this._sharedPreferences.setString(key, value);
void setPreferencesBool(String key, bool value) => this._sharedPreferences.setBool(key, value);
void resetAllPreferences() async {
await (await this._sharedPreferences).setBool('BT.USING_ADVANCED', false);
await (await this._sharedPreferences).setString('BT.FREQUENT', '[ ]');
await (await this._sharedPreferences).setString('BT.SERVICE_UUID', '0000ffe0-0000-1000-8000-00805f9b34fb');
await (await this._sharedPreferences).setString('BT.CHARACTERISTIC_UUID', '0000ffe1-0000-1000-8000-00805f9b34fb');
await (await this._sharedPreferences).setBool('MAP.USING_ADVANCED', false);
await (await this._sharedPreferences).setInt('MAP.PROX.MAX_PER_QUERY', 200);
await (await this._sharedPreferences).setInt('MAP.PROX.MAX_AGE_SECONDS', 200);
}
factory PreferencesHandler() => _singleton;
}
\ No newline at end of file
import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:device_preview/device_preview.dart';
import 'package:flutter/services.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:logair_application/logic/controllers/home_controller.dart';
import 'package:logair_application/logic/controllers/map_display_controller.dart';
import 'package:logair_application/logic/handlers/data_handler.dart';
import 'package:logair_application/logic/handlers/network_handler.dart';
import 'package:logair_application/logic/handlers/position_handler.dart';
import 'package:logair_application/logic/handlers/preference_handler.dart';
import 'package:logair_application/logic/handlers/bluetooth_le_handler.dart';
import 'package:logair_application/ui/routes/home.dart';
import 'package:logair_application/localization/localization_delegate.dart';
......@@ -26,16 +17,6 @@ void main() {
runApp(displayMode ? DevicePreview(child: LogAirApplication()) : LogAirApplication());
}
Future<void> _startHandlers() async {
HomeController();
BTLEHandler();
NetworkHandler();
DataHandler();
PreferencesHandler();
PositionHandler();
MapDisplayController();
}
class LogAirApplication extends StatelessWidget {
static const String _title = 'LogAir Connector';
......
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:logair_application/services/battery_service.dart';
import 'package:logair_application/ui/base/custom_paint.dart';
import 'dart:math';
class BatteryVisualizerWidget extends StatelessWidget {
BatteryVisualizerWidget(this.isLeft, {Key key}) : super(key: key);
Stream<int> getBatteryLevel2() async* {
Random r = new Random();
while (true) {
yield 100; //r.nextInt(100);
await Future.delayed(Duration(seconds: 10));
}
}
final bool isLeft;
Color getColor(int value) {
if (value <= 10)
return Colors.red;
else if (10 < value && value <= 20)
return Colors.yellow;
else if (20 < value)
return Colors.green;
else
return Colors.grey[100];
}
@override
Widget build(BuildContext context) {
return StreamBuilder<int>(
stream: this.isLeft ? BatteryService().getBatteryLevel() : getBatteryLevel2(),
initialData: 0,
builder: (context, snapshot) {
int data = snapshot.data;
return Stack(
children: [
CustomPaint(
size: Size.infinite,
painter: CardPainter(isLeft: this.isLeft, battery: data, color: getColor(data))
),
Container(
alignment: Alignment.center,
child: Text("Battery $data"),
)
]
);
}
);
}
}
\ No newline at end of file