Add All the files from the touchpad_demonstrator Flutter App which can be build for Android and iOS

This commit is contained in:
Richard Stern
2019-06-04 16:51:24 +02:00
parent 26fcc2491c
commit a951e9518d
1340 changed files with 12844936 additions and 0 deletions
+14
View File
@@ -0,0 +1,14 @@
import 'package:flutter/material.dart';
import 'package:touch_demonstrator/src/blocs/appBloc.dart';
class BlocProvider extends InheritedWidget {
final AppBloc bloc;
BlocProvider({Key key, this.bloc, child}) : super(key: key, child: child);
@override
bool updateShouldNotify(InheritedWidget oldWidget) => true;
static AppBloc of(BuildContext context) =>
(context.inheritFromWidgetOfExactType(BlocProvider) as BlocProvider).bloc;
}
+28
View File
@@ -0,0 +1,28 @@
import 'package:touch_demonstrator/src/blocs/bluetoothBloc.dart';
import 'package:touch_demonstrator/src/blocs/debugCounterBloc.dart';
//import 'package:touch_demonstrator/src/blocs/touchDataBloc.dart';
class AppBloc {
DebugBloc _debugBloc;
// EvenCounterBloc _evenCounter;
BluetoothBloc _bluetoothBloc;
// TouchDataBloc _touchDataInputBloc;
AppBloc()
: _debugBloc = DebugBloc(),
_bluetoothBloc = BluetoothBloc();
// _touchDataInputBloc = TouchDataBloc();
DebugBloc get debugBlocGetter => _debugBloc;
// EvenCounterBloc get evenCounterBloc => _evenCounter;
BluetoothBloc get bluetoothBlocGetter => _bluetoothBloc;
// TouchDataBloc get touchInBlocGetter => _touchDataInputBloc;
}
+505
View File
@@ -0,0 +1,505 @@
import 'dart:async';
import 'dart:convert';
import 'package:rxdart/rxdart.dart';
import 'package:rxdart/subjects.dart';
import 'package:flutter_blue/flutter_blue.dart';
import 'package:touch_demonstrator/model/touchData.dart';
import 'package:touch_demonstrator/model/buttonData.dart';
import 'package:flutter_test/flutter_test.dart';
class BluetoothBloc {
FlutterBlue _flutterBlue = FlutterBlue.instance;
/// Scanning
StreamSubscription _scanSubscription;
Map<DeviceIdentifier, ScanResult> scanResults = Map();
/// State
StreamSubscription _stateSubscription;
final _state$ = BehaviorSubject<BluetoothState>();
final _isScanning$ = PublishSubject<bool>();
final _isConnected$ = BehaviorSubject<bool>();
final _deviceFound$ = PublishSubject<Map<DeviceIdentifier, ScanResult>>();
// final _touchMessage$ = BehaviorSubject<String>(seedValue: 'init');
final _singleTouchMessage$ = BehaviorSubject<TouchData>();
final _touchDataHistory$ = BehaviorSubject<List<TouchData>>();
final _touchVisualise$ = BehaviorSubject<List<TouchData>>();
final _buttonEnabledStatus$ = BehaviorSubject<List<bool>>();
final _batteryValue$ = BehaviorSubject<int>();
final _buttonVibration$ = PublishSubject<buttonsState>();
final _slider$ = PublishSubject<int>();
String touchMessage = "";
/// Device
BluetoothDevice device;
/// Device specifications
StreamSubscription deviceConnection;
StreamSubscription deviceStateSubscription;
Map<Guid, StreamSubscription> valueChangedSubscriptions = {};
BluetoothDeviceState deviceState = BluetoothDeviceState.disconnected;
// Stream Controllers
final _scanController = StreamController<void>();
final _stopController = StreamController<void>();
final _connectController = StreamController<ScanResult>();
final _disconnectController = StreamController<void>();
//SINKS (into bloc)
Sink<void> get scan => _scanController.sink;
Sink<void> get stop => _stopController.sink;
Sink<ScanResult> get connect => _connectController.sink;
Sink<void> get disconnect => _disconnectController.sink;
//STREAMS (output bloc)
Stream<BluetoothState> get bluetoothState$ => _state$.stream;
Stream<int> get batteryValue$ => _batteryValue$.stream;
Stream<TouchData> get singleTouchMessage => _singleTouchMessage$.stream;
Stream<List<TouchData>> get getTouchesToVisualise$ =>
_touchVisualise$.stream; //->
Stream<List<bool>> get buttonsState$ => _buttonEnabledStatus$.stream;
Stream<buttonsState> get vibrationButton$ => _buttonVibration$.stream;
Stream<int> get slider$ => _slider$.stream;
Stream<List<TouchData>> get getHistory$ =>
_touchDataHistory$.stream.debounce(Duration(milliseconds: 600)); //->
Stream<bool> get isScanning$ => _isScanning$.stream;
Stream<bool> get isConnected$ => _isConnected$.stream;
Stream<Map<DeviceIdentifier, ScanResult>> get devicesFound$ =>
_deviceFound$.stream.throttle(Duration(seconds: 2));
static const xMax = 1200;
String inputString = "";
final history = List<TouchData>();
static List<TouchData> _fingerTouches =
List.generate(5, (index) => TouchData(5, index, 1200, 1200));
static List<buttonsState> _buttonPressed = [
buttonsState.released,
buttonsState.released,
buttonsState.released
];
static List<bool> _buttonsState = [false, false, false];
// Listen to
BluetoothBloc() {
print('init: Bluetooth BLOC');
_flutterBlue.setLogLevel(LogLevel.warning);
// Listen to BLoC inputs
_flutterBlue.state.then((s) {
_state$.add(s);
});
_stateSubscription = _flutterBlue.onStateChanged().listen((s) {
_state$.add(s);
if (s == BluetoothState.off) {
_resetSensor();
}
});
_scanController.stream.listen((void _) {
_startScan();
});
_stopController.stream.listen((void _) => _stopScan);
_connectController.stream
.listen((ScanResult result) => _connect(result.device));
_disconnectController.stream.listen((void _) {
_disconnect();
});
_isConnected$.add(false);
}
void _startScan() {
print('Bluetooth Bloc: start Bluetooth Scan');
scanResults.clear();
_isScanning$.add(true);
_scanSubscription = _flutterBlue
.scan(
timeout: const Duration(seconds: 1),
)
.listen((scanResult) {
// print('Local Name: ${scanResult.advertisementData.localName}');
scanResults[scanResult.device.id] = scanResult;
// print(scanResult.device.id);
}, onDone: _stopScan);
}
void _stopScan() {
/// Stops any ongoing Bluetooth Search
print('BLOC: _stopScan()');
_scanSubscription?.cancel();
_scanSubscription = null;
_findDevice("Touchpad Demonstrator");
}
void _disconnect() {
/// Disconnects all Bluetooth connections
// Remove all value changed listeners
print('Bluetooth Bloc: disconnect');
valueChangedSubscriptions.forEach((uuid, sub) => sub.cancel());
valueChangedSubscriptions.clear();
deviceStateSubscription?.cancel();
deviceStateSubscription = null;
deviceConnection?.cancel();
deviceConnection = null;
device = null;
_resetSensor();
}
void _resetSensor() {
/// Resets all visual components of the app to initial state
_buttonsState = [false, false, false];
_slider$.add(101);
_buttonEnabledStatus$.add(_buttonsState);
_isConnected$.add(false);
_fingerTouches = [
TouchData(5, 0, 1200, 1200),
TouchData(5, 1, 1200, 1200),
TouchData(5, 2, 1200, 1200),
TouchData(5, 3, 1200, 1200),
TouchData(5, 4, 1200, 1200),
];
_touchVisualise$.add(_fingerTouches);
history.clear();
_touchDataHistory$.add(history);
_batteryValue$.add(null);
}
_findDevice(String deviceNameSearched) {
/// If one device found -> connect to it. If more are found -> Stream the results
var devicesFound = 0;
BluetoothDevice deviceFound;
// const String touchDemonstratorName = "Touchpad Demonstrator";
print("_findDevices()");
scanResults.forEach((k, v) {
if (v.advertisementData.localName.contains(deviceNameSearched)) {
devicesFound++;
deviceFound = v.device;
}
});
print('$devicesFound devices Found');
if (devicesFound == 1) {
// Only one device found -> connect directly.
_connect(deviceFound);
// _deviceFound$.add(scanResults);
} else if (devicesFound > 1) {
// More than one device found.
_deviceFound$.add(scanResults);
} else if (devicesFound == 0) {
// No device found.
scanResults.clear();
_deviceFound$.add(scanResults);
}
Future.delayed(const Duration(milliseconds: 700), () {
_isScanning$.add(false);
});
}
void _connect(BluetoothDevice d) async {
/// Connects device to BluetoothDevice D and subscribes to it.
print('_connect');
device = d;
deviceConnection = _flutterBlue
.connect(device, timeout: const Duration(seconds: 2))
.listen(null, onDone: _disconnect);
device.state.then((s) {
deviceState = s;
print('device state: $deviceState'); //change it immediately
});
// Subscribe to connection changes
deviceStateSubscription = device.onStateChanged().listen((s) {
print('statesubscription change: $s');
deviceState = s;
if (s == BluetoothDeviceState.connected) {
///discover services
device.discoverServices().then((services) {
// services = s;
_checkServiceAndCharacteristic(services);
});
} else if (s == BluetoothDeviceState.disconnected) {
_disconnect();
}
if (device != null) {
_isConnected$.add(true);
}
});
}
_checkServiceAndCharacteristic(List<BluetoothService> services) {
print("_lookForService()");
services.forEach((s) {
print(s.uuid.toString());
if (s.uuid.toString().toUpperCase().substring(4, 8) == "0001") {
// Bluetooth UART characteristic found!
print(
"Service found: ${s.uuid.toString().toUpperCase().substring(4, 8)} -> check Characteristic");
s.characteristics.forEach((c) {
if (c.uuid.toString().toUpperCase().substring(4, 8) == "0003") {
/* print(
"Characteristic found: ${f.uuid.toString().toUpperCase().substring(4, 8)}");*/
_subscribeTouchDataNotification(c);
}
});
}
else if(s.uuid.toString().toUpperCase().substring(4,8) == "180F"){
print('battery service found');
s.characteristics.forEach((c){
if(c.uuid.toString().toUpperCase().substring(4,8) == "2A19"){
_subscribeBatteryNotfications(c);
}
});
}
});
}
_subscribeBatteryNotfications(BluetoothCharacteristic c) async {
print('_subscribe battery: ${c.isNotifying}');
if (c.isNotifying) {
// Unsubscribe from subscription
await device.setNotifyValue(c, false);
valueChangedSubscriptions[c.uuid]?.cancel();
valueChangedSubscriptions.remove(c.uuid);
} else {
print('subscribe battery');
var _batteryValue = await device.readCharacteristic(c);
assert(_batteryValue[0] >= 0 && _batteryValue[0] <= 100);
print('battery right now: ${_batteryValue[0]} %');
_batteryValue$.add(_batteryValue[0]);
// ignore: cancel_subscriptions
final subBattery = device.onValueChanged(c).listen((d) {
print("battery: $d");
});
valueChangedSubscriptions[c.uuid] = subBattery;
}
}
_subscribeTouchDataNotification(BluetoothCharacteristic c) async {
if (c.isNotifying) {
// Unsubscribe from subscription
await device.setNotifyValue(c, false);
valueChangedSubscriptions[c.uuid]?.cancel();
valueChangedSubscriptions.remove(c.uuid);
} else {
// ignore: cancel_subscriptions
final sub = device.onValueChanged(c).listen((d) {
List<int> dFiltered = new List.from(d); // Copy List
dFiltered.removeWhere((item) =>
item < 48 && item != 40 && item != 41 && item != 24 ||
item > 57 && item != 124);
var dDecoded = utf8.decode(dFiltered);
_combineStringToMeasurement(dDecoded);
});
valueChangedSubscriptions[c.uuid] = sub;
}
}
void _combineStringToMeasurement(String dDecoded) {
// Combines one data set.
for (var x = 0; x < dDecoded.length; x++) {
if (touchMessage.length < 15) {
if (touchMessage.length == 0) {
if (dDecoded[x] == '(') {
touchMessage += dDecoded[x];
}
} else {
touchMessage += dDecoded[x];
}
}
if (touchMessage.length == 15) {
_extractTouchpointsFromString(touchMessage);
touchMessage = "";
} else if (touchMessage.length > 15) {
touchMessage = ""; // clear string
}
}
}
void _extractTouchpointsFromString(String inputString) {
// Gets data from data string and saves it
TouchData t = TouchData(0, 0, 0, 0);
final RegExp regExp = new RegExp(
r"\(\d\|\d\|\d{4}\|\d{4}\)",
caseSensitive: false,
multiLine: false,
);
var matches = regExp.allMatches(inputString);
for (var m in matches) {
t.event = int.tryParse(m.group(0)[1]);
t.fingerNumber = int.tryParse(m.group(0)[3]);
t.x = int.tryParse(m.group(0).substring(5, 9));
t.y = int.tryParse(m.group(0).substring(10, 14));
if (t.x < 1100 &&
t.y < 1100 &&
(t.fingerNumber <= 4) &&
(t.event == 1 || t.event == 4 || t.event == 5)) {
_checkButtons(t);
if (t.x >= 950) {
_checkSlider(t);
}
_fillSensorVisualisationStreams(t);
} else {
// print("Touch not Added!!!!!!!!!!!! $i ${t.e} ${t.f} ${t.x} ${t.y}");
}
}
}
void _fillSensorVisualisationStreams(TouchData t) {
_singleTouchMessage$.add(t);
_fingerTouches[t.fingerNumber].touchEvent(t.event, t.x, t.y);
_touchVisualise$.add(_fingerTouches);
//History:
history.add(t);
_touchDataHistory$.add(history);
}
static bool enableButtons = true;
Future _checkButtons(TouchData t) async {
// 4 == press down; 1 == move; 5 == up
final int button0Upper = 130, button0Lower = 320;
final int button1Upper = 320, button1Lower = 510;
final int button2Upper = 510, button2Lower = 730;
const Duration durationButtonDebounce = Duration(milliseconds: 50);
const Duration durationButtonPressMinimum = Duration(milliseconds: 100);
if (t.x < 100 &&
t.y >= button0Upper &&
t.y <= button2Lower &&
enableButtons) {
if (t.event == 5) {
// a button is released!
if (t.y >= button0Upper &&
t.y <= button0Lower &&
_buttonPressed[0] == buttonsState.pressed) {
_buttonsState[0] = !_buttonsState[0];
_buttonsState[1] = _buttonsState[2] = false;
_buttonPressed[0] =
buttonsState.released; // wait for a new button press now
print('bBloc: button released -> ButtonStatus: $_buttonsState');
} else if (t.y >= button1Upper &&
t.y <= button1Lower &&
_buttonPressed[1] == buttonsState.pressed) {
_buttonsState[1] = !_buttonsState[1];
_buttonsState[0] = _buttonsState[2] = false;
_buttonPressed[1] =
buttonsState.released; // wait for a new button press now
print('bBloc: button released -> ButtonStatus: $_buttonsState');
} else if (t.y >= button2Upper &&
t.y <= button2Lower &&
_buttonPressed[2] == buttonsState.pressed) {
_buttonsState[2] = !_buttonsState[2];
_buttonsState[0] = _buttonsState[1] = false;
_buttonPressed[2] =
buttonsState.released; // wait for a new button press now
print('bBloc: button released -> ButtonStatus: $_buttonsState');
}
_buttonEnabledStatus$.add(_buttonsState); // update visuals
_buttonVibration$.add(buttonsState.released);
enableButtons = false;
Future.delayed(durationButtonDebounce, () {
enableButtons = true;
});
} else if (t.event == 4) {
// finger pressed on a button -> send event out
var whichButtonPressed;
if (t.y >= button0Upper &&
t.y <= button0Lower &&
_buttonPressed[0] == buttonsState.released) {
whichButtonPressed = 0;
} else if (t.y >= button1Upper &&
t.y <= button1Lower &&
_buttonPressed[1] == buttonsState.released) {
whichButtonPressed = 1;
} else if (t.y >= button2Upper &&
t.y <= button2Lower &&
_buttonPressed[2] == buttonsState.released) {
whichButtonPressed = 2;
}
if (whichButtonPressed != null &&
whichButtonPressed >= 0 &&
whichButtonPressed <= 2) {
print('bBloc: Button pressed!');
_buttonVibration$.add(buttonsState.pressed);
Future.delayed(durationButtonPressMinimum, () {
_buttonPressed[whichButtonPressed] = buttonsState.pressed;
});
}
}
}
}
Future _checkSlider(TouchData t) async {
const double topSlider = 75.0;
const double bottomSlider = 940.0;
int sliderPercent;
const double range = bottomSlider - topSlider;
double sliderPosition;
double sliderValue;
if ((t.event == 4 || t.event == 1)) {
if (t.y > topSlider) {
sliderPosition = t.y - topSlider;
} else {
sliderPosition = 0;
}
sliderValue = sliderPosition / range; // 0...1
sliderPercent = 100 - (sliderValue * 100).round(); // %
if (sliderPercent > 100) sliderPercent = 100;
if (sliderPercent < 0) sliderPercent = 0;
_slider$.add(sliderPercent);
}
}
void dispose() {
print('cleanup');
_disconnect();
_scanController.close();
_stopController.close();
_connectController.close();
_disconnectController.close();
_touchDataHistory$.close();
_touchVisualise$.close();
_buttonEnabledStatus$.close();
_buttonVibration$.close();
_slider$.close();
_batteryValue$.close();
_isScanning$.close();
_isConnected$.close();
_singleTouchMessage$.close();
_stateSubscription?.cancel();
_stateSubscription = null;
_scanSubscription?.cancel();
_scanSubscription = null;
deviceConnection?.cancel();
deviceConnection = null;
}
int checkButtonPressed(TouchData t) {
return 1;
}
int parseData(String s) {
// _parseData(s);
return 1;
}
}
+42
View File
@@ -0,0 +1,42 @@
import 'dart:async';
import 'package:rxdart/rxdart.dart';
import 'package:rxdart/subjects.dart';
class DebugBloc {
int _counter = 0;
bool _debugScreenEnabled = false;
static const debugSwitchValue = 3;
final _incrementController = StreamController<void>();
final _debugDisableController = StreamController<void>();
final _debugEnabledStatus$ = BehaviorSubject<bool>();
DebugBloc() {
print('init: Debug BLOC');
_incrementController.stream.listen((void _) {
_counter = _counter + 1;
print('counterBloc: debug counter = $_counter / $debugSwitchValue');
if(_counter % debugSwitchValue == 0){
_debugScreenEnabled = !_debugScreenEnabled;
_debugEnabledStatus$.add(_debugScreenEnabled);
_counter = 0;
}
});
_debugDisableController.stream.listen((void _){
if(_debugScreenEnabled){
_counter = 0;
_debugScreenEnabled = false;
_debugEnabledStatus$.add(_debugScreenEnabled);
}
});
}
Sink<void> get debugCounterIncrement => _incrementController.sink;
Sink<void> get debugDisable => _debugDisableController.sink;
Stream<bool> get debugEnabledStatus$ => _debugEnabledStatus$.stream;
void dispose() {
_incrementController.close();
_debugDisableController.close();
_debugEnabledStatus$.close();
}
}
+104
View File
@@ -0,0 +1,104 @@
import 'dart:async';
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:rxdart/rxdart.dart';
import 'package:rxdart/subjects.dart';
import 'package:touch_demonstrator/model/touchData.dart';
class TouchDataBloc {
final int xMax = 1200;
String inputString = "";
final history = List<TouchData>();
// final _touchData$ = BehaviorSubject<TouchData>(); // Touch Data from the input String
final _touchData$ = PublishSubject<TouchData>(); // Touch Data from the input String
final _touchVisualise$ = BehaviorSubject<Map<TouchData, Color>>();
final _touchDataHistory$ = BehaviorSubject<List<TouchData>>(); //All touches
// Controller Input of Data
final _inputTouchDataController = StreamController<String>();
// Controller for outputting
//SINKS (into bloc)
Sink<String> get inputTouchData => _inputTouchDataController.sink;
//STREAMS (output bloc)
Stream<TouchData> get outputTouchData$ => _touchData$.stream; //->
Stream<Map<TouchData,Color>> get outputVisualise$ => _touchVisualise$.stream; //->
Stream<List<TouchData>> get outputHistory$ => _touchDataHistory$.stream; //->
void dispose() {
_inputTouchDataController.close();
_touchData$.close();
_touchVisualise$.close();
_touchDataHistory$.close();
// _touchDataHistory$.close();
}
static List<Color> _colorOfTouches = [
Colors.blue,
Colors.red,
Colors.orange,
Colors.white,
Colors.yellow,
];
static List<TouchData> _lastFingerTouch = [
TouchData(5, 0, 1200, 1200),
TouchData(5, 1, 1200, 1200),
TouchData(5, 2, 1200, 1200),
TouchData(5, 3, 1200, 1200),
TouchData(5, 4, 1200, 1200),
];
Map<TouchData, Color> touchCollection = {
_lastFingerTouch[0]: _colorOfTouches[0],
_lastFingerTouch[1]: _colorOfTouches[1],
_lastFingerTouch[2]: _colorOfTouches[2],
_lastFingerTouch[3]: _colorOfTouches[3],
_lastFingerTouch[4]: _colorOfTouches[4],
};
TouchDataBloc() {
print('init: Touch Data BLOC');
_inputTouchDataController.stream.listen(_testTouchEventData);
}
void _updateStreams(TouchData t){
/* print("<- Update Streams (${t.e}|${t.f}|${t.x.toString().padLeft(4,'0')}|"
"${t.y.toString().padLeft(4,'0')})");*/
_lastFingerTouch[t.fingerNumber].touchEvent(t.event, t.x, t.y);
_touchData$.add(t); // Stream of single touches
_touchVisualise$.add(touchCollection);
//new:
history.add(t);
_touchDataHistory$.add(history);
}
void _testTouchEventData(String i) {
print('_testTouchEventData');
TouchData t = TouchData(0, 0, 0, 0);
inputString = i;
// print("input: $inputString");
RegExp regExp = new RegExp(
r"\(\d{1}\|\d{1}\|\d{4}\|\d{4}\)",
caseSensitive: false,
multiLine: false,
);
var matches = regExp.allMatches(inputString);
for (var m in matches) {
// print('${m.group(0)}');
t.event = int.tryParse(m.group(0)[1]);
t.fingerNumber = int.tryParse(m.group(0)[3]);
t.x = int.tryParse(m.group(0).substring(5, 9));
t.y = int.tryParse(m.group(0).substring(10, 14));
if (t.x < 1024 && t.y < 1024 && (t.fingerNumber <=4) && (t.event==1 || t.event==4 || t.event==5)){
_updateStreams(t);
print('straem update');
}
else{
print("Touch not Added!!!!!!!!!!!!");
}
}
}
}