import 'dart:async'; import 'package:geolocator/geolocator.dart'; import 'location_source.dart'; /// Telefon beépített GPS-ét használó helymeghatározási forrás. /// /// Android háttér-működéshez a [flutter_foreground_task] kezeli /// az előtér-szolgáltatást (notification), ez az osztály csak /// a Geolocator streamet konfigurálja. class PhoneGpsSource implements LocationSource { @override String get displayName => 'Telefon GPS'; StreamController? _controller; StreamSubscription? _positionSub; /// Frissítési intervallum ms-ban. final int intervalMs; /// Minimális elmozdulás méterben új pont előtt. final double distanceFilter; PhoneGpsSource({ this.intervalMs = 1000, this.distanceFilter = 1.0, }); @override bool get isAvailable => _controller != null && !(_controller!.isClosed); @override Stream get positionStream { _controller = StreamController.broadcast(); _startListening(); return _controller!.stream; } Future _startListening() async { // Engedélyek ellenőrzése LocationPermission permission = await Geolocator.checkPermission(); if (permission == LocationPermission.denied) { permission = await Geolocator.requestPermission(); } if (permission == LocationPermission.deniedForever || permission == LocationPermission.denied) { _controller?.addError( Exception('Helymeghatározási engedély megtagadva. ' 'Kérjük, engedélyezze a beállításokban.'), ); return; } final settings = AndroidSettings( accuracy: LocationAccuracy.high, distanceFilter: distanceFilter.toInt(), intervalDuration: Duration(milliseconds: intervalMs), // Háttér-helymeghatározáshoz szükséges — a foreground_task // 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', enableWakeLock: true, ), ); _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), ); } @override Future dispose() async { await _positionSub?.cancel(); await _controller?.close(); _controller = null; } }