2025-08-24 22:35:20 +09:00
|
|
|
import 'dart:async';
|
|
|
|
|
import 'package:geolocator/geolocator.dart';
|
|
|
|
|
import 'package:permission_handler/permission_handler.dart';
|
2026-02-09 21:33:28 +09:00
|
|
|
import 'config/gps_constants.dart';
|
2025-08-24 22:35:20 +09:00
|
|
|
|
|
|
|
|
class GpsService {
|
2025-08-25 07:26:20 +09:00
|
|
|
static double? _lastValidHeading;
|
2026-02-09 21:33:28 +09:00
|
|
|
|
2026-02-12 09:00:10 +09:00
|
|
|
/// Create a position stream with dynamic accuracy setting
|
|
|
|
|
static Stream<Position> createPositionStream({
|
|
|
|
|
LocationAccuracy accuracy = LocationAccuracy.high,
|
|
|
|
|
}) {
|
2025-08-24 22:35:20 +09:00
|
|
|
return Geolocator.getPositionStream(
|
2026-02-12 09:00:10 +09:00
|
|
|
locationSettings: LocationSettings(
|
|
|
|
|
accuracy: accuracy,
|
2025-08-25 07:26:20 +09:00
|
|
|
distanceFilter: 0,
|
2025-08-24 22:35:20 +09:00
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
2026-02-09 21:33:28 +09:00
|
|
|
|
2026-02-12 09:00:10 +09:00
|
|
|
/// Deprecated: Use createPositionStream() instead
|
|
|
|
|
@Deprecated('Use createPositionStream(accuracy: LocationAccuracy.bestForNavigation) instead')
|
|
|
|
|
static Stream<Position> get positionStream {
|
|
|
|
|
return createPositionStream(accuracy: LocationAccuracy.bestForNavigation);
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-24 22:35:20 +09:00
|
|
|
static Future<bool> requestPermissions() async {
|
|
|
|
|
final permission = await Permission.locationWhenInUse.request();
|
|
|
|
|
return permission.isGranted;
|
|
|
|
|
}
|
2026-02-09 21:33:28 +09:00
|
|
|
|
2025-08-24 22:35:20 +09:00
|
|
|
static Future<bool> isLocationServiceEnabled() async {
|
|
|
|
|
return await Geolocator.isLocationServiceEnabled();
|
|
|
|
|
}
|
2026-02-09 21:33:28 +09:00
|
|
|
|
2025-08-25 07:26:20 +09:00
|
|
|
static double getCachedHeading(double heading) {
|
2026-02-09 21:33:28 +09:00
|
|
|
if (heading >= GpsConfig.VALID_HEADING_MIN && heading <= GpsConfig.VALID_HEADING_MAX) {
|
2025-08-25 07:26:20 +09:00
|
|
|
_lastValidHeading = heading;
|
|
|
|
|
return heading;
|
|
|
|
|
}
|
|
|
|
|
return _lastValidHeading ?? 0.0;
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-24 22:35:20 +09:00
|
|
|
static String getCompassDirection(double heading) {
|
2025-08-25 07:26:20 +09:00
|
|
|
final cachedHeading = getCachedHeading(heading);
|
2025-08-24 22:35:20 +09:00
|
|
|
|
|
|
|
|
const directions = ['N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW'];
|
2025-08-25 07:26:20 +09:00
|
|
|
final index = ((cachedHeading + 22.5) / 45).floor() % 8;
|
2025-08-24 22:35:20 +09:00
|
|
|
return directions[index];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static String formatHeading(double heading) {
|
2025-08-25 07:26:20 +09:00
|
|
|
final cachedHeading = getCachedHeading(heading);
|
2025-08-25 23:06:46 +09:00
|
|
|
return '${cachedHeading.round()} ${getCompassDirection(heading)}'; // don't add that degree symbol, this is cooler
|
2025-08-24 22:35:20 +09:00
|
|
|
}
|
2025-10-02 21:43:29 +09:00
|
|
|
}
|