gps_speed_controller.dart 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. import 'dart:async';
  2. import 'package:flutter/foundation.dart';
  3. import '../../data/models/gps_speed.dart';
  4. import '../../data/services/telemetry_bridge.dart';
  5. /// Polls the native GPS speed snapshot. Starting never asks for permission; it
  6. /// simply returns false when precise location is not already allowed or GPS is
  7. /// disabled.
  8. class GpsSpeedController extends ChangeNotifier {
  9. GpsSpeedController(this._platform, {DateTime Function()? clock})
  10. : _clock = clock ?? DateTime.now;
  11. final TelemetryPlatform _platform;
  12. final DateTime Function() _clock;
  13. GpsSpeed _state = const GpsSpeed();
  14. Timer? _timer;
  15. bool _active = false;
  16. bool _polling = false;
  17. bool _disposed = false;
  18. bool get hasPermission => _state.hasPermission;
  19. bool get hasSpeed => _state.isFresh(_clock());
  20. double? get speedKmh => hasSpeed ? _state.speedKmh : null;
  21. Future<void> start() async {
  22. if (_active) return;
  23. _active = true;
  24. final started = await _platform.startGpsSpeed();
  25. if (!started) {
  26. _active = false;
  27. _notify();
  28. return;
  29. }
  30. _timer = Timer.periodic(const Duration(seconds: 1), (_) => _poll());
  31. await _poll();
  32. }
  33. /// Asks for precise location access and starts the fallback when granted.
  34. ///
  35. /// Used only by the Settings switches that explicitly choose GPS speed; the
  36. /// normal resume path still never prompts.
  37. Future<bool> requestPermission() async {
  38. final granted = await _platform.ensureLocationPermission();
  39. if (!granted) {
  40. _notify();
  41. return false;
  42. }
  43. _timer?.cancel();
  44. _timer = null;
  45. _active = false;
  46. await start();
  47. return true;
  48. }
  49. void stop() {
  50. _active = false;
  51. _timer?.cancel();
  52. _timer = null;
  53. _state = const GpsSpeed();
  54. unawaited(_platform.stopGpsSpeed());
  55. _notify();
  56. }
  57. Future<void> _poll() async {
  58. if (!_active || _polling) return;
  59. _polling = true;
  60. try {
  61. final next = await _platform.getGpsSpeed();
  62. if (next != _state) {
  63. _state = next;
  64. _notify();
  65. }
  66. } finally {
  67. _polling = false;
  68. }
  69. }
  70. void _notify() {
  71. if (!_disposed) notifyListeners();
  72. }
  73. @override
  74. void dispose() {
  75. _disposed = true;
  76. _timer?.cancel();
  77. unawaited(_platform.stopGpsSpeed());
  78. super.dispose();
  79. }
  80. }