MotorSignal-App/lib/services/map/map_providers.dart

163 lines
4.5 KiB
Dart

import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'aws_map_provider.dart';
import 'google_map_provider.dart';
import 'map_provider_interface.dart';
import 'open_street_map_provider.dart';
final mapConfigProvider = Provider<MapConfig>((ref) {
final type = ref.watch(mapProviderTypeNotifierProvider);
if (type == AppMapType.openStreetMap) {
return const MapConfig();
}
final aws = ref.watch(awsMapProviderInstance);
return MapConfig.awsLocation(apiKey: aws.apiKey, region: aws.region);
});
class MapProviderTypeNotifier extends StateNotifier<AppMapType> {
static const String _prefKey = 'selected_map_provider_type';
MapProviderTypeNotifier() : super(AppMapType.awsMaps) {
_loadFromPrefs();
}
Future<void> _loadFromPrefs() async {
try {
final prefs = await SharedPreferences.getInstance();
final savedVal = prefs.getString(_prefKey);
if (savedVal == 'googleMaps') {
state = AppMapType.googleMaps;
} else if (savedVal == 'openStreetMap') {
state = AppMapType.openStreetMap;
} else if (savedVal == 'awsMaps') {
state = AppMapType.awsMaps;
}
} catch (_) {}
}
Future<void> setMapProviderType(AppMapType type) async {
state = type;
try {
final prefs = await SharedPreferences.getInstance();
await prefs.setString(_prefKey, type.name);
} catch (_) {}
}
}
final mapProviderTypeNotifierProvider =
StateNotifierProvider<MapProviderTypeNotifier, AppMapType>((ref) {
return MapProviderTypeNotifier();
});
final openStreetMapProviderInstance = Provider<OpenStreetMapProvider>((ref) {
return OpenStreetMapProvider();
});
final googleMapProviderInstance = Provider<GoogleMapProvider>((ref) {
return GoogleMapProvider();
});
final awsMapProviderInstance = Provider<AwsMapProvider>((ref) {
return AwsMapProvider();
});
final activeMapProvider = Provider<AppMapProvider>((ref) {
final type = ref.watch(mapProviderTypeNotifierProvider);
switch (type) {
case AppMapType.openStreetMap:
return ref.watch(openStreetMapProviderInstance);
case AppMapType.googleMaps:
return ref.watch(googleMapProviderInstance);
case AppMapType.awsMaps:
return ref.watch(awsMapProviderInstance);
}
});
class MapFollowNotifier extends StateNotifier<bool> {
MapFollowNotifier() : super(true);
void setFollow(bool follow) {
state = follow;
}
void userInteracted() {
state = false;
}
void recenter() {
state = true;
}
}
final mapFollowStateProvider =
StateNotifierProvider<MapFollowNotifier, bool>((ref) {
return MapFollowNotifier();
});
/// Map orientation mode: North Up vs Heading Up.
enum MapOrientation {
northUp,
headingUp;
String get displayName => this == northUp ? 'North Up' : 'Heading Up';
}
/// Computes the shortest angular difference in degrees from [from] to [to].
/// Result is in range (-180.0, 180.0].
/// Handles circular transitions across the 0°/360° discontinuity:
/// e.g. from 359° to 1° yields +2°, not -358°.
double shortestAngleDiff(double from, double to) {
return ((to - from + 540.0) % 360.0) - 180.0;
}
/// Normalizes an angle in degrees into [0.0, 360.0).
double normalizeAngle(double angle) {
return (angle % 360.0 + 360.0) % 360.0;
}
class MapOrientationNotifier extends StateNotifier<MapOrientation> {
static const String _prefKey = 'selected_map_orientation';
MapOrientationNotifier() : super(MapOrientation.northUp) {
_loadFromPrefs();
}
Future<void> _loadFromPrefs() async {
try {
final prefs = await SharedPreferences.getInstance();
final savedVal = prefs.getString(_prefKey);
if (savedVal == 'headingUp') {
state = MapOrientation.headingUp;
} else if (savedVal == 'northUp') {
state = MapOrientation.northUp;
}
} catch (_) {}
}
Future<void> toggle() async {
final next = state == MapOrientation.northUp
? MapOrientation.headingUp
: MapOrientation.northUp;
state = next;
try {
final prefs = await SharedPreferences.getInstance();
await prefs.setString(_prefKey, next.name);
} catch (_) {}
}
Future<void> setOrientation(MapOrientation orientation) async {
state = orientation;
try {
final prefs = await SharedPreferences.getInstance();
await prefs.setString(_prefKey, orientation.name);
} catch (_) {}
}
}
final mapOrientationProvider =
StateNotifierProvider<MapOrientationNotifier, MapOrientation>((ref) {
return MapOrientationNotifier();
});