diff --git a/DEVELOPER.md b/DEVELOPER.md index 15ac2e3..bcf13db 100644 --- a/DEVELOPER.md +++ b/DEVELOPER.md @@ -484,11 +484,13 @@ The major performance issue was discovered to be double caching with expensive o - **Smart queue management**: Drops oldest requests when queue fills up - **Reduced concurrent connections**: 8 threads instead of 10 for better stability across platforms -### 14. Navigation & Routing (Implemented, Awaiting Integration) +### 14. Navigation & Routing (Implemented and Active) **Current state:** - **Search functionality**: Fully implemented and active - **Avoidance routing**: Fully implemented and active +- **Distance feedback**: Shows real-time distance when selecting second route point +- **Long distance warnings**: Alerts users when routes may timeout (configurable threshold) - **Offline routing**: Requires vector map tiles **Architecture:** @@ -496,6 +498,12 @@ The major performance issue was discovered to be double caching with expensive o - RoutingService handles API communication and route calculation - SearchService provides location lookup and geocoding +**Distance warning system (v1.7.0):** +- **Real-time distance display**: Shows distance from first to second point during selection +- **Configurable threshold**: `kNavigationDistanceWarningThreshold` in dev_config (default 30km) +- **User feedback**: Warning message about potential timeouts for long routes +- **Brutalist approach**: Simple distance calculation using existing `Distance()` utility + --- ## Key Design Decisions & Rationales diff --git a/assets/changelog.json b/assets/changelog.json index 27fd285..229b0ba 100644 --- a/assets/changelog.json +++ b/assets/changelog.json @@ -1,4 +1,10 @@ { + "1.7.0": { + "content": [ + "• NEW: Distance display when selecting second navigation point - shows distance from first location in real-time", + "• NEW: Long distance warning - routes over 30km display a warning about potential timeouts with a note that improvements are coming" + ] + }, "1.6.3": { "content": [ "• Fixed navigation sheet button flow - route to/from buttons no longer reappear after selecting second location", diff --git a/lib/app_state.dart b/lib/app_state.dart index f5e4140..3c008ca 100644 --- a/lib/app_state.dart +++ b/lib/app_state.dart @@ -114,6 +114,8 @@ class AppState extends ChangeNotifier { bool get settingRouteStart => _navigationState.settingRouteStart; bool get isSettingSecondPoint => _navigationState.isSettingSecondPoint; bool get areRoutePointsTooClose => _navigationState.areRoutePointsTooClose; + double? get distanceFromFirstPoint => _navigationState.distanceFromFirstPoint; + bool get distanceExceedsWarningThreshold => _navigationState.distanceExceedsWarningThreshold; bool get isCalculating => _navigationState.isCalculating; bool get showingOverview => _navigationState.showingOverview; String? get routingError => _navigationState.routingError; diff --git a/lib/dev_config.dart b/lib/dev_config.dart index bd4c3b9..317926f 100644 --- a/lib/dev_config.dart +++ b/lib/dev_config.dart @@ -128,6 +128,7 @@ const double kNodeProximityWarningDistance = 15.0; // meters - distance threshol // Navigation route planning configuration const double kNavigationMinRouteDistance = 100.0; // meters - minimum distance between start and end points +const double kNavigationDistanceWarningThreshold = 20000.0; // meters - distance threshold for timeout warning (30km) // Node display configuration const int kDefaultMaxNodes = 500; // Default maximum number of nodes to render on the map at once diff --git a/lib/state/navigation_state.dart b/lib/state/navigation_state.dart index ea7d488..48b90eb 100644 --- a/lib/state/navigation_state.dart +++ b/lib/state/navigation_state.dart @@ -87,6 +87,24 @@ class NavigationState extends ChangeNotifier { return distance < kNavigationMinRouteDistance; } + /// Get distance from first navigation point to provisional location during second point selection + double? get distanceFromFirstPoint { + if (!_isSettingSecondPoint || _provisionalPinLocation == null) return null; + + final firstPoint = _nextPointIsStart ? _routeEnd : _routeStart; + if (firstPoint == null) return null; + + return const Distance().as(LengthUnit.Meter, firstPoint, _provisionalPinLocation!); + } + + /// Check if distance between points would likely cause timeout issues + bool get distanceExceedsWarningThreshold { + final distance = distanceFromFirstPoint; + if (distance == null) return false; + + return distance > kNavigationDistanceWarningThreshold; + } + /// BRUTALIST: Single entry point to search mode void enterSearchMode(LatLng mapCenter) { debugPrint('[NavigationState] enterSearchMode - current mode: $_mode'); diff --git a/lib/widgets/navigation_sheet.dart b/lib/widgets/navigation_sheet.dart index d4d2570..a783331 100644 --- a/lib/widgets/navigation_sheet.dart +++ b/lib/widgets/navigation_sheet.dart @@ -161,7 +161,50 @@ class NavigationSheet extends StatelessWidget { coordinates: provisionalLocation, address: provisionalAddress, ), - const SizedBox(height: 16), + const SizedBox(height: 8), + + // Show distance from first point + if (appState.distanceFromFirstPoint != null) ...[ + Text( + 'Distance: ${(appState.distanceFromFirstPoint! / 1000).toStringAsFixed(1)} km', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: Colors.grey[600], + ), + ), + const SizedBox(height: 8), + ], + + // Show distance warning if threshold exceeded + if (appState.distanceExceedsWarningThreshold) ...[ + Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: Colors.amber.withOpacity(0.1), + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Colors.amber.withOpacity(0.3)), + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Icon(Icons.warning_amber, color: Colors.amber[700], size: 20), + const SizedBox(width: 8), + Expanded( + child: Text( + 'Trips longer than ${(kNavigationDistanceWarningThreshold / 1000).toStringAsFixed(0)} km are likely to time out. We are working to improve this; stay tuned.', + style: TextStyle( + fontSize: 14, + color: Colors.amber[700], + ), + ), + ), + ], + ), + ), + const SizedBox(height: 8), + ], + // Show warning message if locations are too close if (appState.areRoutePointsTooClose) ...[ diff --git a/pubspec.yaml b/pubspec.yaml index 605df20..b23ef00 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: deflockapp description: Map public surveillance infrastructure with OpenStreetMap publish_to: "none" -version: 1.6.3+29 # The thing after the + is the version code, incremented with each release +version: 1.7.0+30 # The thing after the + is the version code, incremented with each release environment: sdk: ">=3.5.0 <4.0.0" # oauth2_client 4.x needs Dart 3.5+