Vaani/lib/features/shake_detector/shake_detector.dart

86 lines
2.1 KiB
Dart
Raw Normal View History

import 'dart:async';
import 'dart:math';
import 'package:logging/logging.dart';
import 'package:sensors_plus/sensors_plus.dart';
import 'package:vaani/features/settings/models/app_settings.dart';
final _logger = Logger('ShakeDetector');
class ShakeDetector {
final ShakeDetectionSettings _settings;
final Function()? onShakeDetected;
ShakeDetector(
this._settings,
this.onShakeDetected, {
startImmediately = true,
}) {
_logger.fine('ShakeDetector created with settings: $_settings');
if (startImmediately) {
start();
}
}
StreamSubscription? _accelerometerSubscription;
int _currentShakeCount = 0;
DateTime _lastShakeTime = DateTime.now();
final StreamController<UserAccelerometerEvent>
_detectedShakeStreamController = StreamController.broadcast();
void start() {
if (_accelerometerSubscription != null) {
_logger.warning('ShakeDetector is already running');
return;
}
_accelerometerSubscription =
userAccelerometerEventStream(samplingPeriod: _settings.samplingPeriod)
.listen((event) {
_logger.finest('RMS: ${event.rms}');
if (event.rms > _settings.threshold) {
_currentShakeCount++;
if (_currentShakeCount >= _settings.shakeTriggerCount &&
!isCoolDownNeeded()) {
_logger.fine('Shake detected $_currentShakeCount times');
onShakeDetected?.call();
_detectedShakeStreamController.add(event);
_lastShakeTime = DateTime.now();
_currentShakeCount = 0;
}
} else {
_currentShakeCount = 0;
}
});
_logger.fine('ShakeDetector started');
}
void stop() {
_currentShakeCount = 0;
_accelerometerSubscription?.cancel();
_accelerometerSubscription = null;
_detectedShakeStreamController.close();
_logger.fine('ShakeDetector stopped');
}
void dispose() {
stop();
}
bool isCoolDownNeeded() {
return _lastShakeTime
.add(_settings.shakeTriggerCoolDown)
.isAfter(DateTime.now());
}
}
extension UserAccelerometerEventRMS on UserAccelerometerEvent {
double get rms => sqrt(x * x + y * y + z * z);
}