chore(02-01): add provider dependencies and refactor GpsDataManager

- Added provider ^6.1.2 and shared_preferences ^2.3.4 to pubspec.yaml
- Removed singleton pattern from GpsDataManager (deleted _instance and instance getter)
- Changed GpsDataManager._internal() to public GpsDataManager() constructor
- Extended ChangeNotifier to enable reactive state updates
- Added _isDisposed guard field to prevent disposed notifications
- Updated _updateData() to call notifyListeners() after stream emission
- Added _isDisposed guards to _onGpsError() and _handleStaleDataTimeout()
- Updated dispose() to set _isDisposed, call super.dispose() last, removed _isInitialized reset
This commit is contained in:
Mikkeli Matlock
2026-02-10 22:03:13 +09:00
parent ee73a1a48d
commit f458b62eea
2 changed files with 17 additions and 6 deletions
+11 -6
View File
@@ -1,4 +1,5 @@
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:geolocator/geolocator.dart';
import '../gps_service.dart';
import '../config/speed_unit.dart';
@@ -6,11 +7,8 @@ import '../config/gps_constants.dart';
import '../models/processed_gps_data.dart';
import 'logger.dart';
class GpsDataManager {
static GpsDataManager? _instance;
static GpsDataManager get instance => _instance ??= GpsDataManager._internal();
GpsDataManager._internal();
class GpsDataManager extends ChangeNotifier {
GpsDataManager();
StreamSubscription<Position>? _gpsSubscription;
final StreamController<ProcessedGpsData> _dataController =
@@ -26,6 +24,7 @@ class GpsDataManager {
);
Timer? _staleDataTimer;
bool _isDisposed = false;
// Public stream for UI components to subscribe to
Stream<ProcessedGpsData> get dataStream => _dataController.stream;
@@ -157,6 +156,7 @@ class GpsDataManager {
}
void _onGpsError(dynamic error) {
if (_isDisposed) return;
// Handle GPS errors gracefully
final errorString = error.toString().toLowerCase();
if (!errorString.contains('timeout') && !errorString.contains('temporarily')) {
@@ -175,6 +175,7 @@ class GpsDataManager {
}
void _handleStaleDataTimeout() {
if (_isDisposed) return;
// Avoid overriding explicit GPS error states or repeated stale notifications
final displayText = _currentData.displaySpeed;
if (displayText == '--' || displayText.startsWith('GPS') || displayText == 'NO PERM') {
@@ -198,9 +199,11 @@ class GpsDataManager {
}
void _updateData(ProcessedGpsData newData) {
if (_isDisposed) return;
Logger.debug('Broadcasting data: ${newData.displaySpeed} ${newData.displayHeading}', 'GpsDataManager');
_currentData = newData;
_dataController.add(newData);
notifyListeners();
Logger.debug('Data broadcast complete', 'GpsDataManager');
}
@@ -212,7 +215,9 @@ class GpsDataManager {
return convertedSpeed < 1.0 ? '--' : convertedSpeed.toStringAsFixed(1);
}
@override
void dispose() {
_isDisposed = true;
Logger.info('Disposing GPS manager...', 'GpsDataManager');
if (_gpsSubscription != null) {
Logger.debug('Cancelling GPS subscription...', 'GpsDataManager');
@@ -223,7 +228,7 @@ class GpsDataManager {
_staleDataTimer?.cancel();
_staleDataTimer = null;
_dataController.close();
_isInitialized = false;
Logger.info('GPS manager disposed', 'GpsDataManager');
super.dispose();
}
}