diff --git a/lib/pages/map_survey/presentations/views/map_survey_view.dart b/lib/pages/map_survey/presentations/views/map_survey_view.dart index 6da7d54..ed42afb 100644 --- a/lib/pages/map_survey/presentations/views/map_survey_view.dart +++ b/lib/pages/map_survey/presentations/views/map_survey_view.dart @@ -86,7 +86,8 @@ class MapSurveyView extends GetView { const ImportedLayerOverlay(), // Track polyline Obx(() { - final inTrackMode = controller.mode.value == MapSurveyMode.track; + final inTrackMode = controller.mode.value == MapSurveyMode.track || + controller.mode.value == MapSurveyMode.fieldWalk; if (!inTrackMode) return const SizedBox.shrink(); final ids = TrackingController.to.overlayTrackIds; if (ids.isEmpty) return const SizedBox.shrink(); diff --git a/lib/pages/tracking/presentation/controllers/tracking_controller.dart b/lib/pages/tracking/presentation/controllers/tracking_controller.dart index 9471c44..2a28849 100644 --- a/lib/pages/tracking/presentation/controllers/tracking_controller.dart +++ b/lib/pages/tracking/presentation/controllers/tracking_controller.dart @@ -88,6 +88,13 @@ class TrackingController extends GetxController { final _db = TrackDatabase.instance; final _exporter = GpxExporter(); + // Timer + DateTime? _lastPositionTime; + Timer? _watchdogTimer; + final gpsSignalLost = false.obs; + + static const _gpsTimeoutSec = 10; + // ── Inicializálás ────────────────────────────────────────────────────────── @override @@ -191,6 +198,7 @@ class TrackingController extends GetxController { isRecording.value = true; isPaused.value = false; + _startWatchdog(); } void pauseRecording() { @@ -245,6 +253,10 @@ class TrackingController extends GetxController { isPaused.value = false; await loadSavedTracks(); + + _watchdogTimer?.cancel(); + _watchdogTimer = null; + gpsSignalLost.value = false; } Future loadSavedTracks() async { @@ -281,11 +293,24 @@ class TrackingController extends GetxController { Future _onPosition(SourcePosition pos) async { try { if (isPaused.value) return; + _lastPositionTime = DateTime.now(); + gpsSignalLost.value = false; final sw = Stopwatch()..start(); final trackId = currentTrack.value?.id; if (trackId == null) return; + final point = TrackPoint( + trackId: trackId, + latitude: pos.latitude, + longitude: pos.longitude, + altitude: pos.altitude, + accuracy: pos.accuracy, + speed: pos.speed, + heading: pos.heading, + timestamp: pos.timestamp, + ); + // Távolság a legutóbbi ponttól double segmentDist = 0; if (_lastPoint != null) { @@ -296,7 +321,14 @@ class TrackingController extends GetxController { pos.longitude, ); // Szűrés: ugrásszerű változás (pl. GPS lock elvesztése) ignorálása - if (segmentDist > 100) return; + if (segmentDist > 100) { + AppLogger.w( + '_onPosition', + 'GPS ugrás kiszűrve: ${segmentDist.toStringAsFixed(0)}m ' + '(pts: ${livePoints.length})'); + _lastPoint = point; // reset — következő pont ettől mér + return; + } } _accumulatedDistance += segmentDist; @@ -306,16 +338,6 @@ class TrackingController extends GetxController { currentSpeedKmh.value = (pos.speed ?? 0) * 3.6; // Pont mentése - final point = TrackPoint( - trackId: trackId, - latitude: pos.latitude, - longitude: pos.longitude, - altitude: pos.altitude, - accuracy: pos.accuracy, - speed: pos.speed, - heading: pos.heading, - timestamp: pos.timestamp, - ); await _db.addPoint(point, _accumulatedDistance); sw.stop(); @@ -398,4 +420,61 @@ class TrackingController extends GetxController { _trackCoords[trackId] = pts.map((p) => LatLng(p.lat, p.lon)).toList(); overlayTrackIds.refresh(); // térkép frissítés } + + void _startWatchdog() { + _watchdogTimer = Timer.periodic( + const Duration(seconds: 5), + (_) => _checkGpsTimeout(), + ); + } + + void _checkGpsTimeout() { + if (!isRecording.value || isPaused.value) return; + final last = _lastPositionTime; + if (last == null) return; + + final elapsedSec = DateTime.now().difference(last).inSeconds; + if (elapsedSec < _gpsTimeoutSec) return; + + if (!gpsSignalLost.value) { + gpsSignalLost.value = true; + + AppLogger.w( + 'watchdog', + 'GPS jel elveszett: ${elapsedSec}s óta nincs pozíció ' + '(pts: ${livePoints.length}, ' + 'táv: ${_formatDistance(_accumulatedDistance)})'); + + AppLogger.w( + 'gps_signal_lost', + 'elapsed_sec: ${elapsedSec}' + 'point_count: ${livePoints.length}' + 'distance_m: ${_accumulatedDistance.round()}'); + + // Foreground notification frissítése + FlutterForegroundTask.updateService( + notificationTitle: '⚠ GPS jel elveszett', + notificationText: 'Track szünetel — folytatódik ha visszajön a jel', + ); + + // Snackbar ha előtérben van az app + if (!isInBackground.value) { + Get.snackbar( + 'GPS jel elveszett', + 'Valószínűleg alagút vagy lefedettség hiány.\n' + 'A rögzítés automatikusan folytatódik.', + duration: const Duration(seconds: 6), + backgroundColor: Colors.orange.shade700, + colorText: Colors.white, + icon: const Icon(Icons.gps_off, color: Colors.white), + snackPosition: SnackPosition.TOP, + ); + } + } + + // Folyamatosan logol amíg nincs jel (percenként egyszer) + if (elapsedSec % 60 == 0) { + AppLogger.w('watchdog', 'GPS még mindig hiányzik: ${elapsedSec}s'); + } + } } diff --git a/lib/services/app_logger.dart b/lib/services/app_logger.dart index 510873a..6861e27 100644 --- a/lib/services/app_logger.dart +++ b/lib/services/app_logger.dart @@ -25,7 +25,7 @@ class AppLogger extends GetxService { // ── Konfiguráció ────────────────────────────────────────────────── /// Csak fejlesztési módban logol (release build-ben kikapcsol) - static const bool _enableInRelease = false; + static const bool _enableInRelease = true; /// Max log fájl méret MB-ban — felette rotál static const int _maxSizeMb = 5; diff --git a/lib/services/firebase_logger.dart b/lib/services/firebase_logger.dart index f4ff182..b8e6ac4 100644 --- a/lib/services/firebase_logger.dart +++ b/lib/services/firebase_logger.dart @@ -36,7 +36,8 @@ class FirebaseLogger extends GetxService { _analytics = FirebaseAnalytics.instance; // Crashlytics engedélyezése — release-ben mindig, debug-ban opcionális - await _crashlytics.setCrashlyticsCollectionEnabled(!kDebugMode); + //await _crashlytics.setCrashlyticsCollectionEnabled(!kDebugMode); + await _crashlytics.setCrashlyticsCollectionEnabled(true); // Eszközazonosító beállítása ha már elérhető _setDeviceInfo(); diff --git a/lib/widgets/app_drawer.dart b/lib/widgets/app_drawer.dart index e7af60e..1a9170f 100644 --- a/lib/widgets/app_drawer.dart +++ b/lib/widgets/app_drawer.dart @@ -1,3 +1,4 @@ +import 'package:firebase_crashlytics/firebase_crashlytics.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:package_info_plus/package_info_plus.dart'; @@ -154,9 +155,17 @@ class AppDrawer extends StatelessWidget { ListTile( leading: const Icon(Icons.volume_up_outlined), title: const Text('Hang és rezgés'), - onTap: () { - Get.back(); + onTap: () async { + // Get.back(); // Get.to(() => const FeedbackSettingsView()); + await FirebaseCrashlytics.instance.recordError( + Exception('Teszt hiba - breadcrumb ellenőrzés'), + StackTrace.current, + reason: 'Manuális teszt', + fatal: false); + await FirebaseCrashlytics.instance.sendUnsentReports(); + + Get.back(); }, ), diff --git a/lib/widgets/tracking/track_info_card.dart b/lib/widgets/tracking/track_info_card.dart index da90331..0971d45 100644 --- a/lib/widgets/tracking/track_info_card.dart +++ b/lib/widgets/tracking/track_info_card.dart @@ -70,6 +70,16 @@ class _RecordingContent extends StatelessWidget { letterSpacing: 0.5, ), ), + const SizedBox(width: 5), + Obx(() { + if (!ctrl.gpsSignalLost.value) return const SizedBox.shrink(); + return Row(children: [ + Icon(Icons.gps_off, size: 12, color: Colors.orange), + const SizedBox(width: 4), + Text('GPS-ejl elveszett', + style: TextStyle(color: Colors.orange, fontSize: 10)) + ]); + }), const Spacer(), // Kártya bezárása (csak megkisebbíti, nem állítja le) GestureDetector(