From 2d1160d992de1c845d7dbb13477b21c089fba59a Mon Sep 17 00:00:00 2001 From: just_stuff_tm <133525672+just-stuff-tm@users.noreply.github.com> Date: Mon, 2 Mar 2026 02:34:46 -0500 Subject: [PATCH] Enhance BLE connection handling and improve USB connection messaging - Wrapped BLE scan and connection methods in try-catch blocks to handle errors gracefully and provide debug output. - Added retry logic for service discovery on web platforms after transient disconnections. - Updated USB connection messages in multiple languages to reflect active support on Android and desktop platforms. - Improved loading indicators for contacts screen to show a spinner during data loading. --- .../meshcore/meshcore_open/MainActivity.kt | 59 +++++++++++++++- lib/connector/meshcore_connector.dart | 68 +++++++++++++++---- lib/l10n/app_bg.arb | 8 +-- lib/l10n/app_de.arb | 8 +-- lib/l10n/app_es.arb | 10 +-- lib/l10n/app_fr.arb | 10 +-- lib/l10n/app_it.arb | 8 +-- lib/l10n/app_localizations_bg.dart | 8 +-- lib/l10n/app_localizations_de.dart | 8 +-- lib/l10n/app_localizations_es.dart | 11 ++- lib/l10n/app_localizations_fr.dart | 11 ++- lib/l10n/app_localizations_it.dart | 8 +-- lib/l10n/app_localizations_nl.dart | 8 +-- lib/l10n/app_localizations_pl.dart | 8 +-- lib/l10n/app_localizations_pt.dart | 8 +-- lib/l10n/app_localizations_ru.dart | 11 ++- lib/l10n/app_localizations_sk.dart | 8 +-- lib/l10n/app_localizations_sl.dart | 10 +-- lib/l10n/app_localizations_sv.dart | 8 +-- lib/l10n/app_localizations_uk.dart | 9 ++- lib/l10n/app_localizations_zh.dart | 8 +-- lib/l10n/app_nl.arb | 8 +-- lib/l10n/app_pl.arb | 8 +-- lib/l10n/app_pt.arb | 8 +-- lib/l10n/app_ru.arb | 10 +-- lib/l10n/app_sk.arb | 8 +-- lib/l10n/app_sl.arb | 10 +-- lib/l10n/app_sv.arb | 8 +-- lib/l10n/app_uk.arb | 8 +-- lib/l10n/app_zh.arb | 8 +-- lib/screens/contacts_screen.dart | 9 ++- 31 files changed, 240 insertions(+), 140 deletions(-) diff --git a/android/app/src/main/kotlin/com/meshcore/meshcore_open/MainActivity.kt b/android/app/src/main/kotlin/com/meshcore/meshcore_open/MainActivity.kt index 11bca61..dec4e28 100644 --- a/android/app/src/main/kotlin/com/meshcore/meshcore_open/MainActivity.kt +++ b/android/app/src/main/kotlin/com/meshcore/meshcore_open/MainActivity.kt @@ -37,6 +37,7 @@ class MainActivity : FlutterActivity() { private var usbConnection: UsbDeviceConnection? = null private var usbPort: UsbSerialPort? = null private var ioManager: SerialInputOutputManager? = null + private var connectedDeviceName: String? = null private var pendingConnectResult: MethodChannel.Result? = null private var pendingConnectPortName: String? = null @@ -45,7 +46,19 @@ class MainActivity : FlutterActivity() { private val permissionReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { - if (intent?.action != usbPermissionAction) { + when (intent?.action) { + UsbManager.ACTION_USB_DEVICE_DETACHED -> { + handleUsbDetached(intent) + return + } + usbPermissionAction -> { + } + else -> { + return + } + } + + if (intent.action != usbPermissionAction) { return } @@ -116,12 +129,19 @@ class MainActivity : FlutterActivity() { override fun onDestroy() { closeUsbConnection() usbIoExecutor.shutdownNow() - unregisterReceiver(permissionReceiver) + try { + unregisterReceiver(permissionReceiver) + } catch (_: IllegalArgumentException) { + } super.onDestroy() } private fun registerUsbPermissionReceiver() { - val filter = IntentFilter(usbPermissionAction) + val filter = + IntentFilter().apply { + addAction(usbPermissionAction) + addAction(UsbManager.ACTION_USB_DEVICE_DETACHED) + } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { registerReceiver(permissionReceiver, filter, RECEIVER_NOT_EXPORTED) } else { @@ -256,6 +276,7 @@ class MainActivity : FlutterActivity() { usbConnection = connection usbPort = port + connectedDeviceName = device.deviceName ioManager = SerialInputOutputManager( @@ -311,6 +332,38 @@ class MainActivity : FlutterActivity() { } catch (_: Exception) { } usbConnection = null + connectedDeviceName = null + } + + private fun handleUsbDetached(intent: Intent) { + val detachedDevice = + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + intent.getParcelableExtra(UsbManager.EXTRA_DEVICE, UsbDevice::class.java) + } else { + @Suppress("DEPRECATION") + intent.getParcelableExtra(UsbManager.EXTRA_DEVICE) + } + + val detachedName = detachedDevice?.deviceName ?: return + + if (pendingConnectPortName == detachedName) { + pendingConnectResult?.error( + "usb_device_detached", + "USB device was removed before the connection completed", + null, + ) + pendingConnectResult = null + pendingConnectPortName = null + } + + if (connectedDeviceName == detachedName) { + closeUsbConnection() + eventSink?.error( + "usb_device_detached", + "USB device was disconnected", + null, + ) + } } private fun pendingIntentFlags(): Int { diff --git a/lib/connector/meshcore_connector.dart b/lib/connector/meshcore_connector.dart index 4b39068..9e0eff6 100644 --- a/lib/connector/meshcore_connector.dart +++ b/lib/connector/meshcore_connector.dart @@ -738,12 +738,18 @@ class MeshCoreConnector extends ChangeNotifier { notifyListeners(); }); - await FlutterBluePlus.startScan( - withKeywords: ["MeshCore-", "Whisper-"], - webOptionalServices: [Guid(MeshCoreUuids.service)], - timeout: timeout, - androidScanMode: AndroidScanMode.lowLatency, - ); + try { + await FlutterBluePlus.startScan( + withKeywords: ["MeshCore-", "Whisper-"], + webOptionalServices: [Guid(MeshCoreUuids.service)], + timeout: timeout, + androidScanMode: AndroidScanMode.lowLatency, + ); + } catch (error) { + debugPrint('[BLE Scan] Scan/picker failure: $error'); + _setState(MeshCoreConnectionState.disconnected); + rethrow; + } await Future.delayed(timeout); await stopScan(); @@ -791,17 +797,24 @@ class MeshCoreConnector extends ChangeNotifier { notifyListeners(); try { + final connectLabel = _deviceDisplayName ?? _deviceId; + debugPrint('[BLE Connect] Starting connect to $connectLabel'); _connectionSubscription = device.connectionState.listen((state) { if (state == BluetoothConnectionState.disconnected && isConnected) { _handleDisconnection(); } }); - await device.connect( - timeout: const Duration(seconds: 15), - mtu: null, - license: License.free, - ); + try { + await device.connect( + timeout: const Duration(seconds: 15), + mtu: null, + license: License.free, + ); + } catch (error) { + debugPrint('[BLE Connect] device.connect() failure: $error'); + rethrow; + } // Request larger MTU only on native platforms; web does not support it. if (!PlatformInfo.isWeb) { @@ -813,7 +826,27 @@ class MeshCoreConnector extends ChangeNotifier { } } - List services = await device.discoverServices(); + late final List services; + try { + services = await device.discoverServices(); + } catch (error) { + debugPrint('[BLE Connect] service discovery failure: $error'); + if (PlatformInfo.isWeb && + error.toString().contains('GATT Server is disconnected')) { + debugPrint( + '[BLE Connect] retrying service discovery after transient web disconnect', + ); + await Future.delayed(const Duration(milliseconds: 300)); + await device.connect( + timeout: const Duration(seconds: 15), + mtu: null, + license: License.free, + ); + services = await device.discoverServices(); + } else { + rethrow; + } + } BluetoothService? uartService; for (var service in services) { @@ -847,6 +880,7 @@ class MeshCoreConnector extends ChangeNotifier { try { await _txCharacteristic!.setNotifyValue(true); } catch (error) { + debugPrint('[BLE Connect] notify failure (web, ignored): $error'); debugPrint('Web setNotifyValue error (ignoring): $error'); } }()); @@ -861,6 +895,7 @@ class MeshCoreConnector extends ChangeNotifier { await _txCharacteristic!.setNotifyValue(true); notifySet = true; } catch (e) { + debugPrint('[BLE Connect] notify failure: $e'); debugPrint('setNotifyValue attempt ${attempt + 1}/3 failed: $e'); if (attempt == 2) rethrow; } @@ -1231,6 +1266,15 @@ class MeshCoreConnector extends ChangeNotifier { _selfInfoRetryTimer?.cancel(); if (PlatformInfo.isWeb && _activeTransport == MeshCoreTransportType.bluetooth) { + _selfInfoRetryTimer = Timer(const Duration(seconds: 10), () { + if (!isConnected || !_awaitingSelfInfo) { + return; + } + if (_isLoadingContacts || _isSyncingChannels || _channelSyncInFlight) { + return; + } + unawaited(sendFrame(buildAppStartFrame())); + }); return; } _selfInfoRetryTimer = Timer.periodic(const Duration(milliseconds: 3500), ( diff --git a/lib/l10n/app_bg.arb b/lib/l10n/app_bg.arb index 0d64508..8c99338 100644 --- a/lib/l10n/app_bg.arb +++ b/lib/l10n/app_bg.arb @@ -1806,9 +1806,9 @@ "connectionChoiceBluetoothLabel": "Bluetooth", "connectionChoiceTitle": "Изберете метода на връзка.", "connectionChoiceSubtitle": "Изберете как искате да получите вашия устройство MeshCore.", - "usbScreenTitle": "Връзката чрез USB ще бъде налична скоро.", - "usbScreenSubtitle": "Създаваме път за комуникация, базиран на последователно предаване на данни, за Android и настолни компютри.", - "usbScreenStatus": "Ще бъде достъпно скоро", - "usbScreenNote": "След като бъде внедрена поддръжката за USB, ще изберете сериен порт и ще се свържете директно към вашето устройство MeshCore.", + "usbScreenNote": "USB серийната връзка е активна на поддържаните Android устройства и настолни платформи.", + "usbScreenStatus": "Изберете USB устройство", + "usbScreenTitle": "Свързване чрез USB", + "usbScreenSubtitle": "Изберете открития сериен уред и свържете директно към вашия MeshCore възел.", "usbScreenEmptyState": "Няма открити USB устройства. Включете едно и опитайте отново." } diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 0c49f8d..44eca06 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -1834,9 +1834,9 @@ "connectionChoiceUsbLabel": "USB", "connectionChoiceBluetoothLabel": "Bluetooth", "connectionChoiceTitle": "Wählen Sie Ihre bevorzugte Verbindungsmethode.", - "usbScreenTitle": "Die USB-Verbindung wird bald verfügbar sein.", - "usbScreenSubtitle": "Wir entwickeln eine Verbindung, die sowohl für Android- als auch für Desktop-Geräte geeignet ist und auf einer seriellen Schnittstelle basiert.", - "usbScreenStatus": "Bald verfügbar", - "usbScreenNote": "Sobald die USB-Unterstützung implementiert ist, wählen Sie einen seriellen Anschluss und verbinden Sie ihn direkt mit Ihrem MeshCore-Gerät.", + "usbScreenSubtitle": "Wählen Sie ein erkannten serielles Gerät aus und verbinden Sie es direkt mit Ihrem MeshCore-Knoten.", + "usbScreenNote": "USB-Serielle Schnittstelle ist auf unterstützten Android-Geräten und Desktop-Plattformen aktiv.", + "usbScreenTitle": "Über USB verbinden", + "usbScreenStatus": "Wählen Sie ein USB-Gerät aus", "usbScreenEmptyState": "Keine USB-Geräte gefunden. Schließen Sie eines an und aktualisieren Sie." } diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 48431e3..a69503a 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -1834,9 +1834,9 @@ "connectionChoiceSubtitle": "Seleccione la forma en que desea acceder a su dispositivo MeshCore.", "connectionChoiceBluetoothLabel": "Bluetooth", "connectionChoiceUsbLabel": "USB", - "usbScreenTitle": "La conexión USB estará disponible próximamente.", - "usbScreenSubtitle": "Estamos creando una conexión en serie para dispositivos Android y de escritorio.", - "usbScreenStatus": "Próximamente", - "usbScreenNote": "Una vez que se implemente el soporte para USB, seleccionará un puerto serie y se conectará directamente a su dispositivo MeshCore.", - "usbScreenEmptyState": "No se detectaron dispositivos USB. Conecte uno y vuelva a intentar." + "usbScreenStatus": "Seleccione un dispositivo USB", + "usbScreenNote": "La comunicación serial a través de USB está activa en dispositivos Android compatibles y en plataformas de escritorio.", + "usbScreenTitle": "Conecte mediante USB", + "usbScreenSubtitle": "Seleccione un dispositivo de serie detectado y conéctelo directamente a su nodo MeshCore.", + "usbScreenEmptyState": "No se encontraron dispositivos USB. Conecte uno y vuelva a cargar." } diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index 61f6551..2e22ee5 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -1806,9 +1806,9 @@ "connectionChoiceBluetoothLabel": "Bluetooth", "connectionChoiceUsbLabel": "USB", "connectionChoiceSubtitle": "Choisissez la méthode de livraison que vous préférez pour votre appareil MeshCore.", - "usbScreenTitle": "La connexion USB sera disponible prochainement.", - "usbScreenSubtitle": "Nous mettons en place un chemin de connexion basé sur une série pour les appareils Android et les ordinateurs de bureau.", - "usbScreenStatus": "Bientôt", - "usbScreenNote": "Une fois que le support USB sera disponible, vous sélectionnerez un port série et vous connecterez directement à votre appareil MeshCore.", - "usbScreenEmptyState": "Aucun périphérique USB n'a été trouvé. Connectez-en un et rafraîchissez." + "usbScreenStatus": "Sélectionnez un périphérique USB", + "usbScreenSubtitle": "Sélectionnez un périphérique série détecté et connectez-vous directement à votre nœud MeshCore.", + "usbScreenNote": "La communication série USB est active sur les appareils Android et les plateformes de bureau pris en charge.", + "usbScreenTitle": "Connectez via USB", + "usbScreenEmptyState": "Aucun périphérique USB n'a été trouvé. Veuillez connecter un périphérique et rafraîchir la page." } diff --git a/lib/l10n/app_it.arb b/lib/l10n/app_it.arb index 827d1e7..14c37fa 100644 --- a/lib/l10n/app_it.arb +++ b/lib/l10n/app_it.arb @@ -1806,9 +1806,9 @@ "connectionChoiceSubtitle": "Seleziona il metodo che preferisci per accedere al tuo dispositivo MeshCore.", "connectionChoiceBluetoothLabel": "Bluetooth", "connectionChoiceUsbLabel": "USB", - "usbScreenTitle": "La connessione USB sarà disponibile a breve.", - "usbScreenSubtitle": "Stiamo sviluppando un percorso di connessione basato su serie per Android e per i desktop.", - "usbScreenStatus": "Arriverà presto", - "usbScreenNote": "Una volta che il supporto USB sarà disponibile, selezionerete una porta seriale e vi connetterete direttamente al vostro dispositivo MeshCore.", + "usbScreenNote": "La comunicazione seriale USB è attiva sui dispositivi Android supportati e sulle piattaforme desktop.", + "usbScreenStatus": "Seleziona un dispositivo USB", + "usbScreenSubtitle": "Seleziona il dispositivo seriale rilevato e connettilo direttamente al tuo nodo MeshCore.", + "usbScreenTitle": "Connessione tramite USB", "usbScreenEmptyState": "Nessun dispositivo USB rilevato. Collegare uno e riavviare." } diff --git a/lib/l10n/app_localizations_bg.dart b/lib/l10n/app_localizations_bg.dart index 861bf6a..4eeedae 100644 --- a/lib/l10n/app_localizations_bg.dart +++ b/lib/l10n/app_localizations_bg.dart @@ -122,18 +122,18 @@ class AppLocalizationsBg extends AppLocalizations { String get connectionChoiceBluetoothLabel => 'Bluetooth'; @override - String get usbScreenTitle => 'Връзката чрез USB ще бъде налична скоро.'; + String get usbScreenTitle => 'Свързване чрез USB'; @override String get usbScreenSubtitle => - 'Създаваме път за комуникация, базиран на последователно предаване на данни, за Android и настолни компютри.'; + 'Изберете открития сериен уред и свържете директно към вашия MeshCore възел.'; @override - String get usbScreenStatus => 'Ще бъде достъпно скоро'; + String get usbScreenStatus => 'Изберете USB устройство'; @override String get usbScreenNote => - 'След като бъде внедрена поддръжката за USB, ще изберете сериен порт и ще се свържете директно към вашето устройство MeshCore.'; + 'USB серийната връзка е активна на поддържаните Android устройства и настолни платформи.'; @override String get usbScreenEmptyState => diff --git a/lib/l10n/app_localizations_de.dart b/lib/l10n/app_localizations_de.dart index f768dbb..a3ab54d 100644 --- a/lib/l10n/app_localizations_de.dart +++ b/lib/l10n/app_localizations_de.dart @@ -123,18 +123,18 @@ class AppLocalizationsDe extends AppLocalizations { String get connectionChoiceBluetoothLabel => 'Bluetooth'; @override - String get usbScreenTitle => 'Die USB-Verbindung wird bald verfügbar sein.'; + String get usbScreenTitle => 'Über USB verbinden'; @override String get usbScreenSubtitle => - 'Wir entwickeln eine Verbindung, die sowohl für Android- als auch für Desktop-Geräte geeignet ist und auf einer seriellen Schnittstelle basiert.'; + 'Wählen Sie ein erkannten serielles Gerät aus und verbinden Sie es direkt mit Ihrem MeshCore-Knoten.'; @override - String get usbScreenStatus => 'Bald verfügbar'; + String get usbScreenStatus => 'Wählen Sie ein USB-Gerät aus'; @override String get usbScreenNote => - 'Sobald die USB-Unterstützung implementiert ist, wählen Sie einen seriellen Anschluss und verbinden Sie ihn direkt mit Ihrem MeshCore-Gerät.'; + 'USB-Serielle Schnittstelle ist auf unterstützten Android-Geräten und Desktop-Plattformen aktiv.'; @override String get usbScreenEmptyState => diff --git a/lib/l10n/app_localizations_es.dart b/lib/l10n/app_localizations_es.dart index 32680ab..cc7261a 100644 --- a/lib/l10n/app_localizations_es.dart +++ b/lib/l10n/app_localizations_es.dart @@ -122,23 +122,22 @@ class AppLocalizationsEs extends AppLocalizations { String get connectionChoiceBluetoothLabel => 'Bluetooth'; @override - String get usbScreenTitle => - 'La conexión USB estará disponible próximamente.'; + String get usbScreenTitle => 'Conecte mediante USB'; @override String get usbScreenSubtitle => - 'Estamos creando una conexión en serie para dispositivos Android y de escritorio.'; + 'Seleccione un dispositivo de serie detectado y conéctelo directamente a su nodo MeshCore.'; @override - String get usbScreenStatus => 'Próximamente'; + String get usbScreenStatus => 'Seleccione un dispositivo USB'; @override String get usbScreenNote => - 'Una vez que se implemente el soporte para USB, seleccionará un puerto serie y se conectará directamente a su dispositivo MeshCore.'; + 'La comunicación serial a través de USB está activa en dispositivos Android compatibles y en plataformas de escritorio.'; @override String get usbScreenEmptyState => - 'No se detectaron dispositivos USB. Conecte uno y vuelva a intentar.'; + 'No se encontraron dispositivos USB. Conecte uno y vuelva a cargar.'; @override String get scanner_scanning => 'Escaneando dispositivos...'; diff --git a/lib/l10n/app_localizations_fr.dart b/lib/l10n/app_localizations_fr.dart index dae3478..5f7d70f 100644 --- a/lib/l10n/app_localizations_fr.dart +++ b/lib/l10n/app_localizations_fr.dart @@ -122,23 +122,22 @@ class AppLocalizationsFr extends AppLocalizations { String get connectionChoiceBluetoothLabel => 'Bluetooth'; @override - String get usbScreenTitle => - 'La connexion USB sera disponible prochainement.'; + String get usbScreenTitle => 'Connectez via USB'; @override String get usbScreenSubtitle => - 'Nous mettons en place un chemin de connexion basé sur une série pour les appareils Android et les ordinateurs de bureau.'; + 'Sélectionnez un périphérique série détecté et connectez-vous directement à votre nœud MeshCore.'; @override - String get usbScreenStatus => 'Bientôt'; + String get usbScreenStatus => 'Sélectionnez un périphérique USB'; @override String get usbScreenNote => - 'Une fois que le support USB sera disponible, vous sélectionnerez un port série et vous connecterez directement à votre appareil MeshCore.'; + 'La communication série USB est active sur les appareils Android et les plateformes de bureau pris en charge.'; @override String get usbScreenEmptyState => - 'Aucun périphérique USB n\'a été trouvé. Connectez-en un et rafraîchissez.'; + 'Aucun périphérique USB n\'a été trouvé. Veuillez connecter un périphérique et rafraîchir la page.'; @override String get scanner_scanning => 'Recherche de périphériques...'; diff --git a/lib/l10n/app_localizations_it.dart b/lib/l10n/app_localizations_it.dart index b138671..aef53e1 100644 --- a/lib/l10n/app_localizations_it.dart +++ b/lib/l10n/app_localizations_it.dart @@ -123,18 +123,18 @@ class AppLocalizationsIt extends AppLocalizations { String get connectionChoiceBluetoothLabel => 'Bluetooth'; @override - String get usbScreenTitle => 'La connessione USB sarà disponibile a breve.'; + String get usbScreenTitle => 'Connessione tramite USB'; @override String get usbScreenSubtitle => - 'Stiamo sviluppando un percorso di connessione basato su serie per Android e per i desktop.'; + 'Seleziona il dispositivo seriale rilevato e connettilo direttamente al tuo nodo MeshCore.'; @override - String get usbScreenStatus => 'Arriverà presto'; + String get usbScreenStatus => 'Seleziona un dispositivo USB'; @override String get usbScreenNote => - 'Una volta che il supporto USB sarà disponibile, selezionerete una porta seriale e vi connetterete direttamente al vostro dispositivo MeshCore.'; + 'La comunicazione seriale USB è attiva sui dispositivi Android supportati e sulle piattaforme desktop.'; @override String get usbScreenEmptyState => diff --git a/lib/l10n/app_localizations_nl.dart b/lib/l10n/app_localizations_nl.dart index f582abc..b1c3452 100644 --- a/lib/l10n/app_localizations_nl.dart +++ b/lib/l10n/app_localizations_nl.dart @@ -122,18 +122,18 @@ class AppLocalizationsNl extends AppLocalizations { String get connectionChoiceBluetoothLabel => 'Bluetooth'; @override - String get usbScreenTitle => 'USB-verbinding is binnenkort beschikbaar.'; + String get usbScreenTitle => 'Verbind via USB'; @override String get usbScreenSubtitle => - 'We ontwikkelen een verbindingspad op basis van seriële communicatie, zowel voor Android als voor desktop-computers.'; + 'Kies een gedetecteerd seriële apparaat en verbind deze direct met uw MeshCore-node.'; @override - String get usbScreenStatus => 'Komende week'; + String get usbScreenStatus => 'Selecteer een USB-apparaat'; @override String get usbScreenNote => - 'Zodra de USB-ondersteuning is geïnstalleerd, selecteert u een seriële poort en verbindt u direct met uw MeshCore-apparaat.'; + 'USB-serieel is actief op ondersteunde Android-apparaten en desktop-platforms.'; @override String get usbScreenEmptyState => diff --git a/lib/l10n/app_localizations_pl.dart b/lib/l10n/app_localizations_pl.dart index 2f103b5..5b1712f 100644 --- a/lib/l10n/app_localizations_pl.dart +++ b/lib/l10n/app_localizations_pl.dart @@ -122,18 +122,18 @@ class AppLocalizationsPl extends AppLocalizations { String get connectionChoiceBluetoothLabel => 'Bluetooth'; @override - String get usbScreenTitle => 'Połączenie USB będzie dostępne wkrótce.'; + String get usbScreenTitle => 'Połącz przez USB'; @override String get usbScreenSubtitle => - 'Tworzymy ścieżkę połączenia opartą na protokole szeregowym, przeznaczoną zarówno dla urządzeń z systemem Android, jak i dla komputerów stacjonarnych.'; + 'Wybierz wykryty urządzenie szeregowe i podłącz je bezpośrednio do swojego węzła MeshCore.'; @override - String get usbScreenStatus => 'Wkrótce'; + String get usbScreenStatus => 'Wybierz urządzenie USB'; @override String get usbScreenNote => - 'Po wdrożeniu wsparcia dla USB, wybierzesz port szeregowy i połączysz się bezpośrednio z urządzeniem MeshCore.'; + 'Port szeregowy USB jest aktywny na urządzeniach z Androidem i platformach stacjonarnych, które obsługują tę funkcję.'; @override String get usbScreenEmptyState => diff --git a/lib/l10n/app_localizations_pt.dart b/lib/l10n/app_localizations_pt.dart index 283bada..1bf5647 100644 --- a/lib/l10n/app_localizations_pt.dart +++ b/lib/l10n/app_localizations_pt.dart @@ -122,18 +122,18 @@ class AppLocalizationsPt extends AppLocalizations { String get connectionChoiceBluetoothLabel => 'Bluetooth'; @override - String get usbScreenTitle => 'A conexão USB estará disponível em breve.'; + String get usbScreenTitle => 'Conecte via USB'; @override String get usbScreenSubtitle => - 'Estamos criando um caminho de conexão baseado em série para dispositivos Android e de desktop.'; + 'Selecione o dispositivo serial detectado e conecte-o diretamente ao seu nó MeshCore.'; @override - String get usbScreenStatus => 'Em breve'; + String get usbScreenStatus => 'Selecione um dispositivo USB'; @override String get usbScreenNote => - 'Assim que o suporte USB for implementado, você poderá selecionar uma porta serial e conectar-se diretamente ao seu dispositivo MeshCore.'; + 'A comunicação serial USB está ativa em dispositivos Android e plataformas de desktop compatíveis.'; @override String get usbScreenEmptyState => diff --git a/lib/l10n/app_localizations_ru.dart b/lib/l10n/app_localizations_ru.dart index 1687782..6a25aa2 100644 --- a/lib/l10n/app_localizations_ru.dart +++ b/lib/l10n/app_localizations_ru.dart @@ -122,23 +122,22 @@ class AppLocalizationsRu extends AppLocalizations { String get connectionChoiceBluetoothLabel => 'Bluetooth'; @override - String get usbScreenTitle => - 'Подключение через USB будет доступно в ближайшее время.'; + String get usbScreenTitle => 'Подключение через USB'; @override String get usbScreenSubtitle => - 'Мы создаем последовательную схему подключения для устройств на базе Android и настольных компьютеров.'; + 'Выберите обнаруженное устройство с последовательным интерфейсом и подключите его напрямую к вашему узлу MeshCore.'; @override - String get usbScreenStatus => 'Скоро'; + String get usbScreenStatus => 'Выберите USB-устройство'; @override String get usbScreenNote => - 'Как только появится поддержка USB, вы сможете выбрать последовательный порт и напрямую подключиться к вашему устройству MeshCore.'; + 'USB-серийный порт активен на поддерживаемых устройствах Android и на настольных платформах.'; @override String get usbScreenEmptyState => - 'Не обнаружено никаких устройств USB. Подключите одно из них и обновите список.'; + 'Не обнаружено устройств USB. Подключите одно из них и обновите список.'; @override String get scanner_scanning => 'Поиск устройств...'; diff --git a/lib/l10n/app_localizations_sk.dart b/lib/l10n/app_localizations_sk.dart index 8949090..a120a7d 100644 --- a/lib/l10n/app_localizations_sk.dart +++ b/lib/l10n/app_localizations_sk.dart @@ -122,18 +122,18 @@ class AppLocalizationsSk extends AppLocalizations { String get connectionChoiceBluetoothLabel => 'Bluetooth'; @override - String get usbScreenTitle => 'Pripojenie cez USB bude k dispozícii čoskoro.'; + String get usbScreenTitle => 'Pripojte cez USB'; @override String get usbScreenSubtitle => - 'Vytvárajeme komunikačný systém založený na sériovej komunikácii pre Android a stolné počítače.'; + 'Vyberte detekovaný sériový zariadenie a pripojte ho priamo k vašej MeshCore uzlu.'; @override - String get usbScreenStatus => 'Čoskoro'; + String get usbScreenStatus => 'Vyberte USB zariadenie'; @override String get usbScreenNote => - 'Po implementácii podpory pre USB, budete môcť vybrať sériový port a priamo sa pripojiť k vašmu zariadeniu MeshCore.'; + 'USB sériová komunikácia je aktívna na podporovaných zariadeniach s Androidom a na desktopových platformách.'; @override String get usbScreenEmptyState => diff --git a/lib/l10n/app_localizations_sl.dart b/lib/l10n/app_localizations_sl.dart index bd0c4d5..8969898 100644 --- a/lib/l10n/app_localizations_sl.dart +++ b/lib/l10n/app_localizations_sl.dart @@ -122,22 +122,22 @@ class AppLocalizationsSl extends AppLocalizations { String get connectionChoiceBluetoothLabel => 'Bluetooth'; @override - String get usbScreenTitle => 'Vnos preko USB-ja bo v kratkem na voljo.'; + String get usbScreenTitle => 'Povežite preko USB'; @override String get usbScreenSubtitle => - 'Gradimo pot za serijsko povezavo za Android in računalnike.'; + 'Izberite zaznano serijsko napravo in se neposredno povežite z vašim MeshCore-om.'; @override - String get usbScreenStatus => 'Čez kratko časa'; + String get usbScreenStatus => 'Izberite USB naprave.'; @override String get usbScreenNote => - 'Ko bo podpora za USB na voljo, boste izbrali serijsko vrata in se neposredno povezali z vašim napravem MeshCore.'; + 'USB serijska povezava je aktivna na podprtih napravah Android in na desktop platformah.'; @override String get usbScreenEmptyState => - 'Niti en USB naprave niso bilo najdeno. Povežite eno in posodobite.'; + 'Niti en USB naprave niso najdeni. Povežite eno in posodobite.'; @override String get scanner_scanning => 'Skeniram za naprave...'; diff --git a/lib/l10n/app_localizations_sv.dart b/lib/l10n/app_localizations_sv.dart index 183250d..2cd731b 100644 --- a/lib/l10n/app_localizations_sv.dart +++ b/lib/l10n/app_localizations_sv.dart @@ -122,18 +122,18 @@ class AppLocalizationsSv extends AppLocalizations { String get connectionChoiceBluetoothLabel => 'Bluetooth'; @override - String get usbScreenTitle => 'USB-anslutning kommer snart'; + String get usbScreenTitle => 'Anslut via USB'; @override String get usbScreenSubtitle => - 'Vi skapar en seriebaserad anslutningsväg för både Android- och skrivbordsenheter.'; + 'Välj en detekterad seriell enhet och anslut direkt till din MeshCore-nod.'; @override - String get usbScreenStatus => 'Kommer snart'; + String get usbScreenStatus => 'Välj en USB-enhet'; @override String get usbScreenNote => - 'När USB-stöd är implementerat, kommer du att välja en seriell port och ansluta direkt till din MeshCore-enhet.'; + 'USB-seriell kommunikation är aktiv på stöderliga Android-enheter och skrivbordsplattformar.'; @override String get usbScreenEmptyState => diff --git a/lib/l10n/app_localizations_uk.dart b/lib/l10n/app_localizations_uk.dart index 19feaac..08c2c0f 100644 --- a/lib/l10n/app_localizations_uk.dart +++ b/lib/l10n/app_localizations_uk.dart @@ -122,19 +122,18 @@ class AppLocalizationsUk extends AppLocalizations { String get connectionChoiceBluetoothLabel => 'Bluetooth'; @override - String get usbScreenTitle => - 'Підключення через USB буде доступне найближчим часом.'; + String get usbScreenTitle => 'Підключити через USB'; @override String get usbScreenSubtitle => - 'Ми створюємо серійний шлях з\'єднання для Android та десктопних комп\'ютерів.'; + 'Виберіть виявлене серійне пристрій і підключіть його безпосередньо до вашого вузла MeshCore.'; @override - String get usbScreenStatus => 'Скоро'; + String get usbScreenStatus => 'Виберіть пристрій USB'; @override String get usbScreenNote => - 'Після того, як буде реалізовано підтримку USB, ви виберете серійний порт і підключитесь безпосередньо до вашого пристрою MeshCore.'; + 'USB-серіальний інтерфейс активний на підтримуваних пристроях на базі Android та на десктопних платформах.'; @override String get usbScreenEmptyState => diff --git a/lib/l10n/app_localizations_zh.dart b/lib/l10n/app_localizations_zh.dart index fdb9f1d..678c63b 100644 --- a/lib/l10n/app_localizations_zh.dart +++ b/lib/l10n/app_localizations_zh.dart @@ -121,16 +121,16 @@ class AppLocalizationsZh extends AppLocalizations { String get connectionChoiceBluetoothLabel => '蓝牙'; @override - String get usbScreenTitle => 'USB 连接即将推出'; + String get usbScreenTitle => '通过USB连接'; @override - String get usbScreenSubtitle => '我们正在构建一个基于串行的连接路径,用于Android和桌面设备。'; + String get usbScreenSubtitle => '选择已检测到的串行设备,并直接连接到您的 MeshCore 节点。'; @override - String get usbScreenStatus => '即将推出'; + String get usbScreenStatus => '选择一个 USB 设备'; @override - String get usbScreenNote => '一旦USB支持功能上线,您就可以选择一个串口,并直接连接到您的MeshCore设备。'; + String get usbScreenNote => '在支持的 Android 设备和桌面平台上,USB 串行通信功能已启用。'; @override String get usbScreenEmptyState => '未找到任何 USB 设备。请插入一个,然后刷新。'; diff --git a/lib/l10n/app_nl.arb b/lib/l10n/app_nl.arb index 2f09405..338a3a2 100644 --- a/lib/l10n/app_nl.arb +++ b/lib/l10n/app_nl.arb @@ -1806,9 +1806,9 @@ "connectionChoiceUsbLabel": "USB", "connectionChoiceSubtitle": "Kies hoe u uw MeshCore-apparaat wilt bereiken.", "connectionChoiceBluetoothLabel": "Bluetooth", - "usbScreenTitle": "USB-verbinding is binnenkort beschikbaar.", - "usbScreenSubtitle": "We ontwikkelen een verbindingspad op basis van seriële communicatie, zowel voor Android als voor desktop-computers.", - "usbScreenStatus": "Komende week", - "usbScreenNote": "Zodra de USB-ondersteuning is geïnstalleerd, selecteert u een seriële poort en verbindt u direct met uw MeshCore-apparaat.", + "usbScreenSubtitle": "Kies een gedetecteerd seriële apparaat en verbind deze direct met uw MeshCore-node.", + "usbScreenStatus": "Selecteer een USB-apparaat", + "usbScreenNote": "USB-serieel is actief op ondersteunde Android-apparaten en desktop-platforms.", + "usbScreenTitle": "Verbind via USB", "usbScreenEmptyState": "Geen USB-apparaten gevonden. Sluit er een aan en herlaad." } diff --git a/lib/l10n/app_pl.arb b/lib/l10n/app_pl.arb index 8988e02..6b47ad5 100644 --- a/lib/l10n/app_pl.arb +++ b/lib/l10n/app_pl.arb @@ -1806,9 +1806,9 @@ "connectionChoiceSubtitle": "Wybierz, w jaki sposób chcesz uzyskać dostęp do swojego urządzenia MeshCore.", "connectionChoiceTitle": "Wybierz metodę połączenia.", "connectionChoiceUsbLabel": "USB", - "usbScreenTitle": "Połączenie USB będzie dostępne wkrótce.", - "usbScreenSubtitle": "Tworzymy ścieżkę połączenia opartą na protokole szeregowym, przeznaczoną zarówno dla urządzeń z systemem Android, jak i dla komputerów stacjonarnych.", - "usbScreenStatus": "Wkrótce", - "usbScreenNote": "Po wdrożeniu wsparcia dla USB, wybierzesz port szeregowy i połączysz się bezpośrednio z urządzeniem MeshCore.", + "usbScreenTitle": "Połącz przez USB", + "usbScreenNote": "Port szeregowy USB jest aktywny na urządzeniach z Androidem i platformach stacjonarnych, które obsługują tę funkcję.", + "usbScreenSubtitle": "Wybierz wykryty urządzenie szeregowe i podłącz je bezpośrednio do swojego węzła MeshCore.", + "usbScreenStatus": "Wybierz urządzenie USB", "usbScreenEmptyState": "Nie znaleziono żadnych urządzeń USB. Podłącz jedno i zaktualizuj." } diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index 296590f..d6d50e8 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -1806,9 +1806,9 @@ "connectionChoiceUsbLabel": "USB", "connectionChoiceBluetoothLabel": "Bluetooth", "connectionChoiceTitle": "Escolha o método de conexão desejado.", - "usbScreenTitle": "A conexão USB estará disponível em breve.", - "usbScreenSubtitle": "Estamos criando um caminho de conexão baseado em série para dispositivos Android e de desktop.", - "usbScreenStatus": "Em breve", - "usbScreenNote": "Assim que o suporte USB for implementado, você poderá selecionar uma porta serial e conectar-se diretamente ao seu dispositivo MeshCore.", + "usbScreenNote": "A comunicação serial USB está ativa em dispositivos Android e plataformas de desktop compatíveis.", + "usbScreenSubtitle": "Selecione o dispositivo serial detectado e conecte-o diretamente ao seu nó MeshCore.", + "usbScreenStatus": "Selecione um dispositivo USB", + "usbScreenTitle": "Conecte via USB", "usbScreenEmptyState": "Nenhum dispositivo USB encontrado. Conecte um e atualize." } diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb index 65b3792..2b8ab81 100644 --- a/lib/l10n/app_ru.arb +++ b/lib/l10n/app_ru.arb @@ -1046,9 +1046,9 @@ "connectionChoiceTitle": "Выберите способ подключения", "connectionChoiceUsbLabel": "USB", "connectionChoiceBluetoothLabel": "Bluetooth", - "usbScreenTitle": "Подключение через USB будет доступно в ближайшее время.", - "usbScreenSubtitle": "Мы создаем последовательную схему подключения для устройств на базе Android и настольных компьютеров.", - "usbScreenStatus": "Скоро", - "usbScreenNote": "Как только появится поддержка USB, вы сможете выбрать последовательный порт и напрямую подключиться к вашему устройству MeshCore.", - "usbScreenEmptyState": "Не обнаружено никаких устройств USB. Подключите одно из них и обновите список." + "usbScreenSubtitle": "Выберите обнаруженное устройство с последовательным интерфейсом и подключите его напрямую к вашему узлу MeshCore.", + "usbScreenNote": "USB-серийный порт активен на поддерживаемых устройствах Android и на настольных платформах.", + "usbScreenStatus": "Выберите USB-устройство", + "usbScreenTitle": "Подключение через USB", + "usbScreenEmptyState": "Не обнаружено устройств USB. Подключите одно из них и обновите список." } diff --git a/lib/l10n/app_sk.arb b/lib/l10n/app_sk.arb index 7178166..46fe7e7 100644 --- a/lib/l10n/app_sk.arb +++ b/lib/l10n/app_sk.arb @@ -1806,9 +1806,9 @@ "connectionChoiceUsbLabel": "USB", "connectionChoiceTitle": "Vyberte si metódu prepojenia.", "connectionChoiceSubtitle": "Vyberte si, ako chcete dosiahnuť váš zariadenie MeshCore.", - "usbScreenTitle": "Pripojenie cez USB bude k dispozícii čoskoro.", - "usbScreenSubtitle": "Vytvárajeme komunikačný systém založený na sériovej komunikácii pre Android a stolné počítače.", - "usbScreenStatus": "Čoskoro", - "usbScreenNote": "Po implementácii podpory pre USB, budete môcť vybrať sériový port a priamo sa pripojiť k vašmu zariadeniu MeshCore.", + "usbScreenStatus": "Vyberte USB zariadenie", + "usbScreenSubtitle": "Vyberte detekovaný sériový zariadenie a pripojte ho priamo k vašej MeshCore uzlu.", + "usbScreenNote": "USB sériová komunikácia je aktívna na podporovaných zariadeniach s Androidom a na desktopových platformách.", + "usbScreenTitle": "Pripojte cez USB", "usbScreenEmptyState": "Nenašli sa žiadne USB zariadenia. Pripojte jedno a obnovte." } diff --git a/lib/l10n/app_sl.arb b/lib/l10n/app_sl.arb index 416106a..1d8943e 100644 --- a/lib/l10n/app_sl.arb +++ b/lib/l10n/app_sl.arb @@ -1806,9 +1806,9 @@ "connectionChoiceUsbLabel": "USB", "connectionChoiceTitle": "Izberite svoj način povezave.", "connectionChoiceSubtitle": "Izberite, kako želite dostopati do svojega naprave MeshCore.", - "usbScreenTitle": "Vnos preko USB-ja bo v kratkem na voljo.", - "usbScreenSubtitle": "Gradimo pot za serijsko povezavo za Android in računalnike.", - "usbScreenStatus": "Čez kratko časa", - "usbScreenNote": "Ko bo podpora za USB na voljo, boste izbrali serijsko vrata in se neposredno povezali z vašim napravem MeshCore.", - "usbScreenEmptyState": "Niti en USB naprave niso bilo najdeno. Povežite eno in posodobite." + "usbScreenSubtitle": "Izberite zaznano serijsko napravo in se neposredno povežite z vašim MeshCore-om.", + "usbScreenTitle": "Povežite preko USB", + "usbScreenStatus": "Izberite USB naprave.", + "usbScreenNote": "USB serijska povezava je aktivna na podprtih napravah Android in na desktop platformah.", + "usbScreenEmptyState": "Niti en USB naprave niso najdeni. Povežite eno in posodobite." } diff --git a/lib/l10n/app_sv.arb b/lib/l10n/app_sv.arb index 9bbcd31..5a55bcb 100644 --- a/lib/l10n/app_sv.arb +++ b/lib/l10n/app_sv.arb @@ -1806,9 +1806,9 @@ "connectionChoiceBluetoothLabel": "Bluetooth", "connectionChoiceSubtitle": "Välj hur du vill komma åt din MeshCore-enhet.", "connectionChoiceTitle": "Välj din anslutningsmetod", - "usbScreenTitle": "USB-anslutning kommer snart", - "usbScreenSubtitle": "Vi skapar en seriebaserad anslutningsväg för både Android- och skrivbordsenheter.", - "usbScreenStatus": "Kommer snart", - "usbScreenNote": "När USB-stöd är implementerat, kommer du att välja en seriell port och ansluta direkt till din MeshCore-enhet.", + "usbScreenTitle": "Anslut via USB", + "usbScreenNote": "USB-seriell kommunikation är aktiv på stöderliga Android-enheter och skrivbordsplattformar.", + "usbScreenSubtitle": "Välj en detekterad seriell enhet och anslut direkt till din MeshCore-nod.", + "usbScreenStatus": "Välj en USB-enhet", "usbScreenEmptyState": "Inga USB-enheter hittades. Anslut en och uppdatera." } diff --git a/lib/l10n/app_uk.arb b/lib/l10n/app_uk.arb index 9a9919c..5b0bde5 100644 --- a/lib/l10n/app_uk.arb +++ b/lib/l10n/app_uk.arb @@ -1806,9 +1806,9 @@ "connectionChoiceUsbLabel": "USB", "connectionChoiceTitle": "Виберіть спосіб зв'язку", "connectionChoiceBluetoothLabel": "Bluetooth", - "usbScreenTitle": "Підключення через USB буде доступне найближчим часом.", - "usbScreenSubtitle": "Ми створюємо серійний шлях з'єднання для Android та десктопних комп'ютерів.", - "usbScreenStatus": "Скоро", - "usbScreenNote": "Після того, як буде реалізовано підтримку USB, ви виберете серійний порт і підключитесь безпосередньо до вашого пристрою MeshCore.", + "usbScreenSubtitle": "Виберіть виявлене серійне пристрій і підключіть його безпосередньо до вашого вузла MeshCore.", + "usbScreenTitle": "Підключити через USB", + "usbScreenStatus": "Виберіть пристрій USB", + "usbScreenNote": "USB-серіальний інтерфейс активний на підтримуваних пристроях на базі Android та на десктопних платформах.", "usbScreenEmptyState": "Не знайдено жодних пристроїв USB. Підключіть один і перезавантажте." } diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index 660b221..c35cbaa 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -1811,9 +1811,9 @@ "connectionChoiceBluetoothLabel": "蓝牙", "connectionChoiceTitle": "选择您的连接方式", "connectionChoiceUsbLabel": "USB", - "usbScreenTitle": "USB 连接即将推出", - "usbScreenSubtitle": "我们正在构建一个基于串行的连接路径,用于Android和桌面设备。", - "usbScreenStatus": "即将推出", - "usbScreenNote": "一旦USB支持功能上线,您就可以选择一个串口,并直接连接到您的MeshCore设备。", + "usbScreenTitle": "通过USB连接", + "usbScreenSubtitle": "选择已检测到的串行设备,并直接连接到您的 MeshCore 节点。", + "usbScreenStatus": "选择一个 USB 设备", + "usbScreenNote": "在支持的 Android 设备和桌面平台上,USB 串行通信功能已启用。", "usbScreenEmptyState": "未找到任何 USB 设备。请插入一个,然后刷新。" } diff --git a/lib/screens/contacts_screen.dart b/lib/screens/contacts_screen.dart index eeecfb9..8c4cec4 100644 --- a/lib/screens/contacts_screen.dart +++ b/lib/screens/contacts_screen.dart @@ -384,8 +384,15 @@ class _ContactsScreenState extends State Widget _buildContactsBody(BuildContext context, MeshCoreConnector connector) { final contacts = connector.contacts; + final shouldShowStartupSpinner = + contacts.isEmpty && + _groups.isEmpty && + connector.isConnected && + (connector.isLoadingContacts || + connector.isLoadingChannels || + connector.selfPublicKey == null); - if (contacts.isEmpty && connector.isLoadingContacts && _groups.isEmpty) { + if (shouldShowStartupSpinner) { return const Center(child: CircularProgressIndicator()); }