Skip to content

Commit

Permalink
setting up UI and analytics block
Browse files Browse the repository at this point in the history
  • Loading branch information
pseudoincorrect committed Mar 29, 2021
1 parent cc13e18 commit cdc679d
Show file tree
Hide file tree
Showing 15 changed files with 541 additions and 104 deletions.
2 changes: 1 addition & 1 deletion Mobile_app/smart_mask/.flutter-plugins-dependencies
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"flutter_blue","path":"C:\\\\Users\\\\maxim\\\\Programming\\\\SDKs\\\\Flutter\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\flutter_blue-0.7.2\\\\","dependencies":[]},{"name":"path_provider","path":"C:\\\\Users\\\\maxim\\\\Programming\\\\SDKs\\\\Flutter\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\path_provider-2.0.1\\\\","dependencies":[]},{"name":"sqflite","path":"C:\\\\Users\\\\maxim\\\\Programming\\\\SDKs\\\\Flutter\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\sqflite-2.0.0+3\\\\","dependencies":[]}],"android":[{"name":"flutter_blue","path":"C:\\\\Users\\\\maxim\\\\Programming\\\\SDKs\\\\Flutter\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\flutter_blue-0.7.2\\\\","dependencies":[]},{"name":"path_provider","path":"C:\\\\Users\\\\maxim\\\\Programming\\\\SDKs\\\\Flutter\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\path_provider-2.0.1\\\\","dependencies":[]},{"name":"sqflite","path":"C:\\\\Users\\\\maxim\\\\Programming\\\\SDKs\\\\Flutter\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\sqflite-2.0.0+3\\\\","dependencies":[]}],"macos":[{"name":"path_provider_macos","path":"C:\\\\Users\\\\maxim\\\\Programming\\\\SDKs\\\\Flutter\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\path_provider_macos-2.0.0\\\\","dependencies":[]},{"name":"sqflite","path":"C:\\\\Users\\\\maxim\\\\Programming\\\\SDKs\\\\Flutter\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\sqflite-2.0.0+3\\\\","dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"C:\\\\Users\\\\maxim\\\\Programming\\\\SDKs\\\\Flutter\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\path_provider_linux-2.0.0\\\\","dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"C:\\\\Users\\\\maxim\\\\Programming\\\\SDKs\\\\Flutter\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\path_provider_windows-2.0.0\\\\","dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"flutter_blue","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_macos","path_provider_linux","path_provider_windows"]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"sqflite","dependencies":[]}],"date_created":"2021-03-24 17:32:08.890493","version":"2.0.3"}
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"flutter_blue","path":"C:\\\\Users\\\\maxim\\\\Programming\\\\SDKs\\\\Flutter\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\flutter_blue-0.7.2\\\\","dependencies":[]},{"name":"path_provider","path":"C:\\\\Users\\\\maxim\\\\Programming\\\\SDKs\\\\Flutter\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\path_provider-2.0.1\\\\","dependencies":[]},{"name":"sqflite","path":"C:\\\\Users\\\\maxim\\\\Programming\\\\SDKs\\\\Flutter\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\sqflite-2.0.0+3\\\\","dependencies":[]}],"android":[{"name":"flutter_blue","path":"C:\\\\Users\\\\maxim\\\\Programming\\\\SDKs\\\\Flutter\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\flutter_blue-0.7.2\\\\","dependencies":[]},{"name":"path_provider","path":"C:\\\\Users\\\\maxim\\\\Programming\\\\SDKs\\\\Flutter\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\path_provider-2.0.1\\\\","dependencies":[]},{"name":"sqflite","path":"C:\\\\Users\\\\maxim\\\\Programming\\\\SDKs\\\\Flutter\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\sqflite-2.0.0+3\\\\","dependencies":[]}],"macos":[{"name":"path_provider_macos","path":"C:\\\\Users\\\\maxim\\\\Programming\\\\SDKs\\\\Flutter\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\path_provider_macos-2.0.0\\\\","dependencies":[]},{"name":"sqflite","path":"C:\\\\Users\\\\maxim\\\\Programming\\\\SDKs\\\\Flutter\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\sqflite-2.0.0+3\\\\","dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"C:\\\\Users\\\\maxim\\\\Programming\\\\SDKs\\\\Flutter\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\path_provider_linux-2.0.0\\\\","dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"C:\\\\Users\\\\maxim\\\\Programming\\\\SDKs\\\\Flutter\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\path_provider_windows-2.0.0\\\\","dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"flutter_blue","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_macos","path_provider_linux","path_provider_windows"]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"sqflite","dependencies":[]}],"date_created":"2021-03-29 17:49:15.960154","version":"2.0.3"}
54 changes: 21 additions & 33 deletions Mobile_app/smart_mask/lib/src/app.dart
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_blue/flutter_blue.dart';
import 'package:smart_mask/src/logic/blocs/analytics/analytics_bloc.dart';
import 'package:smart_mask/src/logic/blocs/analytics/analytics_provider.dart';
import 'package:smart_mask/src/logic/blocs/bluetooth/bluetooth_bloc.dart';
import 'package:smart_mask/src/logic/blocs/bluetooth/bluetooth_provider.dart';
import 'package:smart_mask/src/logic/blocs/sensor_data/sensor_data_bloc.dart';
import 'package:smart_mask/src/logic/blocs/sensor_data/sensor_data_provider.dart';
import 'package:smart_mask/src/ui/screens/bluetooth/ble_find_device_screen.dart';
import 'package:smart_mask/src/ui/screens/graphs_screen.dart';
import 'package:smart_mask/src/ui/screens/analytics_screen.dart';
import 'package:smart_mask/src/ui/screens/sensor_details_screen.dart';
import 'package:smart_mask/src/ui/screens/home_screen.dart';

Expand All @@ -22,15 +25,19 @@ class MyApp extends StatelessWidget {

final bluetoothBloc = BluetoothBloc();
final sensorDataBloc = SensorDataBloc();
final analyticsBloc = AnalyticsBloc();

return SensorDataProvider(
bloc: sensorDataBloc,
child: BluetoothProvider(
bloc: bluetoothBloc,
child: MaterialApp(
title: "Smart Mask",
theme: getTheme(),
home: HomeScreen(),
child: AnalyticsProvider(
bloc: analyticsBloc,
child: MaterialApp(
title: "Smart Mask",
theme: getTheme(),
home: SplashScreen(),
),
),
),
);
Expand All @@ -51,7 +58,7 @@ class MyApp extends StatelessWidget {
}
}

class HomeScreen extends StatelessWidget {
class SplashScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return TabControl();
Expand All @@ -72,7 +79,7 @@ class _TabControlState extends State<TabControl> {
bluetoothBloc = BluetoothProvider.of(context);
return DefaultTabController(
length: choices.length,
initialIndex: 1,
initialIndex: 3,
child: Scaffold(
appBar: AppBar(
title: Row(
Expand Down Expand Up @@ -144,40 +151,21 @@ List<Choice> choices = <Choice>[
Choice(
title: 'Home',
icon: Icons.home,
widget: (BuildContext context) => Home(),
widget: (BuildContext context) => HomeScreen(),
),
Choice(
title: 'Graphs',
icon: Icons.show_chart,
widget: (BuildContext context) => Graph(),
widget: (BuildContext context) => GraphsScreen(),
),
Choice(
title: 'Details',
icon: Icons.zoom_in,
widget: (BuildContext context) => GraphDetails(),
widget: (BuildContext context) => GraphDetailsScreen(),
),
Choice(
title: 'Analytics',
icon: Icons.analytics_outlined,
widget: (BuildContext context) => AnalyticsScreen(),
),
];

class ChoiceCard extends StatelessWidget {
const ChoiceCard({Key key, this.choice}) : super(key: key);

final Choice choice;

@override
Widget build(BuildContext context) {
final TextStyle textStyle = Theme.of(context).textTheme.bodyText2;
return Card(
color: Colors.white,
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Icon(choice.icon, size: 128.0, color: textStyle.color),
Text(choice.title, style: textStyle),
],
),
),
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
// Sensor Data Business Logic (BLoc) provider
//
// Description:
//

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:rxdart/rxdart.dart';
import 'package:smart_mask/src/logic/database/models/sensor_model.dart';
import 'package:smart_mask/src/logic/repositories/sensor_data_repo.dart';

class AnalyticsBloc {
final _sensorDataRepo = SensorDataRepository();
Sensor _selectedSensor = Sensor.sensor_1;
AnalyticsState _analyticsState = AnalyticsState();

BehaviorSubject<Sensor> _selectedSensorSubject;
BehaviorSubject<TimeInterval> _timeRangeSubject;
BehaviorSubject<List<SensorData>> _sensorDataProcessedSubject;
BehaviorSubject<bool> _analyticsRefresh;

AnalyticsBloc() {
_selectedSensorSubject = BehaviorSubject<Sensor>();
_timeRangeSubject = BehaviorSubject<TimeInterval>();
_sensorDataProcessedSubject = BehaviorSubject<List<SensorData>>();
_analyticsRefresh = BehaviorSubject<bool>();
_analyticsRefresh.stream.listen((event) => processAnalytics());
setSelectedSensor(_selectedSensor);
}

processAnalytics() {
print(_analyticsState.toString());
}

Future<TimeInterval> getAvailableInterval() async {
var start = await _sensorDataRepo.getEarliestSensorData(_selectedSensor);
var end = await _sensorDataRepo.getLatestSensorData(_selectedSensor);
var startDate = DateTime.fromMillisecondsSinceEpoch(start.timeStamp);
var endDate = DateTime.fromMillisecondsSinceEpoch(end.timeStamp);
return TimeInterval(startDate, endDate);
}

getSensorData(TimeInterval interval) async {
List<SensorData> sensorData = await _sensorDataRepo.getSensorData(
_selectedSensor,
interval: [interval.start, interval.end],
);
_sensorDataProcessedSubject.sink.add(sensorData);
}

Stream<List<SensorData>> getSensorDataStream() {
return _sensorDataProcessedSubject.stream;
}

Stream<TimeInterval> get timeRangeStream => _timeRangeSubject.stream;

set timeRange(TimeInterval interval) {
_timeRangeSubject.add(interval);
getSensorData(interval);
}

void setSelectedSensor(Sensor sensor) {
_selectedSensorSubject.add(sensor);
}

Stream<Sensor> getSelectedSensorStream() {
return _selectedSensorSubject.stream;
}

Stream<bool> getAnalyticsRefreshStream() {
return _analyticsRefresh.stream;
}

triggerAnalyticsRefresh() {
_analyticsRefresh.add(true);
}

setLowPassFilter(double value) {
_analyticsState.lowPassFilter = value;
triggerAnalyticsRefresh();
}

setHighPassFilter(double value) {
_analyticsState.highPassFilter = value;
triggerAnalyticsRefresh();
}

setTime(int value) {
_analyticsState.time = value;
triggerAnalyticsRefresh();
}

increaseZoomLevel() {
_analyticsState.zoomLevel += 1;
triggerAnalyticsRefresh();
}

decreaseZoomLevel() {
_analyticsState.zoomLevel -= 1;
triggerAnalyticsRefresh();
}

dispose() {
_sensorDataProcessedSubject.close();
_selectedSensorSubject.close();
_timeRangeSubject.close();
}
}

class TimeInterval {
DateTime start;
DateTime end;

TimeInterval(this.start, this.end);

factory TimeInterval.fromMsSinceEpoch(RangeValues range) {
DateTime dateStart =
DateTime.fromMicrosecondsSinceEpoch(range.start.toInt());
DateTime dateEnd = DateTime.fromMicrosecondsSinceEpoch(range.end.toInt());
return TimeInterval(dateStart, dateEnd);
}
}

class AnalyticsState {
int _time;
int _zoomLevel;
double _lowPassFilter;
double _highPassFilter;

AnalyticsState() {
_time = DateTime.now().millisecondsSinceEpoch;
_zoomLevel = 0;
_lowPassFilter = 100.0;
_highPassFilter = 0.2;
}

double get lowPassFilter => _lowPassFilter;

set lowPassFilter(double value) {
if (value < 0 || value <= _highPassFilter || value > 10000) return;
_lowPassFilter = value;
}

double get highPassFilter => _highPassFilter;

set highPassFilter(double value) {
if (value < 0 || value >= _lowPassFilter || value > 10000) return;
_highPassFilter = value;
}

int get time => _time;

set time(int value) {
int nowMs = DateTime.now().millisecondsSinceEpoch;
int nowMinus1monthMs =
DateTime.now().subtract(Duration(days: 30)).millisecondsSinceEpoch;
if (value > nowMs || value < nowMinus1monthMs) return;
_time = value;
}

int get zoomLevel => _zoomLevel;

set zoomLevel(int value) {
if (value < 0 || value > 15) return;
_zoomLevel = value;
}

@override
String toString() {
return "Analytics State ${DateTime.fromMillisecondsSinceEpoch(_time)}, "
"Zoom level : $_zoomLevel, Low pass $_lowPassFilter, High pass $_highPassFilter";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Sensor Data Business Logic (BLoc) provider
//
// Description:
// Enable the Sensor Data bloc to be accessible (provided)
// throughout the app with contex.inherit..

import 'package:flutter/material.dart';
import 'package:smart_mask/src/logic/blocs/analytics/analytics_bloc.dart';

class AnalyticsProvider extends InheritedWidget {
final AnalyticsBloc bloc;

AnalyticsProvider({Key key, Widget child, this.bloc})
: super(key: key, child: child);

bool updateShouldNotify(_) => true;

static AnalyticsBloc of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<AnalyticsProvider>().bloc;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,16 @@

import 'dart:async';
import 'package:rxdart/rxdart.dart';
import 'package:smart_mask/src/logic/blocs/sensor_data/sensor_mock.dart';
import 'package:smart_mask/src/logic/database/models/sensor_model.dart';
import 'package:smart_mask/src/logic/repositories/sensor_data_repo.dart';

class SensorDataBloc {
final _sensorDataRepo = SensorDataRepository();
Sensor _selectedSensor = Sensor.sensor_1;
Duration windowInterval = Duration(seconds: 30);
Duration windowInterval = Duration(seconds: 10);
Duration refreshInterval = Duration(seconds: 1);
SensorsMock sensorsMock;

BehaviorSubject<Sensor> _selectedSensorSubject;
Map<Sensor, BehaviorSubject<List<SensorData>>> _sensorDataSubjects = Map();
Expand All @@ -34,6 +36,8 @@ class SensorDataBloc {
setSelectedSensor(_selectedSensor);

setupTimers(refreshInterval);

// sensorsMock = SensorsMock();
}

getSensorData(Sensor sensor, {List<DateTime> interval}) async {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import 'dart:async';

import 'package:smart_mask/src/logic/database/models/sensor_model.dart';
import 'dart:math';

import 'package:smart_mask/src/logic/repositories/sensor_data_repo.dart';

class SensorsMock {
final _sensorDataRepo = SensorDataRepository();
Map<Sensor, int> sensorMockData = Map();
Random rng;

Duration addInterval = Duration(milliseconds: 200);
Timer mockTimer;

SensorsMock() {
rng = Random();
for (var s in Sensor.values) {
sensorMockData[s] = 0;
}
mockTimer = Timer.periodic(addInterval, (Timer t) => addMockData());
}

addMockData() {
for (var s in Sensor.values) {
var rand = rng.nextInt(10);

if (rng.nextBool())
sensorMockData[s] += rand;
else
sensorMockData[s] -= rand;

if (sensorMockData[s] < -3000) sensorMockData[s] = -3000;
if (sensorMockData[s] > 3000) sensorMockData[s] = 3000;

var sensorData = SensorData.fromSensorAndValue(
s, sensorMockData[s], DateTime.now().millisecondsSinceEpoch);

_sensorDataRepo.insertSensorData(sensorData);
}
}

dispose() {
mockTimer.cancel();
}
}
Loading

0 comments on commit cdc679d

Please sign in to comment.