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 { 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 _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 setStyle(TacticalMapStyle style) async { state = state.copyWith(style: style); try { final prefs = await SharedPreferences.getInstance(); await prefs.setString(_prefKeyStyle, style.name); } catch (_) {} } Future togglePoliceTraps(bool val) async { state = state.copyWith(showPoliceTraps: val); try { final prefs = await SharedPreferences.getInstance(); await prefs.setBool(_prefKeyTraps, val); } catch (_) {} } Future togglePackBlips(bool val) async { state = state.copyWith(showPackBlips: val); try { final prefs = await SharedPreferences.getInstance(); await prefs.setBool(_prefKeyPack, val); } catch (_) {} } Future toggleTwistyHighlights(bool val) async { state = state.copyWith(showTwistyHighlights: val); try { final prefs = await SharedPreferences.getInstance(); await prefs.setBool(_prefKeyTwisty, val); } catch (_) {} } Future toggleOfflineOnly(bool val) async { state = state.copyWith(offlineOnly: val); try { final prefs = await SharedPreferences.getInstance(); await prefs.setBool(_prefKeyOffline, val); } catch (_) {} } Future 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((ref) { return MapLayerSettingsNotifier(); });