From d2605b00da0ebb7a3e3cdd55242f3324fede2b68 Mon Sep 17 00:00:00 2001 From: "torok.istvan" Date: Sat, 11 Jul 2026 18:28:01 +0200 Subject: [PATCH] =?UTF-8?q?Track=20r=C3=B6gz=C3=ADt=C3=A9s=20jav=C3=ADt?= =?UTF-8?q?=C3=A1sa,=20t=C3=A1vols=C3=A1g=20limit=20id=C5=91=20alap=C3=BA?= =?UTF-8?q?=20m=C3=B3dos=C3=ADt=C3=A1sa,=20Fix=20#9=20@30m?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controllers/tracking_controller.dart | 30 ++++++-- lib/services/phone_gps_source.dart | 73 ++++++++++++++----- 2 files changed, 80 insertions(+), 23 deletions(-) diff --git a/lib/pages/tracking/presentation/controllers/tracking_controller.dart b/lib/pages/tracking/presentation/controllers/tracking_controller.dart index 22cf4ff..1562514 100644 --- a/lib/pages/tracking/presentation/controllers/tracking_controller.dart +++ b/lib/pages/tracking/presentation/controllers/tracking_controller.dart @@ -329,17 +329,35 @@ class TrackingController extends GetxController { pos.latitude, pos.longitude, ); - // Szűrés: ugrásszerű változás (pl. GPS lock elvesztése) ignorálása - if (segmentDist > 100) { + + // Szűrés: valóban LEHETETLEN ugrás kiszűrése (pl. GPS lock- + // vesztés utáni téves fix) — az ELTELT IDŐT is figyelembe véve. + // A korábbi, sima 100 m-es távolság-küszöb gyorsabb haladásnál + // (pl. földúton autóval) egy rövid, teljesen normál jel- + // kimaradás után érkező, VALÓS pontokat is kiszűrt, mert + // néhány másodperc alatt egy autó simán megtesz 100+ métert. + final elapsedSec = + point.timestamp.difference(_lastPoint!.timestamp).inMilliseconds / + 1000.0; + final impliedSpeedMs = + elapsedSec > 0 ? segmentDist / elapsedSec : double.infinity; + + // ~50 m/s = 180 km/h — terepen, földúton ennél gyorsabban senki + // nem halad, tehát ami ennél nagyobb sebességet implikálna, az + // GPS-hiba, nem valódi mozgás. + const maxPlausibleSpeedMs = 50.0; + + if (impliedSpeedMs > maxPlausibleSpeedMs) { 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 + 'GPS ugrás kiszűrve: ${segmentDist.toStringAsFixed(0)}m / ' + '${elapsedSec.toStringAsFixed(1)}s ' + '(${(impliedSpeedMs * 3.6).toStringAsFixed(0)} km/h, ' + 'pts: ${livePoints.length})'); + _lastPoint = point; return; } } - _accumulatedDistance += segmentDist; sessionDistance.value = _accumulatedDistance; diff --git a/lib/services/phone_gps_source.dart b/lib/services/phone_gps_source.dart index 2126fa9..0c63e0d 100644 --- a/lib/services/phone_gps_source.dart +++ b/lib/services/phone_gps_source.dart @@ -20,6 +20,12 @@ class PhoneGpsSource implements LocationSource { /// Minimális elmozdulás méterben új pont előtt. final double distanceFilter; + /// Egymást követő sikertelen újraindítási kísérletek száma — véd a + /// végtelen, szoros hiba-ciklus ellen, ha valami tartósan elromlott. + int _retryCount = 0; + static const _maxRetries = 5; + Timer? _retryTimer; + PhoneGpsSource({ this.intervalMs = 1000, this.distanceFilter = 1.0, @@ -59,33 +65,66 @@ class PhoneGpsSource implements LocationSource { // notification biztosítja a jogszerű háttér-használatot. foregroundNotificationConfig: const ForegroundNotificationConfig( notificationText: 'Track rögzítése folyamatban', - notificationTitle: 'Terepi Segéd – Nyomvonal', + notificationTitle: 'Terepi Segéd - Nyomvonal', enableWakeLock: true, ), ); + await _positionSub?.cancel(); + _positionSub = Geolocator.getPositionStream( locationSettings: settings, - ).listen( - (Position pos) { - _controller?.add(SourcePosition( - latitude: pos.latitude, - longitude: pos.longitude, - altitude: pos.altitude, - accuracy: pos.accuracy, - verticalAccuracy: pos.altitudeAccuracy, - speed: pos.speed, - heading: pos.heading, - timestamp: pos.timestamp, - source: displayName, - )); - }, - onError: (e) => _controller?.addError(e), - ); + ).listen((Position pos) { + _retryCount = 0; + _controller?.add(SourcePosition( + latitude: pos.latitude, + longitude: pos.longitude, + altitude: pos.altitude, + accuracy: pos.accuracy, + verticalAccuracy: pos.altitudeAccuracy, + speed: pos.speed, + heading: pos.heading, + timestamp: pos.timestamp, + source: displayName, + )); + }, + onError: (e) => _handleStreamError, + onDone: () => + _handleStreamError(Exception('A GPS-stream váratlanul lezárult.'))); + } + + /// A Geolocator stream NEM öngyógyuló: ha egyszer hibát dob (terepen, + /// zötykölődő telefonnal ez elő szokott fordulni), magától többé NEM + /// küld pozíciót. Ezért itt — a korábbi "csak továbbadjuk és feladjuk" + /// helyett — manuálisan újraindítjuk a mögöttes streamet. Végleges, + /// nem-helyreállítható hibáknál (jogosultság/szolgáltatás kikapcsolva) + /// viszont TOVÁBBADJUK, hogy a TrackingController korrekten leállítsa + /// a rögzítést, ahogy eddig is. + void _handleStreamError(Object e) { + if (e is LocationServiceDisabledException || + e is PermissionDeniedException) { + _controller?.addError(e); + return; + } + + _retryCount++; + if (_retryCount > _maxRetries) { + // Tartósan hibás állapot — ezt már valóban jelezni kell. + _controller?.addError(e); + return; + } + + // Rövid várakozás, majd friss stream indítása. A _controller + // (amit a TrackingController figyel) változatlan marad — onnan + // nézve ez csak egy pillanatnyi szünet a pozíciókban, nem egy + // végleges leállás. + _retryTimer?.cancel(); + _retryTimer = Timer(const Duration(seconds: 1), _startListening); } @override Future dispose() async { + _retryTimer?.cancel(); await _positionSub?.cancel(); await _controller?.close(); _controller = null;