Commit 90c4dbfe authored by Nicolas Richard Walter Boeckh's avatar Nicolas Richard Walter Boeckh 💬

0.7.1 release

Added :
- Tristate toggle
- Entry dialog
- Various docs
- Entry pref

Modified :
- Bluetooth dialog
- DataHandler (only an in between now, fetch ops now on DB),
- Various docs
- decorations
- helpers

Removed :
- BT Unavailable (dialog based)
parent 2e89d17e
{"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-11 14:39:52.190164","version":"1.22.0-2.0.pre.18"}
\ No newline at end of file
{"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
......@@ -6,6 +6,9 @@
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. -->
<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
android:name="io.flutter.app.FlutterApplication"
android:label="logair.io"
......
......@@ -90,7 +90,7 @@ class 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() {
/// 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.
......@@ -103,8 +103,7 @@ class MapDisplayController {
return;
/// 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 (latest != null && latest.timestamp <= (DateTime.now().millisecondsSinceEpoch - 5000))
latest = null;
......@@ -162,7 +161,7 @@ class MapDisplayController {
new Timer.periodic(Duration(minutes: 1), (Timer t) {
if (this._controller != null && this._controller.bounds != null) {
//print('${this._controller.bounds.southWest}, ${this._controller.bounds.northEast}');
NetworkHandler().getProximityPoints(DataHeader().deviceID, this._controller.bounds);
NetworkHandler().getProximityPoints(DataHeader().deviceId, this._controller.bounds);
}
});
}
......
import 'package:collection/collection.dart';
import 'package:flutter/cupertino.dart';
/// @ToDeprecate Describes the contents of the data packets
/// @ReplaceBy Includes the device name and a config_file URL
......@@ -18,19 +19,28 @@ class DataHeader {
bool _headerSet;
String _deviceId;
String _url;
void setHeader(List<int> header) {
this._headerData = String.fromCharCodes(header.sublist(1, header.length - 1)).split(',');
this._deviceId = this._headerData[0];
this._url = this._headerData[1];
this._headerSet = true;
}
void setHeaderFromExisting({String deviceId = '', String url = ''}) {
this._headerData = [deviceID, url];
void setHeaderFromExisting({@required String deviceId, @required String url}) {
this._headerData = [deviceId, url];
this._deviceId = deviceId;
this._url = url;
this._headerSet = true;
}
/// Retrieve the deviceID from the header
String get deviceID => (this._headerData != null && this._headerData.length > 0) ? this._headerData[0] : '';
String get url => (this._headerData != null && this._headerData.length > 0) ? this._headerData[1] : '';
String get deviceId => (this._headerSet && this._deviceId != null) ? this._deviceId : '';
String get url => (this._headerSet && this._url != null) ? this._url : '';
/// @Getter for _headerSet;
bool get headerSet => this._headerSet;
......@@ -45,7 +55,7 @@ class DataHeader {
bool isEqual(List<int> that) => ListEquality().equals(_headerData, that);
// 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() {
this._headerSet = false;
......@@ -54,7 +64,7 @@ class DataHeader {
Stream<String> deviceIdStream() async* {
while(true) {
yield this.deviceID;
yield this._deviceId;
await Future.delayed(Duration(seconds: 1));
}
}
......
......@@ -11,6 +11,7 @@ class DataPacket {
List<int> _data;
int _timestamp;
String _deviceId;
String _url;
/* Location variables */
double _latitude;
......@@ -34,20 +35,24 @@ class DataPacket {
// ignore: unused_field
String _extraData;
int get timestamp => _timestamp;
String get deviceId => _deviceId ?? '';
double get latitude => _latitude;
double get longitude => _longitude;
int get altitude => _altitude;
int get heading => _heading;
double get speed => _speed;
double get temperature => _temperature;
double get pressure => _pressure;
double get relativeHumidity => _relativeHumidity;
double get pm1 => _pm1;
double get pm2_5 => _pm2_5;
double get pm4 => _pm4;
double get pm10 => _pm10;
int get timestamp => this._timestamp;
String get deviceId => this._deviceId ?? '';
String get url => this._url ?? '';
double get latitude => this._latitude;
double get longitude => this._longitude;
int get altitude => this._altitude;
int get heading => this._heading;
double get speed => this._speed;
double get temperature => this._temperature;
double get pressure => this._pressure;
double get relativeHumidity => this._relativeHumidity;
double get pm1 => this._pm1;
double get pm2_5 => this._pm2_5;
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) {
_timestamp = DateTime.now().millisecondsSinceEpoch;
......@@ -83,13 +88,14 @@ 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.fromMappedData(Map<String, dynamic> data) {
List<String> guardSet = ['device_id', 'timestamp_nix', 'latitude', 'longitude', 'altitude', 'speed', 'heading', 'temperature', 'pressure', 'relative_humidity', 'pm_1', 'pm_2_5', 'pm_4', 'pm_10', 'extra'];
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._url = data['url'];
this._timestamp = data['timestamp_nix'];
this._latitude = data['latitude'];
this._longitude = data['longitude'];
......@@ -124,6 +130,7 @@ class DataPacket {
this._pm10
];
/// Retrieves the DB insertable reference to this packet.
Map<String, dynamic> toMap() {
return {
'timestamp_nix': this._timestamp,
......@@ -139,7 +146,10 @@ class DataPacket {
'pm_2_5': this._pm2_5,
'pm_4': this._pm4,
'pm_10': this._pm10,
'extra': ''
'extra': '',
'device_id': this._deviceId,
'url': this._url,
};
}
......
import 'dart:async';
import 'package:logair_application/services/wake_service.dart';
/// Handler that wraps the [WakeService]
......
......@@ -57,40 +57,50 @@ class DataHandler {
bool wasSet = DataHeader().headerSet;
DataHeader().setHeader(packet);
/// Retroactively add all previous packets
if (!wasSet && DataHeader().headerSet)
_sortedData.forEach((packet) => MainDatabaseHandler().insertData(packet, DataHeader().deviceID, DataHeader().url));
if (!wasSet && DataHeader().headerSet) {
_sortedData.forEach((dataPacket) {
dataPacket.deviceId = DataHeader().deviceId;
dataPacket.url = DataHeader().url;
MainDatabaseHandler().insertData(dataPacket);
});
}
/// Or if it is a [DataPacket] instance.
} else if (packet[0] == 91) {
_sortedData.add(DataPacket(packet));
print('PACKET ${String.fromCharCodes(packet)}');
if (DataHeader().headerSet)
MainDatabaseHandler().insertData(_sortedData.last, DataHeader().deviceID, DataHeader().url);
DataPacket dataPacket = DataPacket(packet);
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.
@deprecated
List<DataPacket> getData() => _sortedData;
/// Remove the entirety of the acquired data.
@deprecated
void clearData() {
_sortedData.removeWhere((element) => true);
}
/// Remove the first element of the [DataPacket]s. Used for surgical removal.
@deprecated
void pop(int timestamp) {
if (_sortedData.isNotEmpty)
_sortedData.removeWhere((DataPacket d) => d.timestamp == timestamp);
}
/// Get the latest [DataPacket]
@deprecated
DataPacket getLatestData() => (_sortedData.length > 0) ? _sortedData.last : null;
/// Stream the latest confirmed [DataPacket] received by the device.
@deprecated
Stream<DataPacket> getDataStream() async* {
while(true) {
yield (_sortedData.length > 0) ? _sortedData.last : null;
......
......@@ -3,7 +3,7 @@ import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:logair_application/logic/data_packet.dart';
import 'package:logair_application/utils/location_of_interest.dart';
import 'package:logair_application/utils/helpers/location_of_interest.dart';
import 'package:path/path.dart';
import 'package:rxdart/rxdart.dart';
import 'package:sqflite/sqflite.dart';
......
......@@ -48,11 +48,9 @@ class MainDatabaseHandler {
}
/// Inserts data into the [Database].
Future<void> insertData(DataPacket packet, String deviceId, String url) async {
Future<void> insertData(DataPacket packet) async {
final Database database = await this._mainDatabase;
Map<String, dynamic> insert = packet.toMap();
insert['device_id'] = deviceId;
insert['url'] = url;
await database.insert(
'data',
insert,
......@@ -136,4 +134,20 @@ class MainDatabaseHandler {
return List.generate(data.length, (i) => DataPacket.fromMappedData(data[i]));
}
/// Retrieves the latest packet inserted into the [Database].
Stream<DataPacket> getLatestData() async* {
final Database database = await _mainDatabase;
while (true) {
final List<Map<String, dynamic>> data = await database.rawQuery('SELECT * FROM data ORDER BY timestamp_nix DESC LIMIT 1');
DataPacket packet = (data.length > 0) ? DataPacket.fromMappedData(data[0]) : null;
// Ignore packets older than 5 seconds.
if (packet != null && packet.timestamp + 5000 >= DateTime.now().millisecondsSinceEpoch) {
yield packet;
} else
yield null;
await Future.delayed(Duration(seconds: 1));
}
}
}
\ No newline at end of file
......@@ -13,7 +13,7 @@ import 'package:logair_application/logic/handlers/data_handler.dart';
import 'package:logair_application/logic/handlers/main_database_handler.dart';
import 'package:logair_application/logic/handlers/preference_handler.dart';
import 'package:logair_application/utils/enums/preference_keys.dart';
import 'package:logair_application/utils/location_of_interest.dart';
import 'package:logair_application/utils/helpers/location_of_interest.dart';
import 'package:logair_application/utils/utils.dart';
import 'package:rxdart/rxdart.dart';
import 'package:tuple/tuple.dart';
......@@ -106,12 +106,10 @@ class NetworkHandler {
// Send data in a serialized manner (FIFO)
if (await MainDatabaseHandler().getUnsentPacketsLength().first > 0) {
DataPacket source = (await MainDatabaseHandler().getUnsent(_pushAmount.value ?? PreferenceKeys.NET__MAX_ITEMS_PER_PUSH.defaultValue))[0].item2;
// TODO set url / clean up
DataHeader().setHeaderFromExisting(deviceId: source.deviceId, url: '');
}
// Break conditions ([DataHeader] unset or no [DataPacket] available).
else if (!DataHeader().headerSet || DataHandler().getData().length == 0)
DataHeader().setHeaderFromExisting(deviceId: source.deviceId, url: source.url);
} else {
return;
}
/// The map representation of a [DataHeader].
Map<String, dynamic> headerData = DataHeader().jsonify();
......@@ -149,8 +147,6 @@ 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 (response != null && response.statusCode == 200) {
/// If the transfer was successful ()
for (int i = 0; i < packets.length; i++)
DataHandler().pop(packets[i].timestamp);
await MainDatabaseHandler().setExported(databaseData.map((x) => x.item1).toList());
print('RESPONSE ${response.statusCode}');
......@@ -218,10 +214,9 @@ class NetworkHandler {
return response;
}
//TODO Generate a stream from a place for Place display
/// Retrieve the average [DataPacket] representation of data collected in a user-defined [LocationOfInterest].
Stream<DataPacket> generateLocationOfInterestStream({@required LocationOfInterest loi}) async* {
while (true) {
print('ping');
http.Response response;
try {
response = await _getLocationOfInterestData(latitude: loi.latitude, longitude: loi.longitude);
......@@ -249,7 +244,6 @@ class NetworkHandler {
// TODO: Preferences.
await Future.delayed(Duration(seconds: 60));
}
}
}
\ No newline at end of file
......@@ -6,12 +6,14 @@ import 'package:permission_handler/permission_handler.dart';
/// Handler enabling the frequent polling of the devices [Position]
class PositionHandler {
/// [Singleton]() instantiation factory.
/// [PositionHandler] instantiation factory.
factory PositionHandler() => _singleton;
PositionHandler._internal();
PositionHandler._internal() {
new Timer.periodic(Duration(seconds: 1), (timer) => this._timeSinceLastChange += 1);
}
/// Internal static [Singleton]() reference.
/// Internal static [PositionHandler] reference.
static final PositionHandler _singleton = new PositionHandler._internal();
/// The last known [Position] of the device.
......@@ -26,16 +28,19 @@ class PositionHandler {
/// The current [PermissionGroup] right's status.
GeolocationStatus _geolocationStatus;
/// The time since the [Position] was last updated.
int _timeSinceLastChange = 0;
// TODO: GPS.ACCURACY integrate
/// Default location tweaking options.
/// TODO GPS.ACCURACY integrate
LocationOptions locationOptions = LocationOptions(accuracy: LocationAccuracy.high, distanceFilter: 0, timeInterval: 1);
/// Get whether the user has granted the location permissions.
Stream<GeolocationStatus> getGeolocationStatus() async* {
while (true) {
yield _geolocationStatus;
yield this._geolocationStatus;
this._timeSinceLastChange = 0;
await Future.delayed(Duration(seconds: 1));
}
}
......@@ -84,4 +89,12 @@ class PositionHandler {
await Future.delayed(Duration(milliseconds: 1000));
}
}
/// Retrieves the time since the [Position] was last acquired, in seconds, once per second.
Stream<int> get timeSinceLastPositionAcquired async* {
while(true) {
yield this._timeSinceLastChange;
await Future.delayed(Duration(seconds: 1));
}
}
}
\ No newline at end of file
import 'package:flutter/cupertino.dart';
import 'package:flutter_blue/flutter_blue.dart';
import 'package:geolocator/geolocator.dart';
import 'package:logair_application/utils/enums/preference_keys.dart';
import 'package:shared_preferences/shared_preferences.dart';
......@@ -29,6 +31,7 @@ class PreferencesHandler {
this._sharedPreferencesInternal = await SharedPreferences.getInstance();
/// Initial Setup
print('Setting up preferences');
PreferenceKeys.list.forEach((PreferenceKeys prefs) {
Function setter;
switch (prefs.type) {
......@@ -107,7 +110,7 @@ class PreferencesHandler {
/// Resets all preferences to their default values.
Future<void> resetAllPreferences() async {
PreferenceKeys.list.where((PreferenceKeys k) => k != PreferenceKeys.GEN__SHARE).forEach(
PreferenceKeys.list.where((PreferenceKeys k) => k != PreferenceKeys.GEN__SHARE && k != PreferenceKeys.GEN__FIRST).forEach(
(PreferenceKeys e) async => await resetPreference(e.key)
);
}
......@@ -119,4 +122,11 @@ class PreferencesHandler {
await Future.delayed(Duration(milliseconds: 200));
}
}
void addToFrequentDevices({@required BluetoothDevice device}) async {
// TODO check if in fr devices,
// true => add to first place, shift others back.
// false => add to first, plonk last if len > 10.
}
}
\ No newline at end of file
import 'dart:async';
import 'dart:ui';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_blue/flutter_blue.dart';
import 'package:logair_application/localization/localization.dart';
import 'package:logair_application/logic/handlers/bluetooth_le_handler.dart';
import 'package:logair_application/ui/components/body/bluetooth/bluetooth_unusable_dialog.dart';
import 'package:logair_application/ui/components/body/bluetooth/bt_scan_tile.dart';
import 'package:logair_application/utils/helpers/device.dart';
import 'package:rxdart/rxdart.dart';
class BluetoothDialog extends StatefulWidget {
BluetoothDialog({Key key}) : super(key: key);
@override
_BluetoothDialogState createState() => _BluetoothDialogState(key: key);
}
// TODO Doc
class _BluetoothDialogState extends State<BluetoothDialog> {
_BluetoothDialogState({Key key});
BehaviorSubject<bool> _bluetoothUsable = BehaviorSubject<bool>();
bool _bluetoothAvailable = false;
bool _bluetoothAvailabilityChecked = false;
bool _showingDialog = false;
BluetoothState _state = BluetoothState.off;
List<Device> _frequentDevices;
GlobalKey<ScaffoldState> _key = GlobalKey();
@override
void initState() {
super.initState();
if (!this._bluetoothAvailabilityChecked) {
print('Checking BTAvail');
BTLEHandler().fblueInstance.isAvailable.then(
(bool value) => setState(() {
this._bluetoothAvailabilityChecked = true;
this._bluetoothAvailable = value;
this._bluetoothUsable.value = value && (_state != BluetoothState.off);
})
);
}
BTLEHandler().fblueInstance.state.first.then(
(newState) {
setState(() {
this._bluetoothUsable.value = this._bluetoothAvailable && (newState != BluetoothState.off);
_state = newState;
});
}
);
BTLEHandler().fblueInstance.state.listen((BluetoothState newState) {
if (mounted && _state != newState) {
this._bluetoothUsable.value = this._bluetoothAvailable && (newState != BluetoothState.off);
setState(() {
_state = newState;
});
}
});
}
@override
void dispose() {
_bluetoothUsable.close();
super.dispose();
}
Widget _buildSubZoneTitle({@required String text}) =>
Container(
width: double.maxFinite,
alignment: Alignment.center,
padding: EdgeInsets.symmetric(vertical: 8),
decoration: BoxDecoration(
color: Colors.blueAccent[400],
boxShadow: [
BoxShadow(
offset: Offset(2, -2),
color: Colors.grey[100]
)
],
borderRadius: BorderRadius.only(bottomLeft: Radius.circular(5), bottomRight: Radius.circular(5))
),
child: Text(
text,
style: TextStyle(
fontSize: 20,
color: Colors.white
),
),
);
@override
Widget build(BuildContext context) {
this._bluetoothUsable.listen((bool value) {
if (!value && !_showingDialog) {
_showingDialog = true;
showBluetoothUnusableDialog(context: context, btAvailable: this._bluetoothAvailable);
} else if (value && _showingDialog) {
_showingDialog = false;
Navigator.of(context).pop();
}
});
return SafeArea(
child: Scaffold(
key: _key,
appBar: AppBar(
title: Text(
AppLocalization.of(context).bluetoothScanMessage,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 22
)
),
actions: [
IconButton(
padding: EdgeInsets.all(10),
icon: Icon(Icons.refresh),
onPressed: () async {
if (this._bluetoothUsable.value) {
if (await BTLEHandler().fblueInstance.isScanning.first)
await BTLEHandler().fblueInstance.stopScan();
try {
await BTLEHandler().disconnect();
await BTLEHandler().fblueInstance.startScan(timeout: Duration(seconds: 10));
} catch (e) { }
}
}
)
],
),
body: RefreshIndicator(
onRefresh: () async {
if (this._bluetoothUsable.value) {
if (await BTLEHandler().fblueInstance.isScanning.first)
await BTLEHandler().fblueInstance.stopScan();
try {
await BTLEHandler().disconnect();