Skip to content

Commit

Permalink
started to use flutter_bloc
Browse files Browse the repository at this point in the history
  • Loading branch information
pseudoincorrect committed Apr 5, 2021
1 parent 924af9f commit e4d241a
Show file tree
Hide file tree
Showing 9 changed files with 529 additions and 9 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-04-05 11:21:13.384456","version":"2.0.4"}
{"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-04-05 14:30:33.034504","version":"2.0.4"}
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
import 'package:iirjdart/butterworth.dart';
import 'package:smart_mask/src/logic/database/models/sensor_model.dart';
import 'package:smart_mask/src/logic/repositories/sensor_data_repo.dart';

const MAX_TIME_TICKS = 1000;
const MAX_ZOOM = 10;

class AnalyticsLogic {
late AnalyticsLogicState _state;
late SensorDataRepository _sensorDataRepo;
late Sensor _selectedSensor;
late bool _transform;

AnalyticsLogic() {
_sensorDataRepo = SensorDataRepository();
_state = AnalyticsLogicState();
_state.lowPassFilter = 0.5;
_state.highPassFilter = 0.01;
_transform = false;
_selectedSensor = Sensor.sensor_1;
}

Future<List<SensorData>> getSensorData(TimeInterval interval) async {
final start = DateTime.fromMillisecondsSinceEpoch(interval.start);
final end = DateTime.fromMillisecondsSinceEpoch(interval.end);
List<SensorData> sensorData = await _sensorDataRepo.getSensorData(
_selectedSensor,
interval: [start, end],
);
return sensorData;
}

Future<TimeInterval> getAvailableInterval() async {
final start = await _sensorDataRepo.getOldestSensorData(_selectedSensor);
final end = await _sensorDataRepo.getNewestSensorData(_selectedSensor);
if (start == null || end == null) {
var now = DateTime.now().millisecondsSinceEpoch;
return TimeInterval(now, now);
}
return TimeInterval(start.timeStamp, end.timeStamp);
}

Future<void> getLatestSensorData() async {
final ti = await getAvailableInterval();
_state.dataRaw = await getSensorData(ti);
_state.workTimeInterval = ti;
_state.resetWorkInterval();
}

List<SensorData> refreshAnalytics() {
if (_transform) _calculateTransform();
calculateTimeWindow();
return _getDataWindow();
}

_calculateTransform() {
Butterworth butterworth = Butterworth();
int order = 2;
double sampleRate = 1 / (200 / 1000);
double leftFreq = _state.highPassFilter;
double rightFreq = _state.lowPassFilter;
double centerFreq = (rightFreq - leftFreq) / 2;
double widthFreq = rightFreq - leftFreq;

butterworth.bandPass(order, sampleRate, centerFreq, widthFreq);
double val;
SensorData sensorData;
_state.dataProcessed.clear();

for (var s in _state.dataRaw) {
val = butterworth.filter(s.value.toDouble());
sensorData = SensorData.fromSensorAndValue(
_selectedSensor, val.toInt(), s.timeStamp);
_state.dataProcessed.add(sensorData);
}
}

void calculateTimeWindow() {
final startMs = _state.workTimeInterval.start;
final endMs = _state.workTimeInterval.end;
final posInTicks = _state.timePosInTicks;

final centerMs =
startMs + (posInTicks * (endMs - startMs) ~/ MAX_TIME_TICKS);

final zoomDelta = (endMs - startMs) ~/ pow(2, _state.zoomLevel);
var windowLeftMs = centerMs - zoomDelta;
windowLeftMs = windowLeftMs > startMs ? windowLeftMs : startMs;
var windowRightMs = centerMs + zoomDelta;
windowRightMs = windowRightMs < endMs ? windowRightMs : endMs;

_state.timeWindow = TimeInterval(windowLeftMs, windowRightMs);
}

List<SensorData> _getDataWindow() {
final leftMs = _state._timeWindow.start;
final rightMs = _state._timeWindow.end;
List<SensorData> winList = [];
if (_transform) {
winList = _state.dataProcessed
.where((d) => d.timeStamp >= leftMs && d.timeStamp <= rightMs)
.toList();
} else {
winList = _state.dataRaw
.where((d) => d.timeStamp >= leftMs && d.timeStamp <= rightMs)
.toList();
}
return winList;
}

Future<void> _changeSensor() async {
final ti = await getAvailableInterval();
_state.dataRaw = await getSensorData(ti);
}

Future<void> setSelectedSensor(Sensor sensor) async {
_selectedSensor = sensor;
await _changeSensor();
}

// toggleTransform() {
// _transform = !_transform;
// }

setTransform(bool value) {
_transform = value;
}

// bool isTransformEnabled() {
// return _transform;
// }

// double get lowPassFilter => _state.lowPassFilter;

setLowPassFilter(double value) {
_state.lowPassFilter = value;
}

// double get highPassFilter => _state.highPassFilter;

setHighPassFilter(double value) {
_state.highPassFilter = value;
}

setTimefromInt(int value) {
_state.timePosInTicks = value;
}

increaseZoomLevel() async {
_state.zoomLevel += 1;
}

decreaseZoomLevel() {
_state.zoomLevel -= 1;
}
}

class TimeInterval {
late int start;
late int end;

TimeInterval(this.start, this.end);
}

