Files
irene c2bcd685cf feat: add 4Hz GPS update interval
- Switch LocationSettings to AndroidSettings with intervalDuration: 250ms.
- 250ms = 4Hz; higher rate is only achievable when GNSS is available (not indoors).
2026-08-27 13:17:15 +09:00

75 lines
2.2 KiB
Dart

import 'dart:async';
import 'package:geolocator/geolocator.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:wakelock_plus/wakelock_plus.dart';
import '../../core/constants/gps_constants.dart';
/// Lightweight stateless wrapper around Geolocator.
///
/// Only handles platform I/O — no business logic.
class GpsService {
static double? _lastValidHeading;
/// Create a position stream with dynamic accuracy setting.
static Stream<Position> createPositionStream({
LocationAccuracy accuracy = LocationAccuracy.high,
}) {
return Geolocator.getPositionStream(
locationSettings: AndroidSettings(
accuracy: accuracy,
distanceFilter: 0,
intervalDuration: Duration(milliseconds: 250),
),
);
}
static Future<bool> requestPermissions() async {
final permission = await Permission.locationWhenInUse.request();
return permission.isGranted;
}
static Future<bool> isLocationServiceEnabled() async {
return await Geolocator.isLocationServiceEnabled();
}
static Future<Position?> getCurrentPosition({
LocationAccuracy accuracy = LocationAccuracy.bestForNavigation,
Duration timeLimit = const Duration(seconds: 60),
}) async {
try {
return await Geolocator.getCurrentPosition(
locationSettings: LocationSettings(
accuracy: accuracy,
timeLimit: timeLimit,
),
);
} catch (_) {
return null;
}
}
static double getCachedHeading(double heading) {
if (heading >= GpsConfig.VALID_HEADING_MIN && heading <= GpsConfig.VALID_HEADING_MAX) {
_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)}';
}
static Future<void> setWakeLock(bool enable) async {
await WakelockPlus.toggle(enable: enable);
}
}