From ce8b539be300a0385cf5623d8a95b23e82300145 Mon Sep 17 00:00:00 2001 From: "torok.istvan" Date: Sun, 24 May 2026 14:50:31 +0200 Subject: [PATCH] =?UTF-8?q?MapSurvey=20-=20refraktor=C3=A1l=C3=A1s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controllers/map_survey_controller.dart | 88 ++-- .../presentations/views/map_survey_view.dart | 26 +- .../shell/presentations/views/shell_view.dart | 2 + lib/services/ntrip_service.dart | 8 +- lib/widgets/shared_map_widgets.dart | 440 ++++++------------ 5 files changed, 209 insertions(+), 355 deletions(-) diff --git a/lib/pages/map_survey/presentations/controllers/map_survey_controller.dart b/lib/pages/map_survey/presentations/controllers/map_survey_controller.dart index 00fe3df..abb6cf1 100644 --- a/lib/pages/map_survey/presentations/controllers/map_survey_controller.dart +++ b/lib/pages/map_survey/presentations/controllers/map_survey_controller.dart @@ -64,8 +64,8 @@ class MapSurveyController extends GetxController { RxDouble get gpsLongitudeError => _gnss.longitudeError; RxDouble get gpsAltitudeError => _gnss.altitudeError; Rx get gpsDateTime => _gnss.gpsDateTime; - RxBool get gpsIsConnected => - (_gnss.connectionState.value == GnssConnectionState.connected).obs; + bool get gpsIsConnected => + _gnss.connectionState.value == GnssConnectionState.connected; // NTRIP állapot RxBool get ntripIsConnected => _ntrip.isConnected; @@ -85,6 +85,9 @@ class MapSurveyController extends GetxController { Rx eov = Eov(0, 0).obs; Rx eovHeight = (0.0 as double?).obs; + final eovY = 0.0.obs; + final eovX = 0.0.obs; + // DMS formátum RxInt latDegree = 0.obs; RxInt latMin = 0.obs; @@ -101,17 +104,18 @@ class MapSurveyController extends GetxController { RxBool isMapMoveToCenter = true.obs; RxBool mapIsInitialized = false.obs; - late final MapController mapController; + final MapController mapController = MapController(); - final currentLocationMarker = []; - final pointNotesMarker = []; - final pointsToMeasureMarker = []; - final pointsToMeasureLabel = []; - final pointsToMeasureDropDownMenuItem = >[]; + final currentLocationMarker = [].obs; + final pointNotesMarker = [].obs; + final pointsToMeasureMarker = [].obs; + final pointsToMeasureLabel = [].obs; + final pointsToMeasureDropDownMenuItem = >[].obs; // ── Pont adatok ─────────────────────────────────────────────────── - List pointsToMeasure = []; - List pointWithDescriptionList = []; + final RxList pointsToMeasure = [].obs; + final RxList pointWithDescriptionList = + [].obs; RxInt pointsToMeasureSelectedValue = (-1).obs; RxDouble distance = 0.0.obs; @@ -149,22 +153,17 @@ class MapSurveyController extends GetxController { // ───────────────────────────────────────────────────────────────── @override - void onInit() async { + void onInit() { super.onInit(); + _initAsync(); + } + Future _initAsync() async { prefs = await SharedPreferences.getInstance(); geoidGrid = await GeoidGrid.load('assets/Grids/geoid_eht2014.gtx'); - mapController = MapController(); - // ── NTRIP RTCM adat → GNSS vevő ────────────────────────────── - NtripService.to.onRtcmData = (data) { - GnssService.to.sendToReceiver(data); - }; - - // ── GnssService pozíció változás → EOV, marker, NTRIP GGA ──── - _gnssUpdateSub = _gnss.onDataUpdated.listen((_) { - _onGnssUpdate(); - }); + NtripService.to.onRtcmData = (data) => GnssService.to.sendToReceiver(data); + _gnssUpdateSub = _gnss.onDataUpdated.listen((_) => _onGnssUpdate()); // ── Supabase realtime ───────────────────────────────────────── _supaChannel = Supabase.instance.client @@ -193,18 +192,19 @@ class MapSurveyController extends GetxController { } @override - void onClose() async { - super.onClose(); - + void onClose() { _phoneLocationSub?.cancel(); _gnssUpdateSub?.cancel(); - await _supaChannel?.unsubscribe(); + final f = _supaChannel?.unsubscribe(); + if (f != null) unawaited(f); pointIdController.dispose(); pointDescriptionController.dispose(); gpsHeightController.dispose(); pointPrefixController.dispose(); pointPostfixController.dispose(); + + super.onClose(); } // ───────────────────────────────────────────────────────────────── @@ -220,7 +220,11 @@ class MapSurveyController extends GetxController { final sep = _gnss.geoidSeparation.value; // EOV konverzió - eov.value = ConvertCoordinate.ConvertWgsToEov(lat, lon); + final converted = ConvertCoordinate.ConvertWgsToEov(lat, lon); + eov.value = converted; + eovY.value = converted.Y.toDouble(); + eovX.value = converted.X.toDouble(); + eovHeight.value = geoidGrid.toEovHeight(lat, lon, alt, sep); // DMS @@ -254,10 +258,6 @@ class MapSurveyController extends GetxController { ); } - // ───────────────────────────────────────────────────────────────── - // Telefon GPS fallback - // ───────────────────────────────────────────────────────────────── - // ───────────────────────────────────────────────────────────────── // Térkép vezérlők // ───────────────────────────────────────────────────────────────── @@ -288,21 +288,23 @@ class MapSurveyController extends GetxController { } void _updateCurrentLocationMarker() { - currentLocationMarker.clear(); - currentLocationMarker.add(Marker( - point: LatLng(currentLatitude.value, currentLongitude.value), - width: 15.0, - height: 15.0, - child: Container( + currentLocationMarker.assignAll([ + Marker( + point: LatLng(currentLatitude.value, currentLongitude.value), width: 15.0, height: 15.0, - decoration: BoxDecoration( - color: getCurrentLocationMarkerColor(_gnss.gpsQuality.value), - shape: BoxShape.circle, - border: Border.all(width: 1.5, color: Colors.white), + child: Container( + width: 15.0, + height: 15.0, + decoration: BoxDecoration( + color: getCurrentLocationMarkerColor(_gnss.gpsQuality.value), + shape: BoxShape.circle, + border: Border.all(width: 1.5, color: Colors.white), + ), ), - ), - )); + ) + ]); + if (isMapMoveToCenter.value) { mapController.move( LatLng(currentLatitude.value, currentLongitude.value), @@ -622,7 +624,7 @@ class MapSurveyController extends GetxController { // ───────────────────────────────────────────────────────────────── double calculateDistance(LatLng start, LatLng end) { - const r = 6371.0; + const r = 6371000.0; final lat1 = start.latitude * (pi / 180); final lon1 = start.longitude * (pi / 180); final lat2 = end.latitude * (pi / 180); 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 496cb5b..5dcd840 100644 --- a/lib/pages/map_survey/presentations/views/map_survey_view.dart +++ b/lib/pages/map_survey/presentations/views/map_survey_view.dart @@ -1,13 +1,8 @@ -import 'dart:io'; -import 'dart:math'; - -import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:flutter_map_polywidget/flutter_map_polywidget.dart'; import 'package:get/get.dart'; import 'package:flutter_map/flutter_map.dart'; import 'package:latlong2/latlong.dart'; -import 'package:rive/rive.dart'; import 'package:terepi_seged/pages/map_survey/presentations/controllers/map_survey_controller.dart'; import 'package:terepi_seged/pages/map_survey/presentations/views/settings_dialog.dart'; import 'package:terepi_seged/utils/rive_utils.dart'; @@ -24,12 +19,29 @@ class MapSurveyView extends GetView { @override Widget build(BuildContext context) { return Stack(children: [ - const SharedMapWidget(), + SharedMapWidget( + mapController: controller.mapController, + currentZoom: controller.currentZoom, + onZoomIn: controller.mapZoomIn, + onZoomOut: controller.mapZoomOut, + onCenterOnGps: controller.isMapMoveToCenter, + ), Positioned( top: 8, right: 60, left: 8, - child: CoordinatePanel.fromController(controller), + child: CoordinatePanel( + eovY: controller.eovY, + eovX: controller.eovX, + horError: controller.gpsLatitudeError, + vertError: controller.gpsAltitudeError, + altitudeMsl: controller.gpsAltitude, + geoidSeparation: controller.gpsGeoidSeparation, + ntripConnected: controller.ntripIsConnected, + ntripBytes: controller.ntripReceivedData, + ntripPackets: controller.ntripDataPacketNumbers, + ggaPackets: controller.ggaSenDataPacketNumber, + ), ), // Positioned(top: 8, left: 0, right: 0, child: _ModeSelector()), // Positioned( diff --git a/lib/pages/shell/presentations/views/shell_view.dart b/lib/pages/shell/presentations/views/shell_view.dart index 2885585..ac7295b 100644 --- a/lib/pages/shell/presentations/views/shell_view.dart +++ b/lib/pages/shell/presentations/views/shell_view.dart @@ -23,6 +23,8 @@ class ShellView extends GetView { @override Widget build(BuildContext context) { return Scaffold( + extendBody: true, + extendBodyBehindAppBar: false, appBar: AppBar( // Cím reaktívan frissül tab váltáskor title: Obx(() => Text(controller.currentTitle)), diff --git a/lib/services/ntrip_service.dart b/lib/services/ntrip_service.dart index 68f4ad0..0c2de62 100644 --- a/lib/services/ntrip_service.dart +++ b/lib/services/ntrip_service.dart @@ -37,8 +37,8 @@ class NtripService extends GetxService { final host = '84.206.45.44'.obs; // gnssnet.hu IP final port = 2101.obs; final mountpoint = 'SGO_RTK3.2'.obs; - final username = ''.obs; - final password = ''.obs; + final username = 'elgi03'.obs; + final password = 'StEfan14'.obs; // ── UI controllerek (beállítás dialóghoz) ──────────────────────── final hostController = TextEditingController(); @@ -228,8 +228,8 @@ class NtripService extends GetxService { host.value = prefs.getString('ntrip_host') ?? '84.206.45.44'; port.value = prefs.getInt('ntrip_port') ?? 2101; mountpoint.value = prefs.getString('ntrip_mountpoint') ?? 'SGO_RTK3.2'; - username.value = prefs.getString('ntrip_username') ?? ''; - password.value = prefs.getString('ntrip_password') ?? ''; + username.value = prefs.getString('ntrip_username') ?? 'elgi01'; + password.value = prefs.getString('ntrip_password') ?? 'StEfan14'; } void _syncControllersFromValues() { diff --git a/lib/widgets/shared_map_widgets.dart b/lib/widgets/shared_map_widgets.dart index 33cfd15..d74b13b 100644 --- a/lib/widgets/shared_map_widgets.dart +++ b/lib/widgets/shared_map_widgets.dart @@ -1,264 +1,102 @@ -// lib/widgets/shared_map_widget.dart -import 'dart:math' as math; -import 'dart:math'; +// lib/widgets/shared_map_widgets.dart import 'package:flutter/material.dart'; import 'package:flutter_map/flutter_map.dart'; import 'package:get/get.dart'; import 'package:latlong2/latlong.dart'; -import '../services/gnss/gnss_service.dart'; -import '../services/coord_converter_service.dart'; -import '../pages/map_survey/presentations/controllers/map_survey_controller.dart'; - -// ─── SharedMapWidget ────────────────────────────────────────────────────────── - -class SharedMapWidget extends StatefulWidget { - /// Extra flutter_map rétegek (pl. PolylineLayer, PolygonLayer). - final List extraLayers; - - /// Külső MapController — ha az oldal saját maga is mozgatja a térképet. - final MapController? mapController; - - /// Hosszú nyomás callback (terepbejárás pont hozzáadáshoz). +class SharedMapWidget extends StatelessWidget { + final MapController mapController; + final List layers; final void Function(TapPosition, LatLng)? onLongPress; + final void Function(MapCamera, bool)? onPositionChanged; - /// Megjelenítendő vezérlők. final MapControls controls; - - /// Kezdeti zoom szint. + final LatLng initialCenter; final double initialZoom; + final double minZoom; + final double maxZoom; + + // Controller-owned state (csak megjelenítéshez) + final RxBool? isFollowing; + final RxBool? isNorthUp; + final RxDouble? currentZoom; + final RxDouble? currentRotationRad; + + // Controller-owned commands + final VoidCallback? onZoomIn; + final VoidCallback? onZoomOut; + final VoidCallback? onCenterOnGps; + final VoidCallback? onResetNorth; const SharedMapWidget({ super.key, - this.extraLayers = const [], - this.mapController, + required this.mapController, + this.layers = const [], this.onLongPress, + this.onPositionChanged, this.controls = const MapControls(), + this.initialCenter = const LatLng(47.5, 19.0), this.initialZoom = 18.0, + this.minZoom = 3.0, + this.maxZoom = 25.0, + this.isFollowing, + this.isNorthUp, + this.currentZoom, + this.currentRotationRad, + this.onZoomIn, + this.onZoomOut, + this.onCenterOnGps, + this.onResetNorth, }); - @override - State createState() => _SharedMapWidgetState(); -} - -class _SharedMapWidgetState extends State { - late final MapController _mapController; - - // Reaktív belső állapot - final _isFollowing = true.obs; // GPS követés be/ki - final _currentZoom = 18.0.obs; - final _isNorthUp = true.obs; // forgó térkép vs. É-up - - @override - void initState() { - super.initState(); - _mapController = widget.mapController ?? MapController(); - _currentZoom.value = widget.initialZoom; - } - - @override - void dispose() { - // Csak akkor disposoljuk, ha belső controller - if (widget.mapController == null) { - _mapController.dispose(); - } - super.dispose(); - } - - // ── GPS pozíció követése ──────────────────────────────────────────── - - void _onPositionChanged(MapCamera camera, bool hasGesture) { - _currentZoom.value = camera.zoom; - // Ha a felhasználó manuálisan mozgatja → kikapcsol a követés - if (hasGesture && _isFollowing.value) { - _isFollowing.value = false; - } - } - - void _centerOnPosition() { - final gnss = GnssService.to; - if (gnss.latitude.value == 0) return; - _mapController.move( - LatLng(gnss.latitude.value, gnss.longitude.value), - _currentZoom.value, - ); - _isFollowing.value = true; - } - - void _zoomIn() => - _mapController.move(_mapController.camera.center, _currentZoom.value + 1); - - void _zoomOut() => - _mapController.move(_mapController.camera.center, _currentZoom.value - 1); - - void _resetNorth() { - _mapController.rotate(0); - _isNorthUp.value = true; - } - - // ── GPS stream → térkép mozgatás ─────────────────────────────────── - @override Widget build(BuildContext context) { - return Obx(() { - final gnss = GnssService.to; - final lat = gnss.latitude.value; - final lon = gnss.longitude.value; - - if (_isFollowing.value && lat != 0 && lon != 0) { - WidgetsBinding.instance.addPostFrameCallback((_) { - if (!mounted) return; - _mapController.move(LatLng(lat, lon), _currentZoom.value); - }); - } - - return Stack( - children: [ - // ── Térkép ──────────────────────────────────────────────── - FlutterMap( - mapController: _mapController, - options: MapOptions( - initialCenter: - lat != 0 ? LatLng(lat, lon) : const LatLng(47.5, 19.0), - initialZoom: widget.initialZoom, - maxZoom: 25, - minZoom: 3, - onLongPress: widget.onLongPress, - onPositionChanged: _onPositionChanged, - interactionOptions: const InteractionOptions( - flags: InteractiveFlag.all, - ), + return Stack( + children: [ + FlutterMap( + mapController: mapController, + options: MapOptions( + initialCenter: initialCenter, + initialZoom: initialZoom, + minZoom: minZoom, + maxZoom: maxZoom, + onLongPress: onLongPress, + onPositionChanged: onPositionChanged, + interactionOptions: const InteractionOptions( + flags: InteractiveFlag.all, ), - children: [ - // 1. Alaptérkép - TileLayer( - urlTemplate: - 'http://{s}.google.com/vt/lyrs=s,h&x={x}&y={y}&z={z}', - subdomains: const ['mt0', 'mt1', 'mt2', 'mt3'], - maxNativeZoom: 18, - ), - // 2. Extra rétegek (terepbejárás elemei) - ...widget.extraLayers, - // 3. Bemért pontok - // if (Get.isRegistered()) - // Obx(() => MarkerLayer( - // markers: _buildMeasuredPointMarkers(), - // )), - // 4. Kitűzési célpont + vonal - if (Get.isRegistered()) - Obx(() { - final lat = GnssService.to.latitude.value; - final lon = GnssService.to.longitude.value; - return _buildStakeoutLayer(lat, lon); - }), - // 5. GPS pozíció - Obx(() { - final lat = GnssService.to.latitude.value; - final lon = GnssService.to.longitude.value; - return MarkerLayer( - markers: lat == 0 && lon == 0 - ? [] - : [_buildCurrentPositionMarker(lat, lon)], - ); - }), - ], ), - - // ── Vezérlők ────────────────────────────────────────────── - _MapControlsOverlay( - controls: widget.controls, - isFollowing: _isFollowing, - isNorthUp: _isNorthUp, - currentZoom: _currentZoom, - onZoomIn: _zoomIn, - onZoomOut: _zoomOut, - onCenterOnGps: _centerOnPosition, - onResetNorth: _resetNorth, - ), - - // ── Zoom szint jelzés (opcionális) ──────────────────────── - if (widget.controls.showZoomLevel) - Positioned( - bottom: 8, - left: 8, - child: Obx(() => _ZoomLabel(_currentZoom.value)), + children: [ + TileLayer( + urlTemplate: + 'http://{s}.google.com/vt/lyrs=s,h&x={x}&y={y}&z={z}', + subdomains: const ['mt0', 'mt1', 'mt2', 'mt3'], + maxNativeZoom: 18, ), - ], - ); - }); - } - - // ── Marker builder metódusok ──────────────────────────────────────── - - List _buildMeasuredPointMarkers() { - if (!Get.isRegistered()) return []; - return MapSurveyController.to.pointNotesMarker; - } - - Widget _buildStakeoutLayer(double lat, double lon) { - if (!Get.isRegistered()) - return const SizedBox.shrink(); - final ctrl = MapSurveyController.to; - if (ctrl.mode.value != MapSurveyMode.stakeout || - ctrl.targetEovY.value == 0) { - return const SizedBox.shrink(); - } - - final wgs = CoordConverterService.to - .eovToWgsPoint(ctrl.targetEovY.value, ctrl.targetEovX.value); - final targetLatLng = LatLng(wgs.y, wgs.x); - final dx = ctrl.eov.value.X - ctrl.targetEovX.value; - final dy = ctrl.eov.value.Y - ctrl.targetEovY.value; - final dist = sqrt(dx * dx + dy * dy); - final onTarget = dist < 0.05; - - return Stack(children: [ - // Szaggatott vonal - PolylineLayer(polylines: [ - Polyline( - points: [LatLng(lat, lon), targetLatLng], - color: Colors.orange.withOpacity(0.85), - strokeWidth: 2.5, + ...layers, + ], ), - ]), - // Célpont marker - MarkerLayer(markers: [ - Marker( - point: targetLatLng, - width: 130, - height: 72, - alignment: Alignment.bottomCenter, - child: _LabeledMarker( - label: ctrl.targetName.value, - icon: Icons.flag, - color: Colors.orange, - activeColor: onTarget ? Colors.green : null, - sublabel: onTarget ? '✓ Célponton' : '${dist.toStringAsFixed(3)} m', + _MapControlsOverlay( + controls: controls, + isFollowing: isFollowing, + isNorthUp: isNorthUp, + currentRotationRad: currentRotationRad, + onZoomIn: onZoomIn, + onZoomOut: onZoomOut, + onCenterOnGps: onCenterOnGps, + onResetNorth: onResetNorth, + ), + if (controls.showZoomLevel && currentZoom != null) + Positioned( + bottom: 8, + left: 8, + child: Obx(() => _ZoomLabel(currentZoom!.value)), ), - ), - ]), - ]); - } - - Marker _buildCurrentPositionMarker(double lat, double lon) { - final color = switch (GnssService.to.gpsQuality.value) { - 4 => Colors.green, - 5 => Colors.lightGreen, - 2 => Colors.blue, - 1 => Colors.orange, - _ => Colors.grey, - }; - return Marker( - point: LatLng(lat, lon), - width: 24, - height: 24, - child: _PulsingDot(color: color), + ], ); } } -// ─── Vezérlők konfigurációja ────────────────────────────────────────────────── - class MapControls { final bool showZoomButtons; final bool showFollowButton; @@ -274,7 +112,6 @@ class MapControls { this.showCompass = false, }); - /// Terepbejárás módhoz — nincs follow (rajzolás közben szabad mozgás) const MapControls.fieldTrip() : showZoomButtons = true, showFollowButton = false, @@ -282,7 +119,6 @@ class MapControls { showZoomLevel = true, showCompass = false; - /// Navigáció módhoz — minden vezérlő const MapControls.navigation() : showZoomButtons = true, showFollowButton = true, @@ -290,7 +126,6 @@ class MapControls { showZoomLevel = false, showCompass = true; - /// Minimális — csak zoom const MapControls.minimal() : showZoomButtons = true, showFollowButton = false, @@ -299,23 +134,22 @@ class MapControls { showCompass = false; } -// ─── Vezérlők overlay ──────────────────────────────────────────────────────── - class _MapControlsOverlay extends StatelessWidget { final MapControls controls; - final RxBool isFollowing; - final RxBool isNorthUp; - final RxDouble currentZoom; - final VoidCallback onZoomIn; - final VoidCallback onZoomOut; - final VoidCallback onCenterOnGps; - final VoidCallback onResetNorth; + final RxBool? isFollowing; + final RxBool? isNorthUp; + final RxDouble? currentRotationRad; + + final VoidCallback? onZoomIn; + final VoidCallback? onZoomOut; + final VoidCallback? onCenterOnGps; + final VoidCallback? onResetNorth; const _MapControlsOverlay({ required this.controls, required this.isFollowing, required this.isNorthUp, - required this.currentZoom, + required this.currentRotationRad, required this.onZoomIn, required this.onZoomOut, required this.onCenterOnGps, @@ -326,41 +160,37 @@ class _MapControlsOverlay extends StatelessWidget { Widget build(BuildContext context) { return Positioned( right: 10, - bottom: 80, // BottomNav felett + bottom: 80, child: Column( mainAxisSize: MainAxisSize.min, children: [ - // ── Iránytű / É-ra forgat ───────────────────────────── - if (controls.showNorthButton) - Obx(() => _ControlButton( - icon: Icons.navigation, - tooltip: 'Észak felfelé', - active: isNorthUp.value, - // A gomb elfordul ahogy a térkép forog — vizuális jelzés - child: Transform.rotate( - angle: 0, - child: const Icon(Icons.navigation, size: 20), - ), - onTap: onResetNorth, - )), - + if (controls.showNorthButton && isNorthUp != null) + Obx(() { + final active = isNorthUp!.value; + final angle = currentRotationRad?.value ?? 0.0; + return _ControlButton( + tooltip: 'Észak felfelé', + active: active, + onTap: onResetNorth, + child: Transform.rotate( + angle: -angle, + child: const Icon(Icons.navigation, size: 20), + ), + ); + }), if (controls.showNorthButton) const SizedBox(height: 6), - - // ── GPS követés ─────────────────────────────────────── - if (controls.showFollowButton) + if (controls.showFollowButton && isFollowing != null) Obx(() => _ControlButton( - tooltip: isFollowing.value + tooltip: isFollowing!.value ? 'GPS követés aktív' : 'GPS követés kikapcsolva', - active: isFollowing.value, - icon: - isFollowing.value ? Icons.gps_fixed : Icons.gps_not_fixed, + active: isFollowing!.value, + icon: isFollowing!.value + ? Icons.gps_fixed + : Icons.gps_not_fixed, onTap: onCenterOnGps, )), - if (controls.showFollowButton) const SizedBox(height: 6), - - // ── Zoom gombok ─────────────────────────────────────── if (controls.showZoomButtons) ...[ _ControlButton( icon: Icons.add, @@ -385,7 +215,7 @@ class _ControlButton extends StatelessWidget { final Widget? child; final String tooltip; final bool active; - final VoidCallback onTap; + final VoidCallback? onTap; const _ControlButton({ this.icon, @@ -435,8 +265,6 @@ class _ControlButton extends StatelessWidget { } } -// ─── Zoom szint label ───────────────────────────────────────────────────────── - class _ZoomLabel extends StatelessWidget { final double zoom; const _ZoomLabel(this.zoom); @@ -457,16 +285,15 @@ class _ZoomLabel extends StatelessWidget { } } -// ─── Feliratozott marker ────────────────────────────────────────────────────── - -class _LabeledMarker extends StatelessWidget { +class LabeledMarker extends StatelessWidget { final String label; final IconData icon; final Color color; final Color? activeColor; final String? sublabel; - const _LabeledMarker({ + const LabeledMarker({ + super.key, required this.label, required this.icon, required this.color, @@ -490,7 +317,7 @@ class _LabeledMarker extends StatelessWidget { color: Colors.black.withOpacity(0.3), blurRadius: 4, offset: const Offset(0, 2), - ) + ), ], ), child: Column( @@ -499,39 +326,47 @@ class _LabeledMarker extends StatelessWidget { Text( label, style: const TextStyle( - color: Colors.white, - fontSize: 11, - fontWeight: FontWeight.w600), + color: Colors.white, + fontSize: 11, + fontWeight: FontWeight.w600, + ), overflow: TextOverflow.ellipsis, maxLines: 1, ), if (sublabel != null) - Text(sublabel!, - style: TextStyle( - color: Colors.white.withOpacity(0.9), fontSize: 9)), + Text( + sublabel!, + style: TextStyle( + color: Colors.white.withOpacity(0.9), + fontSize: 9, + ), + ), ], ), ), Container(width: 2, height: 6, color: c), - Icon(icon, color: c, size: 22, shadows: const [ - Shadow(color: Colors.black45, blurRadius: 4, offset: Offset(0, 2)) - ]), + Icon( + icon, + color: c, + size: 22, + shadows: const [ + Shadow(color: Colors.black45, blurRadius: 4, offset: Offset(0, 2)), + ], + ), ], ); } } -// ─── Pulzáló GPS pont ───────────────────────────────────────────────────────── - -class _PulsingDot extends StatefulWidget { +class PulsingDot extends StatefulWidget { final Color color; - const _PulsingDot({required this.color}); + const PulsingDot({super.key, required this.color}); @override - State<_PulsingDot> createState() => _PulsingDotState(); + State createState() => _PulsingDotState(); } -class _PulsingDotState extends State<_PulsingDot> +class _PulsingDotState extends State with SingleTickerProviderStateMixin { late AnimationController _ctrl; late Animation _scale; @@ -540,10 +375,12 @@ class _PulsingDotState extends State<_PulsingDot> void initState() { super.initState(); _ctrl = AnimationController( - vsync: this, duration: const Duration(milliseconds: 1000)) - ..repeat(reverse: true); - _scale = Tween(begin: 0.8, end: 1.2) - .animate(CurvedAnimation(parent: _ctrl, curve: Curves.easeInOut)); + vsync: this, + duration: const Duration(milliseconds: 1000), + )..repeat(reverse: true); + _scale = Tween(begin: 0.8, end: 1.2).animate( + CurvedAnimation(parent: _ctrl, curve: Curves.easeInOut), + ); } @override @@ -564,9 +401,10 @@ class _PulsingDotState extends State<_PulsingDot> border: Border.all(color: Colors.white, width: 2), boxShadow: [ BoxShadow( - color: widget.color.withOpacity(0.5), - blurRadius: 8, - spreadRadius: 2) + color: widget.color.withOpacity(0.5), + blurRadius: 8, + spreadRadius: 2, + ), ], ), ),