class AnalyticsLogicState {
late List<SensorData> dataRaw;
late List<SensorData> dataProcessed;
late TimeInterval _workTimeInterval;
late TimeInterval _timeWindow;
late int _timePosInTicks;
late int _zoomLevel;
late double _lowPassFilter;
late double _highPassFilter;

AnalyticsLogicState() {
dataRaw = [];
dataProcessed = [];
_lowPassFilter = 100.0;
_highPassFilter = 0.2;
_workTimeInterval = TimeInterval(
DateTime.now().millisecondsSinceEpoch,
DateTime.now().millisecondsSinceEpoch,
);
resetWorkInterval();
}

double get lowPassFilter => _lowPassFilter;

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

double get highPassFilter => _highPassFilter;

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

int get zoomLevel => _zoomLevel;

set zoomLevel(int value) {
if (value > 0 && value < MAX_ZOOM) _zoomLevel = value;
}

int get timePosInTicks => _timePosInTicks;

set timePosInTicks(int value) {
if (value > 0 && value <= MAX_TIME_TICKS) _timePosInTicks = value;
}

TimeInterval get workTimeInterval => _workTimeInterval;

set workTimeInterval(TimeInterval ti) {
var start = ti.start;
var end = ti.end;
// start is max one hour before end

if (ti.start < (ti.end - Duration(hours: 1).inMilliseconds))
start = ti.end - Duration(hours: 1).inMilliseconds;

_workTimeInterval = TimeInterval(start, end);
}

TimeInterval get timeWindow => _timeWindow;

set timeWindow(TimeInterval interval) {
final startMs = interval.start;
final endMs = interval.end;
final wStartMs = _workTimeInterval.start;
final wEndMs = _workTimeInterval.end;

if (startMs >= wStartMs && endMs <= wEndMs) _timeWindow = interval;
}

resetWorkInterval() {
_timeWindow = _workTimeInterval;
_zoomLevel = 0;
_timePosInTicks = MAX_TIME_TICKS;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -203,13 +203,6 @@ class TimeInterval {
late int end;

TimeInterval(this.start, this.end);

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

class AnalyticsState {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import 'package:bloc/bloc.dart';
import 'package:meta/meta.dart';
import 'package:smart_mask/src/logic/blocs/analytics/Analytics_logic.dart';
import 'package:smart_mask/src/logic/blocs/bloc.dart';
import 'package:smart_mask/src/logic/database/models/sensor_model.dart';

class AnalyticsBloc extends Bloc<AnalyticsEvent, AnalyticsState> {
late AnalyticsLogic _logic;

AnalyticsBloc() : super(InitialAnalyticsState()) {
_logic = AnalyticsLogic();
}

@override
Stream<AnalyticsState> mapEventToState(AnalyticsEvent event) async* {
if (event is DataRefreshAnalyticsEvent) {
yield* _mapDataRefreshAnalyticsEvent();
} else if (event is ZoomIncAnalyticsEvent) {
yield* _mapZoomIncAnalyticsEvent();
} else if (event is ZoomDecAnalyticsEvent) {
yield* _mapZoomDecAnalyticsEvent();
} else if (event is TimeInTicksAnalyticsEvent) {
yield* _mapTimeInTicksAnalyticsEvent(event);
} else if (event is FilterEnabledAnalyticsEvent) {
yield* _mapFilterEnabledAnalyticsEvent(event);
} else if (event is LowPassAnalyticsEvent) {
yield* _mapLowPassAnalyticsEvent(event);
} else if (event is HighPassAnalyticsEvent) {
yield* _mapHighPassAnalyticsEvent(event);
} else if (event is SelectedSensorAnalyticsEvent) {
yield* _mapSelectedSensorAnalyticsEvent(event);
}
}

Stream<AnalyticsState> _mapDataRefreshAnalyticsEvent() async* {
await _logic.getLatestSensorData();
yield* _refreshData();
}

Stream<AnalyticsState> _mapZoomIncAnalyticsEvent() async* {
_logic.increaseZoomLevel();
yield* _refreshData();
}

Stream<AnalyticsState> _mapZoomDecAnalyticsEvent() async* {
_logic.decreaseZoomLevel();
yield* _refreshData();
}

Stream<AnalyticsState> _mapTimeInTicksAnalyticsEvent(
TimeInTicksAnalyticsEvent event) async* {
_logic.setTimefromInt(event.ticksIn1000);
yield* _refreshData();
yield TimeInTicksAnalyticsState(ticksIn1000: event.ticksIn1000)
}

Stream<AnalyticsState> _mapFilterEnabledAnalyticsEvent(
FilterEnabledAnalyticsEvent event) async* {
_logic.setTransform(event.filterEnabled);
yield* _refreshData();
yield FilterEnabledAnalyticsState(isEnable: event.filterEnabled);
}

Stream<AnalyticsState> _mapLowPassAnalyticsEvent(
LowPassAnalyticsEvent event) async* {
_logic.setLowPassFilter(event.lowPassValue);
yield* _refreshData();
yield LowPassAnalyticsState(lowPassValue: event.lowPassValue);
}

Stream<AnalyticsState> _mapHighPassAnalyticsEvent(
HighPassAnalyticsEvent event) async* {
_logic.setHighPassFilter(event.highPassValue);
yield* _refreshData();
yield HighPassAnalyticsState(highPassValue: event.highPassValue);
}

Stream<AnalyticsState> _mapSelectedSensorAnalyticsEvent(
SelectedSensorAnalyticsEvent event) async* {
await _logic.setSelectedSensor(event.selectedSensor);
yield* _refreshData();
}

///////////////////////////////////////////////////////
Stream<AnalyticsState> _refreshData() async* {
List<SensorData> sensorData = _logic.refreshAnalytics();
var state = SensorDataAnalyticsState(data: sensorData);
yield state;
}
}
Loading

0 comments on commit e4d241a

Please sign in to comment.