diff --git a/lib/connector/meshcore_connector.dart b/lib/connector/meshcore_connector.dart index b99ecf7..93c5dcd 100644 --- a/lib/connector/meshcore_connector.dart +++ b/lib/connector/meshcore_connector.dart @@ -193,6 +193,7 @@ class MeshCoreConnector extends ChangeNotifier { static const int _contactMsgBackoffFallbackMs = 5000; static const int _contactMsgBackoffMinMs = 500; static const int _contactMsgBackoffMaxMs = 15000; + int _pollingInterval = 30; bool _batteryRequested = false; bool _awaitingSelfInfo = false; bool _hasReceivedDeviceInfo = false; @@ -323,8 +324,14 @@ class MeshCoreConnector extends ChangeNotifier { List get allContacts => List.unmodifiable([ ..._contacts, - ..._discoveredContacts.where((c) => !c.isActive), + ..._discoveredContacts.where( + (c) => !c.isActive && c.publicKeyHex != selfPublicKeyHex, + ), ]); + + List get allContactsUnfiltered => + List.unmodifiable([..._contacts, ..._discoveredContacts]); + List get discoveredContacts { return List.unmodifiable(_discoveredContacts); } @@ -2242,9 +2249,18 @@ class MeshCoreConnector extends ChangeNotifier { _batteryPollTimer = null; } + void setPollingInterval(int i) { + _pollingInterval = i.clamp(1, 60); + if (isConnected) { + _startRadioStatsPolling(); + } + } + void _startRadioStatsPolling() { _radioStatsPollTimer?.cancel(); - _radioStatsPollTimer = Timer.periodic(const Duration(seconds: 1), (_) { + _radioStatsPollTimer = Timer.periodic(Duration(seconds: _pollingInterval), ( + _, + ) { if (!isConnected) { _stopRadioStatsPolling(); return; @@ -2369,6 +2385,18 @@ class MeshCoreConnector extends ChangeNotifier { }); } + Contact getFromDiscovered(Contact contact) { + final tmp = _discoveredContacts.firstWhere( + (c) => c.publicKeyHex == contact.publicKeyHex, + orElse: () => contact, + ); + return contact.copyWith( + rawPacket: tmp.rawPacket, + latitude: tmp.latitude, + longitude: tmp.longitude, + ); + } + Future getContacts({int? since, bool preserveExisting = false}) async { if (!isConnected) return; @@ -3735,8 +3763,17 @@ class MeshCoreConnector extends ChangeNotifier { } void _handleContact(Uint8List frame, {bool isContact = true}) { - final contact = Contact.fromFrame(frame); - if (contact != null) { + final contactTmp = Contact.fromFrame(frame); + if (contactTmp != null) { + if (listEquals(contactTmp.publicKey, _selfPublicKey)) { + appLogger.info( + 'Ignoring contact with self public key: ${contactTmp.name}', + tag: 'Connector', + ); + removeContact(contactTmp); + return; + } + final contact = getFromDiscovered(contactTmp); _handleDiscovery(contact, frame, noNotify: true, addActive: true); if (contact.type == advTypeRepeater) { diff --git a/lib/connector/meshcore_protocol.dart b/lib/connector/meshcore_protocol.dart index b42e3e5..396d78b 100644 --- a/lib/connector/meshcore_protocol.dart +++ b/lib/connector/meshcore_protocol.dart @@ -202,15 +202,15 @@ const int cmdGetChannel = 31; const int cmdSetChannel = 32; const int cmdSendTracePath = 36; const int cmdSetOtherParams = 38; -const int cmdSendAnonReq = 57; const int cmdSendTelemetryReq = 39; const int cmdGetCustomVar = 40; const int cmdSetCustomVar = 41; const int cmdSendBinaryReq = 50; +const int cmdGetStats = 56; +const int cmdSendAnonReq = 57; const int cmdSetAutoAddConfig = 58; const int cmdGetAutoAddConfig = 59; const int cmdSetPathHashMode = 61; -const int cmdGetStats = 56; // Text message types const int txtTypePlain = 0; diff --git a/lib/l10n/app_bg.arb b/lib/l10n/app_bg.arb index 0f5145d..09bde69 100644 --- a/lib/l10n/app_bg.arb +++ b/lib/l10n/app_bg.arb @@ -2017,5 +2017,7 @@ "scanner_linuxPairingHidePin": "Скрий ПИН", "scanner_linuxPairingShowPin": "Покажи PIN", "scanner_linuxPairingPinTitle": "PIN код за сдвояване на Bluetooth", - "scanner_linuxPairingPinPrompt": "Въведете ПИН за {deviceName} (оставете празно, ако няма)." -} + "scanner_linuxPairingPinPrompt": "Въведете ПИН за {deviceName} (оставете празно, ако няма).", + "repeater_cliQuickClockSync": "Синхронизация на часовника", + "repeater_cliQuickDiscovery": "Открий Съседи" +} \ No newline at end of file diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index c156a44..08dbe85 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -2045,5 +2045,7 @@ "scanner_linuxPairingShowPin": "PIN anzeigen", "scanner_linuxPairingHidePin": "PIN ausblenden", "scanner_linuxPairingPinTitle": "Bluetooth-Paarungs-PIN", - "scanner_linuxPairingPinPrompt": "Geben Sie die PIN für {deviceName} ein (leer lassen, falls keine)." -} + "scanner_linuxPairingPinPrompt": "Geben Sie die PIN für {deviceName} ein (leer lassen, falls keine).", + "repeater_cliQuickClockSync": "Uhr Synchronisieren", + "repeater_cliQuickDiscovery": "Entdecke Nachbarn" +} \ No newline at end of file diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index d8d73ab..bccb472 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -303,8 +303,12 @@ "path_routeWeight": "{weight}/{max}", "@path_routeWeight": { "placeholders": { - "weight": { "type": "String" }, - "max": { "type": "String" } + "weight": { + "type": "String" + }, + "max": { + "type": "String" + } } }, "appSettings_battery": "Battery", @@ -1333,6 +1337,8 @@ "repeater_cliQuickVersion": "Version", "repeater_cliQuickAdvertise": "Advertise", "repeater_cliQuickClock": "Clock", + "repeater_cliQuickClockSync": "Clock Sync", + "repeater_cliQuickDiscovery": "Discover Neighbors", "repeater_cliHelpAdvert": "Sends an advertisement packet", "repeater_cliHelpReboot": "Reboots the device. (note, you'll prob get 'Timeout' which is normal)", "repeater_cliHelpClock": "Displays current time per device's clock.", diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 245f732..7fcd72b 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -2045,5 +2045,7 @@ "scanner_linuxPairingShowPin": "Mostrar PIN", "scanner_linuxPairingPinTitle": "PIN de emparejamiento Bluetooth", "scanner_linuxPairingHidePin": "Ocultar PIN", - "scanner_linuxPairingPinPrompt": "Introduzca el PIN para {deviceName} (déjelo en blanco si no hay ninguno)." -} + "scanner_linuxPairingPinPrompt": "Introduzca el PIN para {deviceName} (déjelo en blanco si no hay ninguno).", + "repeater_cliQuickDiscovery": "Descubrir Vecinos", + "repeater_cliQuickClockSync": "Sincronización del reloj" +} \ No newline at end of file diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index 21b231a..c78380a 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -2017,5 +2017,7 @@ "scanner_linuxPairingShowPin": "Afficher le code PIN", "scanner_linuxPairingHidePin": "Masquer le code PIN", "scanner_linuxPairingPinTitle": "Code PIN d’appairage Bluetooth", - "scanner_linuxPairingPinPrompt": "Entrez le code PIN pour {deviceName} (laissez vide si aucun)." -} + "scanner_linuxPairingPinPrompt": "Entrez le code PIN pour {deviceName} (laissez vide si aucun).", + "repeater_cliQuickClockSync": "Synchronisation de l'horloge", + "repeater_cliQuickDiscovery": "Découvrir les voisins" +} \ No newline at end of file diff --git a/lib/l10n/app_hu.arb b/lib/l10n/app_hu.arb index dc96020..77081d2 100644 --- a/lib/l10n/app_hu.arb +++ b/lib/l10n/app_hu.arb @@ -2055,5 +2055,7 @@ "scanner_linuxPairingHidePin": "PIN elrejtése", "scanner_linuxPairingShowPin": "PIN megjelenítése", "scanner_linuxPairingPinTitle": "Bluetooth párosítási PIN", - "scanner_linuxPairingPinPrompt": "Adja meg a(z) {deviceName} PIN-kódját (hagyja üresen, ha nincs)." + "scanner_linuxPairingPinPrompt": "Adja meg a(z) {deviceName} PIN-kódját (hagyja üresen, ha nincs).", + "repeater_cliQuickClockSync": "Óra szinkronizálás", + "repeater_cliQuickDiscovery": "Fedezd fel a szomszédokat" } diff --git a/lib/l10n/app_it.arb b/lib/l10n/app_it.arb index 13a9602..e101fea 100644 --- a/lib/l10n/app_it.arb +++ b/lib/l10n/app_it.arb @@ -2017,5 +2017,7 @@ "scanner_linuxPairingShowPin": "Mostra PIN", "scanner_linuxPairingHidePin": "Nascondi PIN", "scanner_linuxPairingPinTitle": "PIN di associazione Bluetooth", - "scanner_linuxPairingPinPrompt": "Inserisci il PIN per {deviceName} (lascia vuoto se non ce n'è)." -} + "scanner_linuxPairingPinPrompt": "Inserisci il PIN per {deviceName} (lascia vuoto se non ce n'è).", + "repeater_cliQuickClockSync": "Sincronizzazione dell'orologio", + "repeater_cliQuickDiscovery": "Scopri i Vicini" +} \ No newline at end of file diff --git a/lib/l10n/app_ja.arb b/lib/l10n/app_ja.arb index adb4eea..d991c7a 100644 --- a/lib/l10n/app_ja.arb +++ b/lib/l10n/app_ja.arb @@ -2055,5 +2055,7 @@ "scanner_linuxPairingShowPin": "PINを表示", "scanner_linuxPairingHidePin": "PINを非表示", "scanner_linuxPairingPinTitle": "Bluetooth ペアリング PIN", - "scanner_linuxPairingPinPrompt": "{deviceName}のPINを入力してください(なしの場合は空欄のまま)。" + "scanner_linuxPairingPinPrompt": "{deviceName}のPINを入力してください(なしの場合は空欄のまま)。", + "repeater_cliQuickClockSync": "クロック同期", + "repeater_cliQuickDiscovery": "近隣を発見する" } diff --git a/lib/l10n/app_ko.arb b/lib/l10n/app_ko.arb index 6bccc19..5ce2eed 100644 --- a/lib/l10n/app_ko.arb +++ b/lib/l10n/app_ko.arb @@ -2055,5 +2055,7 @@ "scanner_linuxPairingShowPin": "PIN 표시", "scanner_linuxPairingPinTitle": "블루투스 페어링 PIN", "scanner_linuxPairingHidePin": "PIN 숨기기", - "scanner_linuxPairingPinPrompt": "{deviceName}에 대한 PIN을 입력하세요 (없으면 비워두세요)." + "scanner_linuxPairingPinPrompt": "{deviceName}에 대한 PIN을 입력하세요 (없으면 비워두세요).", + "repeater_cliQuickClockSync": "시계 동기화", + "repeater_cliQuickDiscovery": "이웃 발견하기" } diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index db787b3..fe2d1ea 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -4322,6 +4322,18 @@ abstract class AppLocalizations { /// **'Clock'** String get repeater_cliQuickClock; + /// No description provided for @repeater_cliQuickClockSync. + /// + /// In en, this message translates to: + /// **'Clock Sync'** + String get repeater_cliQuickClockSync; + + /// No description provided for @repeater_cliQuickDiscovery. + /// + /// In en, this message translates to: + /// **'Discover Neighbors'** + String get repeater_cliQuickDiscovery; + /// No description provided for @repeater_cliHelpAdvert. /// /// In en, this message translates to: diff --git a/lib/l10n/app_localizations_bg.dart b/lib/l10n/app_localizations_bg.dart index 2909278..fc3003c 100644 --- a/lib/l10n/app_localizations_bg.dart +++ b/lib/l10n/app_localizations_bg.dart @@ -2429,6 +2429,12 @@ class AppLocalizationsBg extends AppLocalizations { @override String get repeater_cliQuickClock => 'Часовник'; + @override + String get repeater_cliQuickClockSync => 'Синхронизация на часовника'; + + @override + String get repeater_cliQuickDiscovery => 'Открий Съседи'; + @override String get repeater_cliHelpAdvert => 'Изпраща рекламен пакет'; diff --git a/lib/l10n/app_localizations_de.dart b/lib/l10n/app_localizations_de.dart index 4afefde..e451072 100644 --- a/lib/l10n/app_localizations_de.dart +++ b/lib/l10n/app_localizations_de.dart @@ -2429,6 +2429,12 @@ class AppLocalizationsDe extends AppLocalizations { @override String get repeater_cliQuickClock => 'Uhr'; + @override + String get repeater_cliQuickClockSync => 'Uhr Synchronisieren'; + + @override + String get repeater_cliQuickDiscovery => 'Entdecke Nachbarn'; + @override String get repeater_cliHelpAdvert => 'Sendet eine Ankündigung'; diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index a420a55..59dae81 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -2379,6 +2379,12 @@ class AppLocalizationsEn extends AppLocalizations { @override String get repeater_cliQuickClock => 'Clock'; + @override + String get repeater_cliQuickClockSync => 'Clock Sync'; + + @override + String get repeater_cliQuickDiscovery => 'Discover Neighbors'; + @override String get repeater_cliHelpAdvert => 'Sends an advertisement packet'; diff --git a/lib/l10n/app_localizations_es.dart b/lib/l10n/app_localizations_es.dart index 93a8bc9..4404a61 100644 --- a/lib/l10n/app_localizations_es.dart +++ b/lib/l10n/app_localizations_es.dart @@ -2423,6 +2423,12 @@ class AppLocalizationsEs extends AppLocalizations { @override String get repeater_cliQuickClock => 'Reloj'; + @override + String get repeater_cliQuickClockSync => 'Sincronización del reloj'; + + @override + String get repeater_cliQuickDiscovery => 'Descubrir Vecinos'; + @override String get repeater_cliHelpAdvert => 'Envía un paquete de publicidad'; diff --git a/lib/l10n/app_localizations_fr.dart b/lib/l10n/app_localizations_fr.dart index 9912542..505262f 100644 --- a/lib/l10n/app_localizations_fr.dart +++ b/lib/l10n/app_localizations_fr.dart @@ -2442,6 +2442,12 @@ class AppLocalizationsFr extends AppLocalizations { @override String get repeater_cliQuickClock => 'Horloge'; + @override + String get repeater_cliQuickClockSync => 'Synchronisation de l\'horloge'; + + @override + String get repeater_cliQuickDiscovery => 'Découvrir les voisins'; + @override String get repeater_cliHelpAdvert => 'Envoie un paquet d\'annonce'; diff --git a/lib/l10n/app_localizations_hu.dart b/lib/l10n/app_localizations_hu.dart index dc6374a..66c1085 100644 --- a/lib/l10n/app_localizations_hu.dart +++ b/lib/l10n/app_localizations_hu.dart @@ -2437,6 +2437,12 @@ class AppLocalizationsHu extends AppLocalizations { @override String get repeater_cliQuickClock => 'óra'; + @override + String get repeater_cliQuickClockSync => 'Óra szinkronizálás'; + + @override + String get repeater_cliQuickDiscovery => 'Fedezd fel a szomszédokat'; + @override String get repeater_cliHelpAdvert => 'Elküldi egy hirdetési csomagot'; diff --git a/lib/l10n/app_localizations_it.dart b/lib/l10n/app_localizations_it.dart index 3fc5e56..9e7a990 100644 --- a/lib/l10n/app_localizations_it.dart +++ b/lib/l10n/app_localizations_it.dart @@ -2426,6 +2426,12 @@ class AppLocalizationsIt extends AppLocalizations { @override String get repeater_cliQuickClock => 'Orologio'; + @override + String get repeater_cliQuickClockSync => 'Sincronizzazione dell\'orologio'; + + @override + String get repeater_cliQuickDiscovery => 'Scopri i Vicini'; + @override String get repeater_cliHelpAdvert => 'Invia un pacchetto pubblicitario'; diff --git a/lib/l10n/app_localizations_ja.dart b/lib/l10n/app_localizations_ja.dart index 03d70d4..d632b38 100644 --- a/lib/l10n/app_localizations_ja.dart +++ b/lib/l10n/app_localizations_ja.dart @@ -2322,6 +2322,12 @@ class AppLocalizationsJa extends AppLocalizations { @override String get repeater_cliQuickClock => '時計'; + @override + String get repeater_cliQuickClockSync => 'クロック同期'; + + @override + String get repeater_cliQuickDiscovery => '近隣を発見する'; + @override String get repeater_cliHelpAdvert => '広告用資料を送る'; diff --git a/lib/l10n/app_localizations_ko.dart b/lib/l10n/app_localizations_ko.dart index 5e5925f..10620eb 100644 --- a/lib/l10n/app_localizations_ko.dart +++ b/lib/l10n/app_localizations_ko.dart @@ -2319,6 +2319,12 @@ class AppLocalizationsKo extends AppLocalizations { @override String get repeater_cliQuickClock => '시계'; + @override + String get repeater_cliQuickClockSync => '시계 동기화'; + + @override + String get repeater_cliQuickDiscovery => '이웃 발견하기'; + @override String get repeater_cliHelpAdvert => '광고 패킷을 발송'; diff --git a/lib/l10n/app_localizations_nl.dart b/lib/l10n/app_localizations_nl.dart index bcb2d5d..fe784e9 100644 --- a/lib/l10n/app_localizations_nl.dart +++ b/lib/l10n/app_localizations_nl.dart @@ -2409,6 +2409,12 @@ class AppLocalizationsNl extends AppLocalizations { @override String get repeater_cliQuickClock => 'Tijd'; + @override + String get repeater_cliQuickClockSync => 'Kloksynchronisatie'; + + @override + String get repeater_cliQuickDiscovery => 'Ontdek Buren'; + @override String get repeater_cliHelpAdvert => 'Verstuurt een advertentiepakket'; diff --git a/lib/l10n/app_localizations_pl.dart b/lib/l10n/app_localizations_pl.dart index 5c66761..89adf74 100644 --- a/lib/l10n/app_localizations_pl.dart +++ b/lib/l10n/app_localizations_pl.dart @@ -2436,6 +2436,12 @@ class AppLocalizationsPl extends AppLocalizations { @override String get repeater_cliQuickClock => 'Godzina'; + @override + String get repeater_cliQuickClockSync => 'Synchronizacja zegara'; + + @override + String get repeater_cliQuickDiscovery => 'Odkryj Sąsiadów'; + @override String get repeater_cliHelpAdvert => 'Wysyła pakiet rozgłoszeniowy'; diff --git a/lib/l10n/app_localizations_pt.dart b/lib/l10n/app_localizations_pt.dart index 98c72f5..1b347c4 100644 --- a/lib/l10n/app_localizations_pt.dart +++ b/lib/l10n/app_localizations_pt.dart @@ -2423,6 +2423,12 @@ class AppLocalizationsPt extends AppLocalizations { @override String get repeater_cliQuickClock => 'Relógio'; + @override + String get repeater_cliQuickClockSync => 'Sincronização do Relógio'; + + @override + String get repeater_cliQuickDiscovery => 'Descobrir Vizinhos'; + @override String get repeater_cliHelpAdvert => 'Envia um pacote de anúncios'; diff --git a/lib/l10n/app_localizations_ru.dart b/lib/l10n/app_localizations_ru.dart index 4184641..ff6fb71 100644 --- a/lib/l10n/app_localizations_ru.dart +++ b/lib/l10n/app_localizations_ru.dart @@ -2427,6 +2427,12 @@ class AppLocalizationsRu extends AppLocalizations { @override String get repeater_cliQuickClock => 'Время'; + @override + String get repeater_cliQuickClockSync => 'Синхронизация часов'; + + @override + String get repeater_cliQuickDiscovery => 'Обнаружить Соседей'; + @override String get repeater_cliHelpAdvert => 'Отправляет пакет анонсирования'; diff --git a/lib/l10n/app_localizations_sk.dart b/lib/l10n/app_localizations_sk.dart index 59f46bd..37b3757 100644 --- a/lib/l10n/app_localizations_sk.dart +++ b/lib/l10n/app_localizations_sk.dart @@ -2406,6 +2406,12 @@ class AppLocalizationsSk extends AppLocalizations { @override String get repeater_cliQuickClock => 'Hodiny'; + @override + String get repeater_cliQuickClockSync => 'Synchronizácia hodin'; + + @override + String get repeater_cliQuickDiscovery => 'Objaviť susedov'; + @override String get repeater_cliHelpAdvert => 'Odosiela reklamnú balíček.'; diff --git a/lib/l10n/app_localizations_sl.dart b/lib/l10n/app_localizations_sl.dart index 171353c..536894e 100644 --- a/lib/l10n/app_localizations_sl.dart +++ b/lib/l10n/app_localizations_sl.dart @@ -2409,6 +2409,12 @@ class AppLocalizationsSl extends AppLocalizations { @override String get repeater_cliQuickClock => 'Ura'; + @override + String get repeater_cliQuickClockSync => 'Usklajevanje ure'; + + @override + String get repeater_cliQuickDiscovery => 'Odkrijte sosede'; + @override String get repeater_cliHelpAdvert => 'Pošlje paket oglasov'; diff --git a/lib/l10n/app_localizations_sv.dart b/lib/l10n/app_localizations_sv.dart index 6a776d7..2e20f2a 100644 --- a/lib/l10n/app_localizations_sv.dart +++ b/lib/l10n/app_localizations_sv.dart @@ -2394,6 +2394,12 @@ class AppLocalizationsSv extends AppLocalizations { @override String get repeater_cliQuickClock => 'Klocka'; + @override + String get repeater_cliQuickClockSync => 'Synkronisera klocka'; + + @override + String get repeater_cliQuickDiscovery => 'Upptäck grannar'; + @override String get repeater_cliHelpAdvert => 'Skickar ett annonspaket'; diff --git a/lib/l10n/app_localizations_uk.dart b/lib/l10n/app_localizations_uk.dart index 9ebead2..2335f37 100644 --- a/lib/l10n/app_localizations_uk.dart +++ b/lib/l10n/app_localizations_uk.dart @@ -2427,6 +2427,12 @@ class AppLocalizationsUk extends AppLocalizations { @override String get repeater_cliQuickClock => 'Годинник'; + @override + String get repeater_cliQuickClockSync => 'Синхронізація годинника'; + + @override + String get repeater_cliQuickDiscovery => 'Відкрити сусідів'; + @override String get repeater_cliHelpAdvert => 'Надсилає пакет оголошення'; diff --git a/lib/l10n/app_localizations_zh.dart b/lib/l10n/app_localizations_zh.dart index 6d3a856..8672ac8 100644 --- a/lib/l10n/app_localizations_zh.dart +++ b/lib/l10n/app_localizations_zh.dart @@ -2277,6 +2277,12 @@ class AppLocalizationsZh extends AppLocalizations { @override String get repeater_cliQuickClock => '时钟'; + @override + String get repeater_cliQuickClockSync => '同步时钟'; + + @override + String get repeater_cliQuickDiscovery => '发现邻居'; + @override String get repeater_cliHelpAdvert => '发送广播包'; diff --git a/lib/l10n/app_nl.arb b/lib/l10n/app_nl.arb index 9f164fd..013b074 100644 --- a/lib/l10n/app_nl.arb +++ b/lib/l10n/app_nl.arb @@ -2017,5 +2017,7 @@ "scanner_linuxPairingShowPin": "Toon PIN", "scanner_linuxPairingHidePin": "PIN verbergen", "scanner_linuxPairingPinPrompt": "Voer PIN in voor {deviceName} (laat leeg als er geen is).", - "scanner_linuxPairingPinTitle": "Bluetooth‑koppelings‑PIN" -} + "scanner_linuxPairingPinTitle": "Bluetooth‑koppelings‑PIN", + "repeater_cliQuickDiscovery": "Ontdek Buren", + "repeater_cliQuickClockSync": "Kloksynchronisatie" +} \ No newline at end of file diff --git a/lib/l10n/app_pl.arb b/lib/l10n/app_pl.arb index 87b4754..c499b83 100644 --- a/lib/l10n/app_pl.arb +++ b/lib/l10n/app_pl.arb @@ -2055,5 +2055,7 @@ "scanner_linuxPairingShowPin": "Pokaż PIN", "scanner_linuxPairingHidePin": "Ukryj PIN", "scanner_linuxPairingPinPrompt": "Wprowadź kod PIN dla {deviceName} (pozostaw puste, jeśli brak).", - "scanner_linuxPairingPinTitle": "Kod PIN parowania Bluetooth" -} + "scanner_linuxPairingPinTitle": "Kod PIN parowania Bluetooth", + "repeater_cliQuickClockSync": "Synchronizacja zegara", + "repeater_cliQuickDiscovery": "Odkryj Sąsiadów" +} \ No newline at end of file diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index eb87a15..d492fbd 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -2017,5 +2017,7 @@ "scanner_linuxPairingShowPin": "Mostrar PIN", "scanner_linuxPairingHidePin": "Ocultar PIN", "scanner_linuxPairingPinPrompt": "Insira o PIN para {deviceName} (deixe em branco se não houver).", - "scanner_linuxPairingPinTitle": "PIN de emparelhamento Bluetooth" -} + "scanner_linuxPairingPinTitle": "PIN de emparelhamento Bluetooth", + "repeater_cliQuickClockSync": "Sincronização do Relógio", + "repeater_cliQuickDiscovery": "Descobrir Vizinhos" +} \ No newline at end of file diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb index c9493a0..18fa20e 100644 --- a/lib/l10n/app_ru.arb +++ b/lib/l10n/app_ru.arb @@ -1257,5 +1257,7 @@ "scanner_linuxPairingShowPin": "Показать PIN", "scanner_linuxPairingPinPrompt": "Введите PIN‑код для {deviceName} (оставьте пустым, если нет).", "scanner_linuxPairingHidePin": "Скрыть PIN", - "scanner_linuxPairingPinTitle": "PIN‑код сопряжения Bluetooth" -} + "scanner_linuxPairingPinTitle": "PIN‑код сопряжения Bluetooth", + "repeater_cliQuickDiscovery": "Обнаружить Соседей", + "repeater_cliQuickClockSync": "Синхронизация часов" +} \ No newline at end of file diff --git a/lib/l10n/app_sk.arb b/lib/l10n/app_sk.arb index 5a7aa6d..12b5081 100644 --- a/lib/l10n/app_sk.arb +++ b/lib/l10n/app_sk.arb @@ -2017,5 +2017,7 @@ "scanner_linuxPairingPinPrompt": "Zadajte PIN pre {deviceName} (ak nie je, nechajte prázdne).", "scanner_linuxPairingShowPin": "Zobraziť PIN", "scanner_linuxPairingHidePin": "Skryť PIN", - "scanner_linuxPairingPinTitle": "Bluetooth párovací PIN" -} + "scanner_linuxPairingPinTitle": "Bluetooth párovací PIN", + "repeater_cliQuickClockSync": "Synchronizácia hodin", + "repeater_cliQuickDiscovery": "Objaviť susedov" +} \ No newline at end of file diff --git a/lib/l10n/app_sl.arb b/lib/l10n/app_sl.arb index 9adb387..8de6586 100644 --- a/lib/l10n/app_sl.arb +++ b/lib/l10n/app_sl.arb @@ -2017,5 +2017,7 @@ "scanner_linuxPairingShowPin": "Prikaži PIN", "scanner_linuxPairingHidePin": "Skrij PIN", "scanner_linuxPairingPinPrompt": "Vnesite PIN za {deviceName} (pustite prazno, če ga ni).", - "scanner_linuxPairingPinTitle": "Bluetooth PIN za seznanjanje" -} + "scanner_linuxPairingPinTitle": "Bluetooth PIN za seznanjanje", + "repeater_cliQuickDiscovery": "Odkrijte sosede", + "repeater_cliQuickClockSync": "Usklajevanje ure" +} \ No newline at end of file diff --git a/lib/l10n/app_sv.arb b/lib/l10n/app_sv.arb index e4ace3e..91743db 100644 --- a/lib/l10n/app_sv.arb +++ b/lib/l10n/app_sv.arb @@ -2017,5 +2017,7 @@ "scanner_linuxPairingShowPin": "Visa PIN", "scanner_linuxPairingPinTitle": "Bluetooth‑parnings‑PIN", "scanner_linuxPairingPinPrompt": "Ange PIN för {deviceName} (lämna tomt om ingen).", - "scanner_linuxPairingHidePin": "Dölj PIN" -} + "scanner_linuxPairingHidePin": "Dölj PIN", + "repeater_cliQuickDiscovery": "Upptäck grannar", + "repeater_cliQuickClockSync": "Synkronisera klocka" +} \ No newline at end of file diff --git a/lib/l10n/app_uk.arb b/lib/l10n/app_uk.arb index 8e27da1..b8cabed 100644 --- a/lib/l10n/app_uk.arb +++ b/lib/l10n/app_uk.arb @@ -2017,5 +2017,7 @@ "scanner_linuxPairingPinTitle": "PIN‑код спарювання Bluetooth", "scanner_linuxPairingShowPin": "Показати PIN", "scanner_linuxPairingPinPrompt": "Введіть PIN для {deviceName} (залиште порожнім, якщо його немає).", - "scanner_linuxPairingHidePin": "Приховати PIN" -} + "scanner_linuxPairingHidePin": "Приховати PIN", + "repeater_cliQuickClockSync": "Синхронізація годинника", + "repeater_cliQuickDiscovery": "Відкрити сусідів" +} \ No newline at end of file diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index cd7b44d..9d23c8e 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -2022,5 +2022,7 @@ "scanner_linuxPairingShowPin": "显示 PIN码", "scanner_linuxPairingPinPrompt": "输入 {deviceName} 的 PIN(如果没有,请留空)。", "scanner_linuxPairingPinTitle": "蓝牙配对 PIN", - "scanner_linuxPairingHidePin": "隐藏 PIN" -} + "scanner_linuxPairingHidePin": "隐藏 PIN", + "repeater_cliQuickDiscovery": "发现邻居", + "repeater_cliQuickClockSync": "同步时钟" +} \ No newline at end of file diff --git a/lib/screens/channel_message_path_screen.dart b/lib/screens/channel_message_path_screen.dart index 94b8eee..0eb2c22 100644 --- a/lib/screens/channel_message_path_screen.dart +++ b/lib/screens/channel_message_path_screen.dart @@ -822,7 +822,8 @@ List<_PathHop> _buildPathHops( ) { if (pathBytes.isEmpty) return const []; final candidatesByPrefix = >{}; - for (final contact in connector.allContacts) { + final allContacts = connector.allContacts; + for (final contact in allContacts) { if (contact.publicKey.isEmpty) continue; if (contact.type != advTypeRepeater && contact.type != advTypeRoom) { continue; @@ -839,7 +840,8 @@ List<_PathHop> _buildPathHops( : null; var previousPosition = startPoint; final distance = Distance(); - + var lastDistance = 0.0; + var bestDistance = 0.0; final hops = <_PathHop>[]; for (var i = 0; i < pathBytes.length; i++) { final searchPoint = i == 0 ? startPoint : previousPosition; @@ -848,7 +850,7 @@ List<_PathHop> _buildPathHops( if (candidates != null && candidates.isNotEmpty) { var bestIndex = 0; if (searchPoint != null) { - var bestDistance = double.infinity; + bestDistance = double.infinity; for (var j = 0; j < candidates.length; j++) { final candidate = candidates[j]; if (!candidate.hasLocation || @@ -876,6 +878,16 @@ List<_PathHop> _buildPathHops( if (resolvedPosition != null) { previousPosition = resolvedPosition; } + // If the best candidate is much farther than the previous hop, it's likely not the correct match. + if (lastDistance + bestDistance > 70000 && + candidates != null && + candidates.isNotEmpty) { + i--; + lastDistance = bestDistance; + continue; + } + lastDistance = bestDistance; + hops.add( _PathHop( index: i + 1, diff --git a/lib/screens/channels_screen.dart b/lib/screens/channels_screen.dart index d67d03d..51d2453 100644 --- a/lib/screens/channels_screen.dart +++ b/lib/screens/channels_screen.dart @@ -127,7 +127,7 @@ class _ChannelsScreenState extends State canPop: allowBack, child: Scaffold( appBar: AppBar( - title: AppBarTitle(context.l10n.channels_title, indicators: false), + title: AppBarTitle(context.l10n.channels_title), centerTitle: true, automaticallyImplyLeading: false, actions: [ diff --git a/lib/screens/chat_screen.dart b/lib/screens/chat_screen.dart index aecdc81..ab7082c 100644 --- a/lib/screens/chat_screen.dart +++ b/lib/screens/chat_screen.dart @@ -290,6 +290,7 @@ class _ChatScreenState extends State { tooltip: context.l10n.chat_pathManagement, onPressed: () => _showPathHistory(context), ), + const RadioStatsIconButton(), Consumer( builder: (context, connector, _) { return PopupMenuButton( @@ -362,7 +363,6 @@ class _ChatScreenState extends State { ); }, ), - const RadioStatsIconButton(), ], ), body: Consumer( diff --git a/lib/screens/companion_radio_stats_screen.dart b/lib/screens/companion_radio_stats_screen.dart index 01fb64d..9c37676 100644 --- a/lib/screens/companion_radio_stats_screen.dart +++ b/lib/screens/companion_radio_stats_screen.dart @@ -24,6 +24,7 @@ class _CompanionRadioStatsScreenState extends State { final c = context.read(); _connector = c; c.acquireRadioStatsPolling(); + c.setPollingInterval(1); c.radioStatsNotifier.addListener(_onStatsUpdate); } @@ -44,6 +45,7 @@ class _CompanionRadioStatsScreenState extends State { void dispose() { _connector?.radioStatsNotifier.removeListener(_onStatsUpdate); _connector?.releaseRadioStatsPolling(); + _connector?.setPollingInterval(30); super.dispose(); } diff --git a/lib/screens/contacts_screen.dart b/lib/screens/contacts_screen.dart index d5b01f2..62a380b 100644 --- a/lib/screens/contacts_screen.dart +++ b/lib/screens/contacts_screen.dart @@ -1240,9 +1240,7 @@ class _ContactsScreenState extends State if (isRepeater) ...[ ListTile( leading: const Icon(Icons.radar, color: Colors.green), - title: contact.pathBytesForDisplay.isNotEmpty - ? Text(context.l10n.contacts_pathTrace) - : Text(context.l10n.contacts_ping), + title: Text(context.l10n.contacts_ping), onTap: () { final hw = context .read() @@ -1251,11 +1249,8 @@ class _ContactsScreenState extends State context, MaterialPageRoute( builder: (context) => PathTraceMapScreen( - title: contact.pathBytesForDisplay.isNotEmpty - ? context.l10n.contacts_repeaterPathTrace - : context.l10n.contacts_repeaterPing, - path: contact.pathBytesForDisplay, - flipPathAround: true, + title: context.l10n.contacts_repeaterPing, + path: Uint8List.fromList([contact.publicKey.first]), targetContact: contact, pathHashByteWidth: hw, ), @@ -1274,9 +1269,7 @@ class _ContactsScreenState extends State ] else if (isRoom) ...[ ListTile( leading: const Icon(Icons.radar, color: Colors.green), - title: contact.pathLength > 0 - ? Text(context.l10n.contacts_pathTrace) - : Text(context.l10n.contacts_ping), + title: Text(context.l10n.contacts_pathTrace), onTap: () { final hw = context .read() @@ -1288,7 +1281,9 @@ class _ContactsScreenState extends State title: contact.pathBytesForDisplay.isNotEmpty ? context.l10n.contacts_roomPathTrace : context.l10n.contacts_roomPing, - path: contact.pathBytesForDisplay, + path: contact.pathBytesForDisplay.isNotEmpty + ? contact.pathBytesForDisplay + : Uint8List.fromList([contact.publicKey.first]), flipPathAround: contact.pathBytesForDisplay.isNotEmpty, targetContact: contact, pathHashByteWidth: hw, diff --git a/lib/screens/discovery_screen.dart b/lib/screens/discovery_screen.dart index 4e7c6e8..3f9d965 100644 --- a/lib/screens/discovery_screen.dart +++ b/lib/screens/discovery_screen.dart @@ -38,6 +38,13 @@ class _DiscoveryScreenState extends State { super.dispose(); } + DateTime _resolveLastSeen(Contact contact) { + if (contact.type != advTypeChat) return contact.lastSeen; + return contact.lastMessageAt.isAfter(contact.lastSeen) + ? contact.lastMessageAt + : contact.lastSeen; + } + @override Widget build(BuildContext context) { final l10n = context.l10n; @@ -108,11 +115,56 @@ class _DiscoveryScreenState extends State { maxLines: 1, overflow: TextOverflow.ellipsis, ), - trailing: Text( - _formatLastSeen(context, contact.lastSeen), - style: TextStyle( - fontSize: 12, - color: Colors.grey[600], + // Clamp text scaling in trailing section to prevent overflow while + // maintaining accessibility. Primary content (title/subtitle) scales normally. + trailing: MediaQuery( + data: MediaQuery.of(context).copyWith( + textScaler: TextScaler.linear( + MediaQuery.textScalerOf( + context, + ).scale(1.0).clamp(1.0, 1.3), + ), + ), + child: SizedBox( + width: 120, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Text( + _formatLastSeen( + context, + _resolveLastSeen(contact), + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + textAlign: TextAlign.right, + style: TextStyle( + fontSize: 12, + color: Colors.grey[600], + ), + ), + Row( + mainAxisSize: MainAxisSize.min, + children: [ + if (contact.hasLocation) + Icon( + Icons.location_on, + size: 14, + color: Colors.grey[400], + ), + if (contact.rawPacket != null) + const SizedBox(width: 2), + if (contact.rawPacket != null) + Icon( + Icons.cell_tower, + size: 14, + color: Colors.grey[400], + ), + ], + ), + ], + ), ), ), onTap: () { diff --git a/lib/screens/map_screen.dart b/lib/screens/map_screen.dart index 9616d47..f2d09f3 100644 --- a/lib/screens/map_screen.dart +++ b/lib/screens/map_screen.dart @@ -64,6 +64,7 @@ class _MapScreenState extends State { bool _hasInitializedMap = false; bool _removedMarkersLoaded = false; final List _pathTrace = []; + final List _pathTraceContacts = []; final List _points = []; final List _polylines = []; bool _legendExpanded = false; @@ -488,7 +489,7 @@ class _MapScreenState extends State { ), ), ), - if (!_isBuildingPathTrace) + if (!settings.mapShowOverlaps) ..._buildGuessedMarker( guessedLocations, showLabels: _showNodeLabels, @@ -788,17 +789,26 @@ class _MapScreenState extends State { final markers = []; for (final guess in guessed) { + if (guess.contact.type == advTypeChat && _isBuildingPathTrace) { + continue; + } + final color = _getNodeColor(guess.contact.type); final marker = Marker( point: guess.position, width: 35, height: 35, child: GestureDetector( - onTap: () => _showNodeInfo( - context, - guess.contact, - guessedPosition: guess.position, - ), + onLongPress: () => _isBuildingPathTrace + ? _showNodeInfo(context, guess.contact) + : null, + onTap: () => _isBuildingPathTrace + ? _addToPath(context, guess.contact, position: guess.position) + : _showNodeInfo( + context, + guess.contact, + guessedPosition: guess.position, + ), child: Container( padding: const EdgeInsets.all(4), decoration: BoxDecoration( @@ -870,23 +880,29 @@ class _MapScreenState extends State { addContact = true; } - final hasOverlap = contacts - .where( - (c) => - c.publicKeyHex != contact.publicKeyHex && - c.publicKey.first == contact.publicKey.first && - (c.type == advTypeRepeater || c.type == advTypeRoom) && - (contact.type == advTypeRepeater || - contact.type == advTypeRoom), - ) - .firstOrNull; - - if (hasOverlap == null && - settings.mapShowOverlaps && - !_isBuildingPathTrace) { + if (contact.type == advTypeChat && _isBuildingPathTrace) { addContact = false; } + if (settings.mapShowOverlaps) { + final hasOverlap = contacts + .where( + (c) => + c.publicKeyHex != contact.publicKeyHex && + c.publicKey.first == contact.publicKey.first && + (c.type == advTypeRepeater || c.type == advTypeRoom) && + (contact.type == advTypeRepeater || + contact.type == advTypeRoom), + ) + .firstOrNull; + + if (hasOverlap == null && + settings.mapShowOverlaps && + !_isBuildingPathTrace) { + addContact = false; + } + } + if (addContact) { filtered.add(contact); } @@ -2121,12 +2137,18 @@ class _MapScreenState extends State { } } - void _addToPath(BuildContext context, Contact contact) { + void _addToPath(BuildContext context, Contact contact, {LatLng? position}) { setState(() { _pathTrace.add( contact.publicKey[0], ); // Add first 16 bytes of public key to path trace - _points.add(LatLng(contact.latitude!, contact.longitude!)); + _pathTraceContacts.add( + contact.copyWith( + latitude: position?.latitude ?? contact.latitude, + longitude: position?.longitude ?? contact.longitude, + ), + ); // Add contact to path trace contacts + _points.add(position ?? LatLng(contact.latitude!, contact.longitude!)); }); } @@ -2134,6 +2156,7 @@ class _MapScreenState extends State { setState(() { _isBuildingPathTrace = true; _pathTrace.clear(); + _pathTraceContacts.clear(); _points.clear(); _polylines.clear(); _points.add(position); @@ -2142,6 +2165,7 @@ class _MapScreenState extends State { void _removePath() { setState(() { + _pathTraceContacts.removeLast(); _pathTrace.removeLast(); // Remove last node from path trace _points.removeLast(); // Remove last point from points list _polylines.clear(); // Clear polylines @@ -2201,6 +2225,7 @@ class _MapScreenState extends State { title: l10n.contacts_pathTrace, path: Uint8List.fromList(_pathTrace), pathHashByteWidth: hashW, + pathContacts: _pathTraceContacts, ), ), ); diff --git a/lib/screens/path_trace_map.dart b/lib/screens/path_trace_map.dart index 5b02931..7f3b4eb 100644 --- a/lib/screens/path_trace_map.dart +++ b/lib/screens/path_trace_map.dart @@ -56,6 +56,7 @@ class PathTraceMapScreen extends StatefulWidget { final bool reversePathAround; final Contact? targetContact; final int pathHashByteWidth; + final List? pathContacts; const PathTraceMapScreen({ super.key, @@ -66,6 +67,7 @@ class PathTraceMapScreen extends StatefulWidget { this.reversePathAround = false, this.targetContact, this.pathHashByteWidth = pathHashSize, + this.pathContacts, }); @override @@ -74,6 +76,8 @@ class PathTraceMapScreen extends StatefulWidget { class _PathTraceMapScreenState extends State { static const double _labelZoomThreshold = 8.5; + //miles to meters conversion for filtering out repeaters that are too far from the last known GPS hop to be a likely match, to avoid false matches that throw off the inferred positions of other hops in the path + static const double _maxRepeaterMatchDistanceMeters = 40 * 1609.344; StreamSubscription? _frameSubscription; Timer? _timeoutTimer; @@ -266,17 +270,43 @@ class _PathTraceMapScreenState extends State { .toList(); Map pathContacts = {}; - final contacts = connector.allContacts; - contacts.where((c) => c.type != advTypeChat).forEach((repeater) { - for (var repeaterData in pathData) { - if (listEquals( - repeater.publicKey.sublist(0, 1), - Uint8List.fromList([repeaterData]), - )) { - pathContacts[repeaterData] = repeater; + Contact lastContact = Contact( + path: Uint8List(0), + pathLength: 0, + publicKey: connector.selfPublicKey ?? Uint8List(0), + name: context.l10n.pathTrace_you, + type: advTypeChat, + latitude: connector.selfLatitude, + longitude: connector.selfLongitude, + lastSeen: DateTime.now(), + ); + if (widget.pathContacts != null) { + pathContacts = {for (var c in widget.pathContacts!) c.publicKey[0]: c}; + } else { + final contacts = connector.allContactsUnfiltered; + contacts.where((c) => c.type != advTypeChat).forEach((repeater) { + if (lastContact.latitude != null && + lastContact.longitude != null && + repeater.hasLocation && + lastContact.hasLocation && + Distance().distance( + LatLng(lastContact.latitude!, lastContact.longitude!), + LatLng(repeater.latitude!, repeater.longitude!), + ) > + _maxRepeaterMatchDistanceMeters) { + return; //skip reapeaters that are far away from the last one with known GPS, to avoid false matches } - } - }); + for (var repeaterData in pathData) { + if (listEquals( + repeater.publicKey.sublist(0, 1), + Uint8List.fromList([repeaterData]), + )) { + pathContacts[repeaterData] = repeater; + lastContact = repeater; + } + } + }); + } // For hops with no GPS contact, infer position from other contacts // with known GPS that share the same last-hop byte. diff --git a/lib/screens/repeater_cli_screen.dart b/lib/screens/repeater_cli_screen.dart index 52d92aa..5f76828 100644 --- a/lib/screens/repeater_cli_screen.dart +++ b/lib/screens/repeater_cli_screen.dart @@ -35,13 +35,15 @@ class _RepeaterCliScreenState extends State { // Common commands for quick access late final List> _quickCommands = [ + {'labelKey': 'advertise', 'command': 'advert'}, {'labelKey': 'getName', 'command': 'get name'}, {'labelKey': 'getRadio', 'command': 'get radio'}, {'labelKey': 'getTx', 'command': 'get tx'}, + {'labelKey': 'discovery', 'command': 'discover.neighbors'}, {'labelKey': 'neighbors', 'command': 'neighbors'}, {'labelKey': 'version', 'command': 'ver'}, - {'labelKey': 'advertise', 'command': 'advert'}, {'labelKey': 'clock', 'command': 'clock'}, + {'labelKey': 'clock sync', 'command': 'clock sync'}, ]; @override @@ -407,6 +409,10 @@ class _RepeaterCliScreenState extends State { return l10n.repeater_cliQuickAdvertise; case 'clock': return l10n.repeater_cliQuickClock; + case 'clock sync': + return l10n.repeater_cliQuickClockSync; + case 'discovery': + return l10n.repeater_cliQuickDiscovery; default: return key; } diff --git a/lib/utils/gpx_export.dart b/lib/utils/gpx_export.dart index b0165bd..296cc3a 100644 --- a/lib/utils/gpx_export.dart +++ b/lib/utils/gpx_export.dart @@ -14,12 +14,13 @@ class ContactExport { final double lon; final String desc; final double? ele; - + final String url; ContactExport({ required this.name, required this.lat, required this.lon, required this.desc, + required this.url, this.ele, }); } @@ -40,6 +41,7 @@ class GpxExport { String name, double lat, double lon, + String url, String desc, [ double? ele, ]) { @@ -50,55 +52,66 @@ class GpxExport { lon: lon, desc: desc.trim(), ele: ele, + url: url, ), ); } void addRepeaters() { - final contacts = _connector.contacts - .where((c) => c.type == advTypeRepeater || c.type == advTypeRoom) - .toList(); + final contacts = _connector.allContacts.where( + (c) => c.type == advTypeRepeater || c.type == advTypeRoom, + ); for (var contact in contacts) { if (contact.latitude == null || contact.longitude == null) { continue; } + final url = contact.rawPacket != null + ? "meshcore://${pubKeyToHex(contact.rawPacket!)}" + : ""; _addContact( contact.name, contact.latitude!, contact.longitude!, "Type: ${contact.typeLabel}\nPublic Key: ${contact.publicKeyHex}", + url, ); } } void addContacts() { - final contacts = _connector.contacts - .where((c) => c.type == advTypeChat) - .toList(); + final contacts = _connector.allContacts.where((c) => c.type == advTypeChat); for (var contact in contacts) { if (contact.latitude == null || contact.longitude == null) { continue; } + final url = contact.rawPacket != null + ? "meshcore://${pubKeyToHex(contact.rawPacket!)}" + : ""; _addContact( contact.name, contact.latitude!, contact.longitude!, "Type: ${contact.typeLabel}\nPublic Key: ${contact.publicKeyHex}", + url, ); } } void addAll() { - final contacts = _connector.contacts; - for (var contact in contacts.toList()) { + final contacts = _connector.allContacts; + for (var contact in contacts) { if (contact.latitude == null || contact.longitude == null) { continue; } + final url = contact.rawPacket != null + ? "meshcore://${pubKeyToHex(contact.rawPacket!)}" + : ""; _addContact( contact.name, contact.latitude ?? 0.0, contact.longitude ?? 0.0, "Type: ${contact.typeLabel}\nPublic Key: ${contact.publicKeyHex}", + url, ); } } @@ -138,6 +151,9 @@ class GpxExport { ele: c.ele, name: c.name, desc: c.desc, + extensions: { + "meshcore": {"url": c.url}, + }, ), ) .toList(); diff --git a/lib/widgets/repeater_login_dialog.dart b/lib/widgets/repeater_login_dialog.dart index ce6c2b7..48bb6ac 100644 --- a/lib/widgets/repeater_login_dialog.dart +++ b/lib/widgets/repeater_login_dialog.dart @@ -113,7 +113,7 @@ class _RepeaterLoginDialogState extends State { messageBytes: responseBytes, ); final timeoutSeconds = (timeoutMs / 1000).ceil(); - final timeout = Duration(milliseconds: timeoutMs); + final timeout = Duration(milliseconds: timeoutMs + 2000); final selectionLabel = selection.useFlood ? 'flood' : '${selection.hopCount} hops'; diff --git a/lib/widgets/room_login_dialog.dart b/lib/widgets/room_login_dialog.dart index 91d2c8c..3a923fe 100644 --- a/lib/widgets/room_login_dialog.dart +++ b/lib/widgets/room_login_dialog.dart @@ -108,7 +108,7 @@ class _RoomLoginDialogState extends State { messageBytes: responseBytes, ); final timeoutSeconds = (timeoutMs / 1000).ceil(); - final timeout = Duration(milliseconds: timeoutMs); + final timeout = Duration(milliseconds: timeoutMs + 2000); final selectionLabel = selection.useFlood ? 'flood' : '${selection.hopCount} hops';