diff --git a/assets/changelog.json b/assets/changelog.json index 0103faa..7a5a455 100644 --- a/assets/changelog.json +++ b/assets/changelog.json @@ -1,5 +1,5 @@ { - "1.2.6": { + "1.2.7": { "content": "• NEW: Compass indicator shows map orientation and enables north-lock mode\n• Smart area caching: Loads 3x larger areas and refreshes data every 60 seconds for much faster browsing\n• Enhanced tile loading: Increased retry attempts with faster delays - tiles load much more reliably\n• Better network status: Simplified loading indicator logic\n• Instant node display: Surveillance devices now appear immediately when data finishes loading\n• Node limit alerts: Get notified when some nodes are not drawn" }, "1.2.4": { diff --git a/lib/app_state.dart b/lib/app_state.dart index ba916e0..fea43c9 100644 --- a/lib/app_state.dart +++ b/lib/app_state.dart @@ -130,7 +130,7 @@ class AppState extends ChangeNotifier { int get maxCameras => _settingsState.maxCameras; UploadMode get uploadMode => _settingsState.uploadMode; FollowMeMode get followMeMode => _settingsState.followMeMode; - bool get northLockEnabled => _settingsState.northLockEnabled; + bool get proximityAlertsEnabled => _settingsState.proximityAlertsEnabled; int get proximityAlertDistance => _settingsState.proximityAlertDistance; bool get networkStatusIndicatorEnabled => _settingsState.networkStatusIndicatorEnabled; @@ -411,10 +411,6 @@ class AppState extends ChangeNotifier { await _settingsState.setFollowMeMode(mode); } - Future setNorthLockEnabled(bool enabled) async { - await _settingsState.setNorthLockEnabled(enabled); - } - /// Set proximity alerts enabled/disabled Future setProximityAlertsEnabled(bool enabled) async { await _settingsState.setProximityAlertsEnabled(enabled); diff --git a/lib/dev_config.dart b/lib/dev_config.dart index 7decabe..2d57bfc 100644 --- a/lib/dev_config.dart +++ b/lib/dev_config.dart @@ -69,8 +69,7 @@ const double kPreFetchAreaExpansionMultiplier = 3.0; // Expand visible bounds by const int kPreFetchZoomLevel = 10; // Always pre-fetch at this zoom level for consistent area sizes const int kMaxPreFetchSplitDepth = 3; // Maximum recursive splits when hitting Overpass node limit -// North lock configuration -const double kNorthLockDisableThresholdDegrees = 10.0; // Rotation threshold to disable north lock (degrees) +// Data refresh configuration const int kDataRefreshIntervalSeconds = 60; // Refresh cached data after this many seconds // Follow-me mode smooth transitions diff --git a/lib/state/settings_state.dart b/lib/state/settings_state.dart index cbf1eec..b87a793 100644 --- a/lib/state/settings_state.dart +++ b/lib/state/settings_state.dart @@ -24,7 +24,6 @@ class SettingsState extends ChangeNotifier { static const String _selectedTileTypePrefsKey = 'selected_tile_type'; static const String _legacyTestModePrefsKey = 'test_mode'; static const String _followMeModePrefsKey = 'follow_me_mode'; - static const String _northLockEnabledPrefsKey = 'north_lock_enabled'; static const String _proximityAlertsEnabledPrefsKey = 'proximity_alerts_enabled'; static const String _proximityAlertDistancePrefsKey = 'proximity_alert_distance'; static const String _networkStatusIndicatorEnabledPrefsKey = 'network_status_indicator_enabled'; @@ -34,7 +33,6 @@ class SettingsState extends ChangeNotifier { int _maxCameras = 250; UploadMode _uploadMode = kEnableDevelopmentModes ? UploadMode.simulate : UploadMode.production; FollowMeMode _followMeMode = FollowMeMode.follow; - bool _northLockEnabled = false; bool _proximityAlertsEnabled = false; int _proximityAlertDistance = kProximityAlertDefaultDistance; bool _networkStatusIndicatorEnabled = false; @@ -47,7 +45,6 @@ class SettingsState extends ChangeNotifier { int get maxCameras => _maxCameras; UploadMode get uploadMode => _uploadMode; FollowMeMode get followMeMode => _followMeMode; - bool get northLockEnabled => _northLockEnabled; bool get proximityAlertsEnabled => _proximityAlertsEnabled; int get proximityAlertDistance => _proximityAlertDistance; bool get networkStatusIndicatorEnabled => _networkStatusIndicatorEnabled; @@ -100,9 +97,6 @@ class SettingsState extends ChangeNotifier { _maxCameras = prefs.getInt(_maxCamerasPrefsKey) ?? 250; } - // Load north lock enabled setting - _northLockEnabled = prefs.getBool(_northLockEnabledPrefsKey) ?? false; - // Load proximity alerts settings _proximityAlertsEnabled = prefs.getBool(_proximityAlertsEnabledPrefsKey) ?? false; _proximityAlertDistance = prefs.getInt(_proximityAlertDistancePrefsKey) ?? kProximityAlertDefaultDistance; @@ -298,29 +292,12 @@ class SettingsState extends ChangeNotifier { if (_followMeMode != mode) { _followMeMode = mode; - // Disable north lock when switching to rotating mode (incompatible) - if (mode == FollowMeMode.rotating && _northLockEnabled) { - _northLockEnabled = false; - final prefs = await SharedPreferences.getInstance(); - await prefs.setBool(_northLockEnabledPrefsKey, false); - } - final prefs = await SharedPreferences.getInstance(); await prefs.setInt(_followMeModePrefsKey, mode.index); notifyListeners(); } } - /// Set north lock enabled/disabled - Future setNorthLockEnabled(bool enabled) async { - if (_northLockEnabled != enabled) { - _northLockEnabled = enabled; - final prefs = await SharedPreferences.getInstance(); - await prefs.setBool(_northLockEnabledPrefsKey, enabled); - notifyListeners(); - } - } - /// Set proximity alerts enabled/disabled Future setProximityAlertsEnabled(bool enabled) async { if (_proximityAlertsEnabled != enabled) { diff --git a/lib/widgets/compass_indicator.dart b/lib/widgets/compass_indicator.dart index 81e0074..bee5283 100644 --- a/lib/widgets/compass_indicator.dart +++ b/lib/widgets/compass_indicator.dart @@ -6,7 +6,7 @@ import 'package:provider/provider.dart'; import '../app_state.dart'; -/// A compass indicator widget that shows the current map rotation and allows tapping to enable/disable north lock. +/// A compass indicator widget that shows the current map rotation and allows tapping to animate to north. /// The compass appears in the top-right corner of the map and is disabled (non-interactive) when in follow+rotate mode. class CompassIndicator extends StatefulWidget { final AnimatedMapController mapController; @@ -21,8 +21,6 @@ class CompassIndicator extends StatefulWidget { } class _CompassIndicatorState extends State { - double _lastRotation = 0.0; - @override Widget build(BuildContext context) { return Consumer( @@ -40,38 +38,23 @@ class _CompassIndicatorState extends State { // Check if we're in follow+rotate mode (compass should be disabled) final isDisabled = appState.followMeMode == FollowMeMode.rotating; - final northLockEnabled = appState.northLockEnabled; - - // Force rebuild when north lock changes by comparing rotation - if (northLockEnabled && rotationDegrees != _lastRotation) { - WidgetsBinding.instance.addPostFrameCallback((_) { - if (mounted) setState(() {}); - }); - } - _lastRotation = rotationDegrees; return Positioned( top: (appState.uploadMode == UploadMode.sandbox || appState.uploadMode == UploadMode.simulate) ? 60 : 18, right: 16, child: GestureDetector( onTap: isDisabled ? null : () { - // Toggle north lock (but not when in follow+rotate mode) - final newNorthLockEnabled = !northLockEnabled; - appState.setNorthLockEnabled(newNorthLockEnabled); - - // If enabling north lock, animate to north-up orientation - if (newNorthLockEnabled) { - try { - widget.mapController.animateTo( - dest: widget.mapController.mapController.camera.center, - zoom: widget.mapController.mapController.camera.zoom, - rotation: 0.0, - duration: const Duration(milliseconds: 500), - curve: Curves.easeOut, - ); - } catch (_) { - // Controller not ready, ignore - } + // Animate to north-up orientation + try { + widget.mapController.animateTo( + dest: widget.mapController.mapController.camera.center, + zoom: widget.mapController.mapController.camera.zoom, + rotation: 0.0, + duration: const Duration(milliseconds: 500), + curve: Curves.easeOut, + ); + } catch (_) { + // Controller not ready, ignore } }, child: Container( @@ -85,10 +68,8 @@ class _CompassIndicatorState extends State { border: Border.all( color: isDisabled ? Colors.grey.shade400 - : (northLockEnabled - ? Theme.of(context).colorScheme.primary - : Colors.grey.shade300), - width: northLockEnabled ? 3.0 : 2.0, + : Colors.grey.shade300, + width: 2.0, ), boxShadow: [ BoxShadow( @@ -128,9 +109,7 @@ class _CompassIndicatorState extends State { size: 20, color: isDisabled ? Colors.grey.shade600 - : (northLockEnabled - ? Colors.red.shade700 - : Colors.red.shade600), + : Colors.red.shade600, ), ), // Small 'N' label @@ -141,9 +120,7 @@ class _CompassIndicatorState extends State { fontWeight: FontWeight.bold, color: isDisabled ? Colors.grey.shade600 - : (northLockEnabled - ? Colors.red.shade700 - : Colors.red.shade600), + : Colors.red.shade600, ), ), ], diff --git a/lib/widgets/map/gps_controller.dart b/lib/widgets/map/gps_controller.dart index 8017a99..2bec741 100644 --- a/lib/widgets/map/gps_controller.dart +++ b/lib/widgets/map/gps_controller.dart @@ -89,8 +89,7 @@ class GpsController { int proximityAlertDistance = 200, List nearbyNodes = const [], List enabledProfiles = const [], - // Optional parameter for north lock functionality - bool northLockEnabled = false, + }) { final latLng = LatLng(position.latitude, position.longitude); _currentLatLng = latLng; @@ -114,12 +113,11 @@ class GpsController { WidgetsBinding.instance.addPostFrameCallback((_) { try { if (followMeMode == FollowMeMode.follow) { - // Follow position only, keep current rotation (unless north lock is enabled) - final rotation = northLockEnabled ? 0.0 : controller.mapController.camera.rotation; + // Follow position only, keep current rotation controller.animateTo( dest: latLng, zoom: controller.mapController.camera.zoom, - rotation: rotation, + rotation: controller.mapController.camera.rotation, duration: kFollowMeAnimationDuration, curve: Curves.easeOut, ); @@ -157,7 +155,7 @@ class GpsController { required int Function() getProximityAlertDistance, required List Function() getNearbyNodes, required List Function() getEnabledProfiles, - required bool Function() getNorthLockEnabled, + }) async { final perm = await Geolocator.requestPermission(); if (perm == LocationPermission.denied || @@ -173,8 +171,6 @@ class GpsController { final proximityAlertDistance = getProximityAlertDistance(); final nearbyNodes = getNearbyNodes(); final enabledProfiles = getEnabledProfiles(); - final northLockEnabled = getNorthLockEnabled(); - processPositionUpdate( position: position, followMeMode: currentFollowMeMode, @@ -184,7 +180,6 @@ class GpsController { proximityAlertDistance: proximityAlertDistance, nearbyNodes: nearbyNodes, enabledProfiles: enabledProfiles, - northLockEnabled: northLockEnabled, ); }); } diff --git a/lib/widgets/map_view.dart b/lib/widgets/map_view.dart index bd0bf6e..25f53bd 100644 --- a/lib/widgets/map_view.dart +++ b/lib/widgets/map_view.dart @@ -74,8 +74,7 @@ class MapViewState extends State { // Track map center to clear queue on significant panning LatLng? _lastCenter; - // Track rotation to detect intentional vs accidental rotation - double? _lastRotation; + // State for proximity alert banner bool _showProximityBanner = false; @@ -181,17 +180,7 @@ class MapViewState extends State { } return []; }, - getNorthLockEnabled: () { - if (mounted) { - try { - return context.read().northLockEnabled; - } catch (e) { - debugPrint('[MapView] Could not read north lock enabled: $e'); - return false; - } - } - return false; - }, + ); // Fetch initial cameras @@ -561,41 +550,7 @@ class MapViewState extends State { if (gesture) { widget.onUserGesture(); - // Handle north lock: prevent rotation or disable lock if user rotates significantly - if (appState.northLockEnabled) { - try { - final currentRotation = pos.rotation; - if (_lastRotation != null) { - // Calculate rotation change since last gesture - final rotationChange = (currentRotation - _lastRotation!).abs(); - // If user tries to rotate significantly, disable north lock and allow it - if (rotationChange > kNorthLockDisableThresholdDegrees) { - appState.setNorthLockEnabled(false); - // Allow this rotation to proceed - } else { - // Small rotation or zoom gesture - force map back to north (0°) - if (currentRotation.abs() > 0.1) { // Only correct if actually rotated - WidgetsBinding.instance.addPostFrameCallback((_) { - try { - _controller.animateTo( - dest: pos.center, - zoom: pos.zoom, - rotation: 0.0, - duration: const Duration(milliseconds: 100), // Quick snap back - curve: Curves.easeOut, - ); - } catch (_) { - // Controller not ready, ignore - } - }); - } - } - } - _lastRotation = currentRotation; - } catch (_) { - // Controller not ready, ignore - } - } + } if (session != null) { diff --git a/pubspec.yaml b/pubspec.yaml index 80e9551..168b9b9 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.2.6+5 # The thing after the + is the version code, incremented with each release +version: 1.2.7+6 # 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+