diff --git a/lib/widgets/snr_indicator.dart b/lib/widgets/snr_indicator.dart index 30956e2..99f2053 100644 --- a/lib/widgets/snr_indicator.dart +++ b/lib/widgets/snr_indicator.dart @@ -1,8 +1,64 @@ import 'package:flutter/material.dart'; +import 'package:latlong2/latlong.dart'; + import '../connector/meshcore_connector.dart'; +import '../connector/meshcore_protocol.dart'; import '../l10n/l10n.dart'; +import '../models/contact.dart'; import 'signal_ui.dart'; +Contact? _getRepeaterPrefixMatchNearLocation( + List contacts, + int pubkeyFirstByte, { + LatLng? searchPoint, + bool preferFavorites = false, +}) { + final candidates = contacts + .where( + (c) => + c.publicKey.isNotEmpty && + c.publicKey.first == pubkeyFirstByte && + (c.type == advTypeRepeater || c.type == advTypeRoom), + ) + .toList(); + + if (candidates.isEmpty) return null; + + candidates.sort((a, b) { + if (preferFavorites) { + final favA = a.isFavorite ? 1 : 0; + final favB = b.isFavorite ? 1 : 0; + final favCompare = favB.compareTo(favA); + if (favCompare != 0) return favCompare; + } + + final seenCompare = b.lastSeen.compareTo(a.lastSeen); + if (seenCompare != 0) return seenCompare; + + return a.publicKeyHex.compareTo(b.publicKeyHex); + }); + + if (searchPoint == null) { + return candidates.first; + } + + final distance = Distance(); + Contact best = candidates.first; + var bestDistance = double.infinity; + + for (final c in candidates) { + if (c.hasLocation && c.latitude != null && c.longitude != null) { + final d = distance(searchPoint, LatLng(c.latitude!, c.longitude!)); + if (d < bestDistance) { + bestDistance = d; + best = c; + } + } + } + + return best; +} + class SNRUi { final IconData icon; final Color color; @@ -64,6 +120,15 @@ class SNRIndicator extends StatefulWidget { } class _SNRIndicatorState extends State { + bool _isValidSelfLocation(double lat, double lon) { + const double epsilon = 1e-6; + return (lat.abs() > epsilon || lon.abs() > epsilon) && + lat >= -90.0 && + lat <= 90.0 && + lon >= -180.0 && + lon <= 180.0; + } + @override Widget build(BuildContext context) { final directRepeaters = widget.connector.directRepeaters; @@ -158,10 +223,25 @@ class _SNRIndicatorState extends State { widget.connector.currentSf, ); final allContacts = widget.connector.allContacts; - final name = allContacts - .where((c) => c.publicKey.first == repeater.pubkeyFirstByte) - .map((c) => c.name) - .firstOrNull; + + final selfLat = widget.connector.selfLatitude; + final selfLon = widget.connector.selfLongitude; + + LatLng? selfPoint; + if (selfLat != null && + selfLon != null && + _isValidSelfLocation(selfLat, selfLon)) { + selfPoint = LatLng(selfLat, selfLon); + } + + final contact = _getRepeaterPrefixMatchNearLocation( + allContacts, + repeater.pubkeyFirstByte, + searchPoint: selfPoint, + preferFavorites: true, + ); + + final name = contact?.name; return Column( children: [ diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index ffc8c59..2428a77 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -9,6 +9,7 @@ import flutter_blue_plus_darwin import flutter_local_notifications import mobile_scanner import package_info_plus +import path_provider_foundation import share_plus import shared_preferences_foundation import sqflite_darwin @@ -19,6 +20,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin")) MobileScannerPlugin.register(with: registry.registrar(forPlugin: "MobileScannerPlugin")) FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) + PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))