diff --git a/.claude/settings.local.json b/.claude/settings.local.json index fd2b7ca..84ca3c4 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -47,7 +47,8 @@ "Bash(flutter pub add:*)", "Bash(flutter run)", "Bash(echo:*)", - "Bash(pkill:*)" + "Bash(pkill:*)", + "Bash(git restore:*)" ], "deny": [], "ask": [] diff --git a/CLAUDE.md b/CLAUDE.md index 7d6cac6..b6169a0 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -551,21 +551,17 @@ org.gradle.jvmargs=-Xmx4096m ## Services Reference ### LocationTrackingService (Singleton) -**Purpose**: GPS tracking + intelligent mesh location broadcasting +**Purpose**: GPS tracking for map display and trail recording **Callbacks**: `onPositionUpdate`, `onError`, `onBroadcastSent`, `onTrackingStateChanged` -**Thresholds**: -- Min distance: 5.0m -- Max distance: 100.0m -- Min time: 30s +**Broadcasting**: +- **Automatic broadcasting DISABLED** - No automatic position adverts to mesh network +- Manual broadcasting available via `broadcastLocationNow()` method +- User must explicitly use the advert button to broadcast location +- GPS tracking continues for map display, currentPosition tracking, and trail recording -**Logic**: -- First update → broadcast immediately -- ≥100m moved → broadcast immediately -- ≥5m + ≥30s → broadcast - -**File**: `lib/services/location_tracking_service.dart` (501 lines) +**File**: `lib/services/location_tracking_service.dart` ### MapMarkerService (Singleton) **Purpose**: Map marker generation + geodesic calculations diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 9e44271..82287e7 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1,4 +1,6 @@ PODS: + - device_info_plus (0.0.1): + - Flutter - DKImagePickerController/Core (4.3.9): - DKImagePickerController/ImageDataManager - DKImagePickerController/Resource @@ -34,55 +36,131 @@ PODS: - DKImagePickerController/PhotoGallery - Flutter - Flutter (1.0.0) + - flutter_background_service_ios (0.0.3): + - Flutter + - flutter_blue_plus_darwin (0.0.2): + - Flutter + - FlutterMacOS + - flutter_compass (0.0.1): + - Flutter + - flutter_local_notifications (0.0.1): + - Flutter + - geolocator_apple (1.2.0): + - Flutter + - FlutterMacOS + - nsd_ios (0.0.1): + - Flutter + - ObjectBox (4.4.1) + - objectbox_flutter_libs (0.0.1): + - Flutter + - ObjectBox (= 4.4.1) + - package_info_plus (0.4.5): + - Flutter - path_provider_foundation (0.0.1): - Flutter - FlutterMacOS + - permission_handler_apple (9.3.0): + - Flutter - SDWebImage (5.21.3): - SDWebImage/Core (= 5.21.3) - SDWebImage/Core (5.21.3) + - share_plus (0.0.1): + - Flutter - shared_preferences_foundation (0.0.1): - Flutter - FlutterMacOS - SwiftyGif (5.4.5) - url_launcher_ios (0.0.1): - Flutter + - vibration (3.0.0): + - Flutter DEPENDENCIES: + - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`) - file_picker (from `.symlinks/plugins/file_picker/ios`) - Flutter (from `Flutter`) + - flutter_background_service_ios (from `.symlinks/plugins/flutter_background_service_ios/ios`) + - flutter_blue_plus_darwin (from `.symlinks/plugins/flutter_blue_plus_darwin/darwin`) + - flutter_compass (from `.symlinks/plugins/flutter_compass/ios`) + - flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`) + - geolocator_apple (from `.symlinks/plugins/geolocator_apple/darwin`) + - nsd_ios (from `.symlinks/plugins/nsd_ios/ios`) + - objectbox_flutter_libs (from `.symlinks/plugins/objectbox_flutter_libs/ios`) + - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) + - permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`) + - share_plus (from `.symlinks/plugins/share_plus/ios`) - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) + - vibration (from `.symlinks/plugins/vibration/ios`) SPEC REPOS: trunk: - DKImagePickerController - DKPhotoGallery + - ObjectBox - SDWebImage - SwiftyGif EXTERNAL SOURCES: + device_info_plus: + :path: ".symlinks/plugins/device_info_plus/ios" file_picker: :path: ".symlinks/plugins/file_picker/ios" Flutter: :path: Flutter + flutter_background_service_ios: + :path: ".symlinks/plugins/flutter_background_service_ios/ios" + flutter_blue_plus_darwin: + :path: ".symlinks/plugins/flutter_blue_plus_darwin/darwin" + flutter_compass: + :path: ".symlinks/plugins/flutter_compass/ios" + flutter_local_notifications: + :path: ".symlinks/plugins/flutter_local_notifications/ios" + geolocator_apple: + :path: ".symlinks/plugins/geolocator_apple/darwin" + nsd_ios: + :path: ".symlinks/plugins/nsd_ios/ios" + objectbox_flutter_libs: + :path: ".symlinks/plugins/objectbox_flutter_libs/ios" + package_info_plus: + :path: ".symlinks/plugins/package_info_plus/ios" path_provider_foundation: :path: ".symlinks/plugins/path_provider_foundation/darwin" + permission_handler_apple: + :path: ".symlinks/plugins/permission_handler_apple/ios" + share_plus: + :path: ".symlinks/plugins/share_plus/ios" shared_preferences_foundation: :path: ".symlinks/plugins/shared_preferences_foundation/darwin" url_launcher_ios: :path: ".symlinks/plugins/url_launcher_ios/ios" + vibration: + :path: ".symlinks/plugins/vibration/ios" SPEC CHECKSUMS: + device_info_plus: 21fcca2080fbcd348be798aa36c3e5ed849eefbe DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60 file_picker: a0560bc09d61de87f12d246fc47d2119e6ef37be Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467 + flutter_background_service_ios: 00d31bdff7b4bfe06d32375df358abe0329cf87e + flutter_blue_plus_darwin: 20a08bfeaa0f7804d524858d3d8744bcc1b6dbc3 + flutter_compass: b236ab69b61545cce89fd58527f401a7587d5cc1 + flutter_local_notifications: a5a732f069baa862e728d839dd2ebb904737effb + geolocator_apple: ab36aa0e8b7d7a2d7639b3b4e48308394e8cef5e + nsd_ios: 596ad79109ddd3e52d665f650f36428049e3653e + ObjectBox: 7da4aceb5013d041bfafdbc6d744a26918b09757 + objectbox_flutter_libs: 09b1dec1b4cd27bf1a5f9bae7ccaa7e43588bf31 + package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499 path_provider_foundation: bb55f6dbba17d0dccd6737fe6f7f34fbd0376880 + permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d SDWebImage: 16309af6d214ba3f77a7c6f6fdda888cb313a50a + share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4 url_launcher_ios: 7a95fa5b60cc718a708b8f2966718e93db0cef1b + vibration: 69774ad57825b11c951ee4c46155f455d7a592ce PODFILE CHECKSUM: 3c63482e143d1b91d2d2560aee9fb04ecc74ac7e diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index bec1b68..9a08f5b 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -198,6 +198,7 @@ 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 0F5356670725D838348C6698 /* [CP] Embed Pods Frameworks */, + 5C71E5FAEF51EAE4BBF3727A /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -324,6 +325,23 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; + 5C71E5FAEF51EAE4BBF3727A /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; diff --git a/lib/screens/settings_screen.dart b/lib/screens/settings_screen.dart index 086d25a..40dadbf 100644 --- a/lib/screens/settings_screen.dart +++ b/lib/screens/settings_screen.dart @@ -627,42 +627,6 @@ class _SettingsScreenState extends State { ), const Divider(), - // Location Settings Section - _buildSectionHeader( - AppLocalizations.of(context)!.locationBroadcasting, - ), - - // Automatic tracking settings - SwitchListTile( - secondary: const Icon(Icons.location_on), - title: Text(AppLocalizations.of(context)!.autoLocationTracking), - subtitle: Text( - AppLocalizations.of(context)!.automaticallyBroadcastPosition, - ), - value: _locationService.isTracking, - onChanged: (value) { - if (value) { - _startBackgroundTracking(); - } else { - _stopBackgroundTracking(); - } - }, - ), - - if (_locationService.isTracking) ...[ - ListTile( - leading: const Icon(Icons.tune), - title: Text(AppLocalizations.of(context)!.configureTracking), - subtitle: Text( - AppLocalizations.of(context)!.distanceAndTimeThresholds, - ), - trailing: const Icon(Icons.chevron_right), - onTap: () => _showTrackingConfigDialog(), - ), - ], - - const Divider(), - // About Section _buildSectionHeader(AppLocalizations.of(context)!.about), ListTile( diff --git a/lib/services/location_tracking_service.dart b/lib/services/location_tracking_service.dart index 5450c6e..727cce4 100644 --- a/lib/services/location_tracking_service.dart +++ b/lib/services/location_tracking_service.dart @@ -420,52 +420,11 @@ class LocationTrackingService { } /// Check if position should be broadcast based on distance and time thresholds + /// DISABLED: Automatic broadcasting removed - use advert button for manual broadcasts void _checkAndBroadcast(Position position) { - // If never broadcast before, do it now - if (_lastBroadcastPosition == null || _lastBroadcastTime == null) { - _broadcastPosition(position); - return; - } - - // Calculate time since last broadcast - final timeSinceLastBroadcast = DateTime.now().difference( - _lastBroadcastTime!, - ); - final secondsSinceLastBroadcast = timeSinceLastBroadcast.inSeconds; - - // Calculate distance from last broadcast position - final distanceFromLastBroadcast = Geolocator.distanceBetween( - _lastBroadcastPosition!.latitude, - _lastBroadcastPosition!.longitude, - position.latitude, - position.longitude, - ); - - debugPrint( - ' Distance from last broadcast: ${distanceFromLastBroadcast.toStringAsFixed(1)}m', - ); - debugPrint(' Time since last broadcast: ${secondsSinceLastBroadcast}s'); - - // Broadcast if moved beyond max distance threshold - if (distanceFromLastBroadcast >= maxDistanceMeters) { - debugPrint( - ' 📤 Triggering broadcast: exceeded max distance (${maxDistanceMeters}m)', - ); - _broadcastPosition(position); - return; - } - - // Broadcast if minimum time interval passed AND moved beyond min distance - if (secondsSinceLastBroadcast >= minTimeIntervalSeconds && - distanceFromLastBroadcast >= minDistanceMeters) { - debugPrint( - ' 📤 Triggering broadcast: exceeded min time (${minTimeIntervalSeconds}s) and min distance (${minDistanceMeters}m)', - ); - _broadcastPosition(position); - return; - } - - debugPrint(' ⏸️ Not broadcasting: thresholds not met'); + // Automatic broadcasting disabled + // Use the manual advert button instead + debugPrint(' ⏸️ [LocationTracking] Automatic broadcasting disabled (use advert button)'); } // ============================================================================