Last active
January 13, 2025 16:35
-
-
Save PlugFox/a60a7b02b9b96ddaf06a446c7750daa4 to your computer and use it in GitHub Desktop.
ShakeDetector
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'dart:async'; | |
import 'dart:math' as math; | |
import 'package:flutter/widgets.dart'; | |
import 'package:sensors_plus/sensors_plus.dart' as sensors show accelerometerEvents; | |
// ignore: prefer_mixin | |
class ShakeDetector with ChangeNotifier { | |
ShakeDetector({ | |
int minShakeCount = 5, | |
num shakeThresholdGravity = 3, | |
Duration minTimeBetweenShakes = const Duration(milliseconds: 250), | |
Duration shakeCountResetTime = const Duration(milliseconds: 1500), | |
}) : _minShakeCount = minShakeCount, | |
_shakeThresholdGravity = shakeThresholdGravity, | |
_minTimeBetweenShakes = minTimeBetweenShakes, | |
_shakeCountResetTime = shakeCountResetTime { | |
_startListening(); | |
} | |
/// Количество встряхиваний для срабатывания уведомления | |
final int _minShakeCount; | |
/// Ускорение при котором движение телефона считается | |
/// за встряхивание | |
final num _shakeThresholdGravity; | |
/// Минимальное окно между встряхиваниями | |
/// Все что меньше него - игнорируется | |
final Duration _minTimeBetweenShakes; | |
/// Промежуток времени после которого сбрасывается прогресс | |
final Duration _shakeCountResetTime; | |
final _stopwatch = Stopwatch(); | |
StreamSubscription<num>? _streamSubscription; | |
/// Приостановить подписку | |
void pause() => _streamSubscription?.pause(); | |
/// Продолжить подписку | |
void resume() => _streamSubscription?.resume(); | |
@override | |
@mustCallSuper | |
void dispose() { | |
_stopListening(); | |
super.dispose(); | |
} | |
/// Starts listening to accerelometer events | |
void _startListening() { | |
var shakeCount = 0; | |
_stopwatch.start(); | |
_streamSubscription = sensors.accelerometerEvents.where((_) => _stopwatch.elapsed > _minTimeBetweenShakes).map<num>((event) { | |
final gX = event.x / 9.81; | |
final gY = event.y / 9.81; | |
final gZ = event.z / 9.81; | |
// gForce will be close to 1 when there is no movement. | |
final gForce = math.sqrt( | |
math.pow(gX, 2) + math.pow(gY, 2) + math.pow(gZ, 2), | |
); | |
return gForce; | |
}).listen( | |
(gForce) { | |
if (gForce < _shakeThresholdGravity) return; | |
// reset the shake count after 1.5 seconds of no shakes | |
if (_stopwatch.elapsed > _shakeCountResetTime) { | |
shakeCount = 0; | |
} | |
_stopwatch.reset(); | |
//print('#$shakeCount gForce:$gForce elapsed: ${elapsed.inMilliseconds}'); | |
if (++shakeCount >= _minShakeCount) { | |
shakeCount = 0; | |
notifyListeners(); | |
} | |
}, | |
cancelOnError: false, | |
onDone: _stopwatch.stop, | |
); | |
} | |
/// Stops listening to accelerometer events | |
void _stopListening() => _streamSubscription?.cancel(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment