diff --git a/lib/app_state.dart b/lib/app_state.dart index c5508f7..4b805c2 100644 --- a/lib/app_state.dart +++ b/lib/app_state.dart @@ -122,6 +122,7 @@ class AppState extends ChangeNotifier { // Navigation search state bool get isNavigationSearchLoading => _navigationState.isSearchLoading; List get navigationSearchResults => _navigationState.searchResults; + int get navigationAvoidanceDistance => _settingsState.navigationAvoidanceDistance; // Profile state List get profiles => _profileState.profiles; @@ -645,6 +646,11 @@ class AppState extends ChangeNotifier { await _settingsState.setSuspectedLocationMinDistance(distance); } + /// Set navigation avoidance distance + Future setNavigationAvoidanceDistance(int distance) async { + await _settingsState.setNavigationAvoidanceDistance(distance); + } + // ---------- Queue Methods ---------- void clearQueue() { _uploadQueueState.clearQueue(); diff --git a/lib/screens/navigation_settings_screen.dart b/lib/screens/navigation_settings_screen.dart index 9bc8ab3..6e3b218 100644 --- a/lib/screens/navigation_settings_screen.dart +++ b/lib/screens/navigation_settings_screen.dart @@ -8,6 +8,7 @@ class NavigationSettingsScreen extends StatelessWidget { @override Widget build(BuildContext context) { + final appState = context.watch(); final locService = LocalizationService.instance; return AnimatedBuilder( @@ -26,48 +27,28 @@ class NavigationSettingsScreen extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - // Coming soon message - Card( - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Icon(Icons.info_outline, color: Colors.blue), - const SizedBox(width: 8), - Text( - 'Navigation Features', - style: Theme.of(context).textTheme.titleMedium?.copyWith( - fontWeight: FontWeight.bold, - ), - ), - ], - ), - const SizedBox(height: 8), - Text( - 'Navigation and routing settings will be available here. Coming soon:\n\n' - '• Surveillance avoidance distance\n' - '• Route planning preferences\n' - '• Search history management\n' - '• Distance units (metric/imperial)', - style: Theme.of(context).textTheme.bodyMedium, - ), - ], - ), - ), - ), - - const SizedBox(height: 24), - - // Placeholder settings (disabled for now) - _buildDisabledSetting( - context, - icon: Icons.warning_outlined, - title: locService.t('navigation.avoidanceDistance'), - subtitle: locService.t('navigation.avoidanceDistanceSubtitle'), - value: '100 ${locService.t('navigation.meters')}', + ListTile( + leading: const Icon(Icons.social_distance), + title: Text(locService.t('navigation.avoidanceDistance')), + subtitle: Text(locService.t('navigation.avoidanceDistanceSubtitle')), + trailing: SizedBox( + width: 80, + child: TextFormField( + initialValue: appState.navigationAvoidanceDistance.toString(), + keyboardType: const TextInputType.numberWithOptions(signed: false, decimal: false), + textInputAction: TextInputAction.done, + decoration: const InputDecoration( + isDense: true, + contentPadding: EdgeInsets.symmetric(vertical: 6, horizontal: 8), + border: OutlineInputBorder(), + suffixText: 'm', + ), + onFieldSubmitted: (value) { + final distance = int.tryParse(value) ?? 250; + appState.setNavigationAvoidanceDistance(distance.clamp(0, 2000)); + } + ) + ) ), const Divider(), @@ -126,4 +107,4 @@ class NavigationSettingsScreen extends StatelessWidget { ), ); } -} \ No newline at end of file +} diff --git a/lib/services/routing_service.dart b/lib/services/routing_service.dart index 62eaa03..6b3c95f 100644 --- a/lib/services/routing_service.dart +++ b/lib/services/routing_service.dart @@ -2,6 +2,7 @@ import 'dart:convert'; import 'package:flutter/foundation.dart'; import 'package:http/http.dart' as http; import 'package:latlong2/latlong.dart'; +import 'package:shared_preferences/shared_preferences.dart'; class RouteResult { final List waypoints; @@ -31,6 +32,9 @@ class RoutingService { required LatLng end, }) async { debugPrint('[RoutingService] Calculating route from $start to $end'); + + final prefs = await SharedPreferences.getInstance(); + final avoidance_distance = await prefs.getInt('navigation_avoidance_distance'); final uri = Uri.parse('$_baseUrl'); final params = { @@ -42,6 +46,7 @@ class RoutingService { 'longitude': end.longitude, 'latitude': end.latitude }, + 'avoidance_distance': avoidance_distance, 'enabled_profiles': [ // revise to be dynamic based on user input { 'id': 'generic-ALPR', @@ -50,7 +55,8 @@ class RoutingService { 'surveillance:type': 'ALPR' } } - ] + ], + 'show_exclusion_zone': false, // if true, returns a GeoJSON Feature MultiPolygon showing what areas are avoided in calculating the route }; debugPrint('[RoutingService] alprwatch request: $uri $params'); diff --git a/lib/state/navigation_state.dart b/lib/state/navigation_state.dart index e94c7cb..f090c64 100644 --- a/lib/state/navigation_state.dart +++ b/lib/state/navigation_state.dart @@ -224,7 +224,7 @@ class NavigationState extends ChangeNotifier { /// Calculate route using alprwatch void _calculateRoute() { if (_routeStart == null || _routeEnd == null) return; - + debugPrint('[NavigationState] Calculating route with alprwatch...'); _isCalculating = true; _routingError = null; diff --git a/lib/state/settings_state.dart b/lib/state/settings_state.dart index c07ef32..8b0eb15 100644 --- a/lib/state/settings_state.dart +++ b/lib/state/settings_state.dart @@ -29,6 +29,7 @@ class SettingsState extends ChangeNotifier { static const String _networkStatusIndicatorEnabledPrefsKey = 'network_status_indicator_enabled'; static const String _suspectedLocationMinDistancePrefsKey = 'suspected_location_min_distance'; static const String _pauseQueueProcessingPrefsKey = 'pause_queue_processing'; + static const String _navigationAvoidanceDistancePrefsKey = 'navigation_avoidance_distance'; bool _offlineMode = false; bool _pauseQueueProcessing = false; @@ -41,6 +42,7 @@ class SettingsState extends ChangeNotifier { int _suspectedLocationMinDistance = 100; // meters List _tileProviders = []; String _selectedTileTypeId = ''; + int _navigationAvoidanceDistance = 250; // meters // Getters bool get offlineMode => _offlineMode; @@ -54,6 +56,7 @@ class SettingsState extends ChangeNotifier { int get suspectedLocationMinDistance => _suspectedLocationMinDistance; List get tileProviders => List.unmodifiable(_tileProviders); String get selectedTileTypeId => _selectedTileTypeId; + int get navigationAvoidanceDistance => _navigationAvoidanceDistance; /// Get the currently selected tile type TileType? get selectedTileType { @@ -100,6 +103,11 @@ class SettingsState extends ChangeNotifier { // Load max nodes _maxNodes = prefs.getInt(_maxNodesPrefsKey) ?? kDefaultMaxNodes; + + // Load navigation avoidance distance + if (prefs.containsKey(_navigationAvoidanceDistancePrefsKey)) { + _navigationAvoidanceDistance = prefs.getInt(_navigationAvoidanceDistancePrefsKey) ?? 250; + } // Load proximity alerts settings _proximityAlertsEnabled = prefs.getBool(_proximityAlertsEnabledPrefsKey) ?? false; @@ -351,4 +359,14 @@ class SettingsState extends ChangeNotifier { } } -} \ No newline at end of file + // Set distance for avoidance of nodes during navigation + Future setNavigationAvoidanceDistance(int distance) async { + if (_navigationAvoidanceDistance != distance) { + _navigationAvoidanceDistance = distance; + final prefs = await SharedPreferences.getInstance(); + await prefs.setInt(_navigationAvoidanceDistancePrefsKey, distance); + notifyListeners(); + } + } + +}