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

187 lines
5.7 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:shared_preferences/shared_preferences.dart';
/// Selectable tactical map base tile styles for MOB-06 / MAP-02.
enum TacticalMapStyle {
tacticalDark,
satellite4K,
elevation3D,
}
extension TacticalMapStyleExtension on TacticalMapStyle {
String get displayName {
switch (this) {
case TacticalMapStyle.tacticalDark:
return 'Tactical Dark';
case TacticalMapStyle.satellite4K:
return 'Satellite 4K';
case TacticalMapStyle.elevation3D:
return '3D Topo Elevation';
}
}
String get subtitle {
switch (this) {
case TacticalMapStyle.tacticalDark:
return 'Vector with highlighted twisty passes';
case TacticalMapStyle.satellite4K:
return 'Esri / AWS aerial satellite imagery';
case TacticalMapStyle.elevation3D:
return 'Mountain contours & elevation shading';
}
}
IconData get icon {
switch (this) {
case TacticalMapStyle.tacticalDark:
return Icons.dark_mode_outlined;
case TacticalMapStyle.satellite4K:
return Icons.satellite_alt_outlined;
case TacticalMapStyle.elevation3D:
return Icons.terrain_outlined;
}
}
}
/// Tactical layer and overlay preferences for the motorcycle map HUD.
class MapLayerSettings {
final TacticalMapStyle style;
final bool showPoliceTraps;
final bool showPackBlips;
final bool showTwistyHighlights;
final bool offlineOnly;
const MapLayerSettings({
this.style = TacticalMapStyle.tacticalDark,
this.showPoliceTraps = true,
this.showPackBlips = true,
this.showTwistyHighlights = true,
this.offlineOnly = false,
});
MapLayerSettings copyWith({
TacticalMapStyle? style,
bool? showPoliceTraps,
bool? showPackBlips,
bool? showTwistyHighlights,
bool? offlineOnly,
}) {
return MapLayerSettings(
style: style ?? this.style,
showPoliceTraps: showPoliceTraps ?? this.showPoliceTraps,
showPackBlips: showPackBlips ?? this.showPackBlips,
showTwistyHighlights: showTwistyHighlights ?? this.showTwistyHighlights,
offlineOnly: offlineOnly ?? this.offlineOnly,
);
}
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is MapLayerSettings &&
runtimeType == other.runtimeType &&
style == other.style &&
showPoliceTraps == other.showPoliceTraps &&
showPackBlips == other.showPackBlips &&
showTwistyHighlights == other.showTwistyHighlights &&
offlineOnly == other.offlineOnly;
@override
int get hashCode =>
style.hashCode ^
showPoliceTraps.hashCode ^
showPackBlips.hashCode ^
showTwistyHighlights.hashCode ^
offlineOnly.hashCode;
}
class MapLayerSettingsNotifier extends StateNotifier<MapLayerSettings> {
static const String _prefKeyStyle = 'tactical_map_style';
static const String _prefKeyTraps = 'tactical_show_police_traps';
static const String _prefKeyPack = 'tactical_show_pack_blips';
static const String _prefKeyTwisty = 'tactical_show_twisty';
static const String _prefKeyOffline = 'tactical_offline_only';
MapLayerSettingsNotifier() : super(const MapLayerSettings()) {
_loadFromPrefs();
}
Future<void> _loadFromPrefs() async {
try {
final prefs = await SharedPreferences.getInstance();
final styleStr = prefs.getString(_prefKeyStyle);
final style = styleStr != null
? TacticalMapStyle.values.firstWhere(
(s) => s.name == styleStr,
orElse: () => TacticalMapStyle.tacticalDark,
)
: TacticalMapStyle.tacticalDark;
state = MapLayerSettings(
style: style,
showPoliceTraps: prefs.getBool(_prefKeyTraps) ?? true,
showPackBlips: prefs.getBool(_prefKeyPack) ?? true,
showTwistyHighlights: prefs.getBool(_prefKeyTwisty) ?? true,
offlineOnly: prefs.getBool(_prefKeyOffline) ?? false,
);
} catch (_) {}
}
Future<void> setStyle(TacticalMapStyle style) async {
state = state.copyWith(style: style);
try {
final prefs = await SharedPreferences.getInstance();
await prefs.setString(_prefKeyStyle, style.name);
} catch (_) {}
}
Future<void> togglePoliceTraps(bool val) async {
state = state.copyWith(showPoliceTraps: val);
try {
final prefs = await SharedPreferences.getInstance();
await prefs.setBool(_prefKeyTraps, val);
} catch (_) {}
}
Future<void> togglePackBlips(bool val) async {
state = state.copyWith(showPackBlips: val);
try {
final prefs = await SharedPreferences.getInstance();
await prefs.setBool(_prefKeyPack, val);
} catch (_) {}
}
Future<void> toggleTwistyHighlights(bool val) async {
state = state.copyWith(showTwistyHighlights: val);
try {
final prefs = await SharedPreferences.getInstance();
await prefs.setBool(_prefKeyTwisty, val);
} catch (_) {}
}
Future<void> toggleOfflineOnly(bool val) async {
state = state.copyWith(offlineOnly: val);
try {
final prefs = await SharedPreferences.getInstance();
await prefs.setBool(_prefKeyOffline, val);
} catch (_) {}
}
Future<void> resetToDefaults() async {
state = const MapLayerSettings();
try {
final prefs = await SharedPreferences.getInstance();
await prefs.remove(_prefKeyStyle);
await prefs.remove(_prefKeyTraps);
await prefs.remove(_prefKeyPack);
await prefs.remove(_prefKeyTwisty);
await prefs.remove(_prefKeyOffline);
} catch (_) {}
}
}
final mapLayerSettingsProvider =
StateNotifierProvider<MapLayerSettingsNotifier, MapLayerSettings>((ref) {
return MapLayerSettingsNotifier();
});