6d1cf5fac3
- Add GpsDataManager singleton service for centralized GPS data processing - Refactor main app to use processed GPS data streams instead of raw position data - Add haptic feedback to all main UI tap interactions (theme, unit, navigation) - Implement faster GPS update frequency (500ms timeLimit in LocationSettings) - Clean up verbose debug logging while preserving essential error logs - Remove unused debug variables and imports - Preserve existing background survival mechanisms and overlay lifecycle - Add temporary GPS simulation while resolving geolocator engine conflicts Architecture improvements: - Clean data flow: GPS Hardware → GpsDataManager → Main App → Overlay - Single source of truth for processed GPS data in manager - Separation of concerns: GPS logic isolated from UI components - Foundation ready for intelligent caching logic implementation Technical notes: - GPS engine conflict detected, temporarily using simulation data - All functionality tested and working with test data - Real GPS integration pending engine conflict resolution 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
47 lines
1.5 KiB
Dart
47 lines
1.5 KiB
Dart
import 'dart:async';
|
|
import 'package:geolocator/geolocator.dart';
|
|
import 'package:permission_handler/permission_handler.dart';
|
|
|
|
class GpsService {
|
|
static double? _lastValidHeading;
|
|
|
|
static Stream<Position> get positionStream {
|
|
return Geolocator.getPositionStream(
|
|
locationSettings: const LocationSettings(
|
|
accuracy: LocationAccuracy.bestForNavigation,
|
|
distanceFilter: 0,
|
|
timeLimit: Duration(milliseconds: 500), // Force updates every 500ms for faster GPS refresh
|
|
),
|
|
);
|
|
}
|
|
|
|
static Future<bool> requestPermissions() async {
|
|
final permission = await Permission.locationWhenInUse.request();
|
|
return permission.isGranted;
|
|
}
|
|
|
|
static Future<bool> isLocationServiceEnabled() async {
|
|
return await Geolocator.isLocationServiceEnabled();
|
|
}
|
|
|
|
static double getCachedHeading(double heading) {
|
|
if (heading >= 0 && heading <= 360) {
|
|
_lastValidHeading = heading;
|
|
return heading;
|
|
}
|
|
return _lastValidHeading ?? 0.0;
|
|
}
|
|
|
|
static String getCompassDirection(double heading) {
|
|
final cachedHeading = getCachedHeading(heading);
|
|
|
|
const directions = ['N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW'];
|
|
final index = ((cachedHeading + 22.5) / 45).floor() % 8;
|
|
return directions[index];
|
|
}
|
|
|
|
static String formatHeading(double heading) {
|
|
final cachedHeading = getCachedHeading(heading);
|
|
return '${cachedHeading.round()} ${getCompassDirection(heading)}'; // don't add that degree symbol, this is cooler
|
|
}
|
|
} |