refactor(data): create layered architecture with core/data/ui packages
- Move constants from lib/config/ to lib/core/constants/ - Move color themes to lib/core/theme/ - Create LocationData domain model in data/models/ - Create lightweight GpsService in data/services/ - Create LocationRepository in data/repositories/ consolidating GpsDataManager business logic (GPS stream, staleness, precision) - Create shared SpeedDisplay widget in ui/shared/ - Defer overlay feature — stubs reserved in ui/features/overlay/
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
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: LocationSettings(
|
||||
accuracy: accuracy,
|
||||
distanceFilter: 0,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user