From 2a04ebb8b613842c9ec7b75157da699fab82549f Mon Sep 17 00:00:00 2001 From: Michael Lynch Date: Fri, 16 Jan 2026 09:35:02 -0500 Subject: [PATCH] Show repeater login error in login dialog --- lib/l10n/app_bg.arb | 2 ++ lib/l10n/app_de.arb | 2 ++ lib/l10n/app_en.arb | 2 ++ lib/l10n/app_es.arb | 2 ++ lib/l10n/app_fr.arb | 2 ++ lib/l10n/app_it.arb | 2 ++ lib/l10n/app_localizations.dart | 6 ++++ lib/l10n/app_localizations_bg.dart | 4 +++ lib/l10n/app_localizations_de.dart | 4 +++ lib/l10n/app_localizations_en.dart | 4 +++ lib/l10n/app_localizations_es.dart | 4 +++ lib/l10n/app_localizations_fr.dart | 4 +++ lib/l10n/app_localizations_it.dart | 4 +++ lib/l10n/app_localizations_nl.dart | 4 +++ lib/l10n/app_localizations_pl.dart | 4 +++ lib/l10n/app_localizations_pt.dart | 4 +++ lib/l10n/app_localizations_sk.dart | 4 +++ lib/l10n/app_localizations_sl.dart | 4 +++ lib/l10n/app_localizations_sv.dart | 4 +++ lib/l10n/app_localizations_zh.dart | 3 ++ lib/l10n/app_nl.arb | 2 ++ lib/l10n/app_pl.arb | 2 ++ lib/l10n/app_pt.arb | 2 ++ lib/l10n/app_sk.arb | 2 ++ lib/l10n/app_sl.arb | 2 ++ lib/l10n/app_sv.arb | 2 ++ lib/l10n/app_zh.arb | 2 ++ lib/widgets/repeater_login_dialog.dart | 45 +++++++++++++++++++++----- 28 files changed, 120 insertions(+), 8 deletions(-) diff --git a/lib/l10n/app_bg.arb b/lib/l10n/app_bg.arb index 4c747da..92bbb99 100644 --- a/lib/l10n/app_bg.arb +++ b/lib/l10n/app_bg.arb @@ -821,6 +821,8 @@ } } }, + "login_failedMessage": "Входът не беше успешен. Или паролата е грешна, или повторителят е недостъпен.", + "common_reload": "Презареди", "common_clear": "Изчисти", "path_currentPath": "Текущ път: {path}", diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 9044962..d3a2dd1 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -821,6 +821,8 @@ } } }, + "login_failedMessage": "Anmeldung fehlgeschlagen. Entweder ist das Passwort falsch oder der Repeater ist nicht erreichbar.", + "common_reload": "Neu laden", "common_clear": "Löschen", "path_currentPath": "Aktiger Pfad: {path}", diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index dc53f73..00c59a1 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -711,6 +711,8 @@ "error": {"type": "String"} } }, + "login_failedMessage": "Login failed. Either the password is incorrect or the repeater is unreachable.", + "common_reload": "Reload", "common_clear": "Clear", diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 1515eb6..ee56cb7 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -821,6 +821,8 @@ } } }, + "login_failedMessage": "Inicio fallido. La contraseña es incorrecta o el repetidor no está disponible.", + "common_reload": "Recargar", "common_clear": "Borrar", "path_currentPath": "Ruta actual: {path}", diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index 6a09a33..a83a8ae 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -821,6 +821,8 @@ } } }, + "login_failedMessage": "Connexion échouée. Soit le mot de passe est incorrect, soit le relais est injoignable.", + "common_reload": "Recharger", "common_clear": "Effacer", "path_currentPath": "Chemin actuel : {path}", diff --git a/lib/l10n/app_it.arb b/lib/l10n/app_it.arb index 72be091..e44115b 100644 --- a/lib/l10n/app_it.arb +++ b/lib/l10n/app_it.arb @@ -821,6 +821,8 @@ } } }, + "login_failedMessage": "Accesso fallito. La password non è corretta oppure il ripetitore non è raggiungibile.", + "common_reload": "Ricaricare", "common_clear": "Cancella", "path_currentPath": "Percorso corrente: {path}", diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index a2c7ddb..4b2fcfb 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -2687,6 +2687,12 @@ abstract class AppLocalizations { /// **'Login failed: {error}'** String login_failed(String error); + /// No description provided for @login_failedMessage. + /// + /// In en, this message translates to: + /// **'Login failed. Either the password is incorrect or the repeater is unreachable.'** + String get login_failedMessage; + /// No description provided for @common_reload. /// /// In en, this message translates to: diff --git a/lib/l10n/app_localizations_bg.dart b/lib/l10n/app_localizations_bg.dart index 5def822..b5a1b49 100644 --- a/lib/l10n/app_localizations_bg.dart +++ b/lib/l10n/app_localizations_bg.dart @@ -1475,6 +1475,10 @@ class AppLocalizationsBg extends AppLocalizations { return 'Входът не беше успешен: $error'; } + @override + String get login_failedMessage => + 'Входът не беше успешен. Или паролата е грешна, или повторителят е недостъпен.'; + @override String get common_reload => 'Презареди'; diff --git a/lib/l10n/app_localizations_de.dart b/lib/l10n/app_localizations_de.dart index 591de39..6366b80 100644 --- a/lib/l10n/app_localizations_de.dart +++ b/lib/l10n/app_localizations_de.dart @@ -1474,6 +1474,10 @@ class AppLocalizationsDe extends AppLocalizations { return 'Anmeldung fehlgeschlagen: $error'; } + @override + String get login_failedMessage => + 'Anmeldung fehlgeschlagen. Entweder ist das Passwort falsch oder der Repeater ist nicht erreichbar.'; + @override String get common_reload => 'Neu laden'; diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index 9e04923..37f103e 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -1453,6 +1453,10 @@ class AppLocalizationsEn extends AppLocalizations { return 'Login failed: $error'; } + @override + String get login_failedMessage => + 'Login failed. Either the password is incorrect or the repeater is unreachable.'; + @override String get common_reload => 'Reload'; diff --git a/lib/l10n/app_localizations_es.dart b/lib/l10n/app_localizations_es.dart index 82259cf..f939e3b 100644 --- a/lib/l10n/app_localizations_es.dart +++ b/lib/l10n/app_localizations_es.dart @@ -1472,6 +1472,10 @@ class AppLocalizationsEs extends AppLocalizations { return 'Inicio fallido: $error'; } + @override + String get login_failedMessage => + 'Inicio fallido. La contraseña es incorrecta o el repetidor no está disponible.'; + @override String get common_reload => 'Recargar'; diff --git a/lib/l10n/app_localizations_fr.dart b/lib/l10n/app_localizations_fr.dart index c7735bc..6b0a987 100644 --- a/lib/l10n/app_localizations_fr.dart +++ b/lib/l10n/app_localizations_fr.dart @@ -1478,6 +1478,10 @@ class AppLocalizationsFr extends AppLocalizations { return 'Connexion échouée : $error'; } + @override + String get login_failedMessage => + 'Connexion échouée. Soit le mot de passe est incorrect, soit le relais est injoignable.'; + @override String get common_reload => 'Recharger'; diff --git a/lib/l10n/app_localizations_it.dart b/lib/l10n/app_localizations_it.dart index cd2d022..117f4c1 100644 --- a/lib/l10n/app_localizations_it.dart +++ b/lib/l10n/app_localizations_it.dart @@ -1470,6 +1470,10 @@ class AppLocalizationsIt extends AppLocalizations { return 'Accesso fallito: $error'; } + @override + String get login_failedMessage => + 'Accesso fallito. La password non è corretta oppure il ripetitore non è raggiungibile.'; + @override String get common_reload => 'Ricaricare'; diff --git a/lib/l10n/app_localizations_nl.dart b/lib/l10n/app_localizations_nl.dart index b9ae792..5f3e436 100644 --- a/lib/l10n/app_localizations_nl.dart +++ b/lib/l10n/app_localizations_nl.dart @@ -1466,6 +1466,10 @@ class AppLocalizationsNl extends AppLocalizations { return 'Inloggen mislukt: $error'; } + @override + String get login_failedMessage => + 'Inloggen mislukt. Het wachtwoord is onjuist of de repeater is niet bereikbaar.'; + @override String get common_reload => 'Opnieuw laden'; diff --git a/lib/l10n/app_localizations_pl.dart b/lib/l10n/app_localizations_pl.dart index 180d8e2..73adc0d 100644 --- a/lib/l10n/app_localizations_pl.dart +++ b/lib/l10n/app_localizations_pl.dart @@ -1474,6 +1474,10 @@ class AppLocalizationsPl extends AppLocalizations { return 'Zalogowanie się nie powiodło: $error'; } + @override + String get login_failedMessage => + 'Logowanie nie powiodło się. Hasło jest nieprawidłowe albo repeater jest nieosiągalny.'; + @override String get common_reload => 'Ponownie załadować'; diff --git a/lib/l10n/app_localizations_pt.dart b/lib/l10n/app_localizations_pt.dart index 403c4d6..3a995b5 100644 --- a/lib/l10n/app_localizations_pt.dart +++ b/lib/l10n/app_localizations_pt.dart @@ -1472,6 +1472,10 @@ class AppLocalizationsPt extends AppLocalizations { return 'Login falhou: $error'; } + @override + String get login_failedMessage => + 'Falha no login. A senha está incorreta ou o repetidor está inacessível.'; + @override String get common_reload => 'Recarregar'; diff --git a/lib/l10n/app_localizations_sk.dart b/lib/l10n/app_localizations_sk.dart index e9eb10c..52178a2 100644 --- a/lib/l10n/app_localizations_sk.dart +++ b/lib/l10n/app_localizations_sk.dart @@ -1468,6 +1468,10 @@ class AppLocalizationsSk extends AppLocalizations { return 'Prihlásenie zlyhalo: $error'; } + @override + String get login_failedMessage => + 'Prihlásenie zlyhalo. Heslo je nesprávne alebo je opakovač nedostupný.'; + @override String get common_reload => 'Načítať'; diff --git a/lib/l10n/app_localizations_sl.dart b/lib/l10n/app_localizations_sl.dart index f95797b..35f9aee 100644 --- a/lib/l10n/app_localizations_sl.dart +++ b/lib/l10n/app_localizations_sl.dart @@ -1469,6 +1469,10 @@ class AppLocalizationsSl extends AppLocalizations { return 'Prijava je bila neuspešna: $error'; } + @override + String get login_failedMessage => + 'Prijava je bila neuspešna. Geslo je napačno ali pa je repetitor nedosegljiv.'; + @override String get common_reload => 'Ponovno naloži'; diff --git a/lib/l10n/app_localizations_sv.dart b/lib/l10n/app_localizations_sv.dart index 6f97659..eb6d693 100644 --- a/lib/l10n/app_localizations_sv.dart +++ b/lib/l10n/app_localizations_sv.dart @@ -1457,6 +1457,10 @@ class AppLocalizationsSv extends AppLocalizations { return 'Inloggning misslyckades: $error'; } + @override + String get login_failedMessage => + 'Inloggning misslyckades. Antingen är lösenordet fel eller så går det inte att nå repeatern.'; + @override String get common_reload => 'Ladda om'; diff --git a/lib/l10n/app_localizations_zh.dart b/lib/l10n/app_localizations_zh.dart index e5b5a9f..767a380 100644 --- a/lib/l10n/app_localizations_zh.dart +++ b/lib/l10n/app_localizations_zh.dart @@ -1411,6 +1411,9 @@ class AppLocalizationsZh extends AppLocalizations { return '登录失败:$error'; } + @override + String get login_failedMessage => '登录失败。密码不正确或中继器不可达。'; + @override String get common_reload => '重新加载'; diff --git a/lib/l10n/app_nl.arb b/lib/l10n/app_nl.arb index 79fc69d..88cce67 100644 --- a/lib/l10n/app_nl.arb +++ b/lib/l10n/app_nl.arb @@ -821,6 +821,8 @@ } } }, + "login_failedMessage": "Inloggen mislukt. Het wachtwoord is onjuist of de repeater is niet bereikbaar.", + "common_reload": "Opnieuw laden", "common_clear": "Schoonmaken", "path_currentPath": "Huidige pad: {path}", diff --git a/lib/l10n/app_pl.arb b/lib/l10n/app_pl.arb index bab67b5..d1ce3d0 100644 --- a/lib/l10n/app_pl.arb +++ b/lib/l10n/app_pl.arb @@ -821,6 +821,8 @@ } } }, + "login_failedMessage": "Logowanie nie powiodło się. Hasło jest nieprawidłowe albo repeater jest nieosiągalny.", + "common_reload": "Ponownie załadować", "common_clear": "Wyczyść", "path_currentPath": "Aktualny ścieżka: {path}", diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index 59f4a47..a98663c 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -821,6 +821,8 @@ } } }, + "login_failedMessage": "Falha no login. A senha está incorreta ou o repetidor está inacessível.", + "common_reload": "Recarregar", "common_clear": "Limpar", "path_currentPath": "Caminho atual: {path}", diff --git a/lib/l10n/app_sk.arb b/lib/l10n/app_sk.arb index 67043a7..c1e5fcb 100644 --- a/lib/l10n/app_sk.arb +++ b/lib/l10n/app_sk.arb @@ -821,6 +821,8 @@ } } }, + "login_failedMessage": "Prihlásenie zlyhalo. Heslo je nesprávne alebo je opakovač nedostupný.", + "common_reload": "Načítať", "common_clear": "Zmazať", "path_currentPath": "Aktívna cesta: {path}", diff --git a/lib/l10n/app_sl.arb b/lib/l10n/app_sl.arb index 8a8dc59..b551934 100644 --- a/lib/l10n/app_sl.arb +++ b/lib/l10n/app_sl.arb @@ -821,6 +821,8 @@ } } }, + "login_failedMessage": "Prijava je bila neuspešna. Geslo je napačno ali pa je repetitor nedosegljiv.", + "common_reload": "Ponovno naloži", "common_clear": "Ponoviti", "path_currentPath": "Trenutna pot: {path}", diff --git a/lib/l10n/app_sv.arb b/lib/l10n/app_sv.arb index 866e438..c0c299b 100644 --- a/lib/l10n/app_sv.arb +++ b/lib/l10n/app_sv.arb @@ -821,6 +821,8 @@ } } }, + "login_failedMessage": "Inloggning misslyckades. Antingen är lösenordet fel eller så går det inte att nå repeatern.", + "common_reload": "Ladda om", "common_clear": "Rensa", "path_currentPath": "Nuvarande sökväg: {path}", diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index f1349e8..e3b5633 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -821,6 +821,8 @@ } } }, + "login_failedMessage": "登录失败。密码不正确或中继器不可达。", + "common_reload": "重新加载", "common_clear": "清除", "path_currentPath": "当前路径:{path}", diff --git a/lib/widgets/repeater_login_dialog.dart b/lib/widgets/repeater_login_dialog.dart index f4129cd..54c0150 100644 --- a/lib/widgets/repeater_login_dialog.dart +++ b/lib/widgets/repeater_login_dialog.dart @@ -31,6 +31,7 @@ class _RepeaterLoginDialogState extends State { bool _savePassword = false; bool _isLoading = true; bool _obscurePassword = true; + String? _loginError; late MeshCoreConnector _connector; int _currentAttempt = 0; static const int _maxAttempts = 5; @@ -79,6 +80,7 @@ class _RepeaterLoginDialogState extends State { setState(() { _isLoggingIn = true; _currentAttempt = 0; + _loginError = null; }); try { @@ -134,7 +136,7 @@ class _RepeaterLoginDialogState extends State { 'Login failed for ${repeater.name}', tag: 'RepeaterLogin', ); - throw Exception('Wrong password or node is unreachable'); + break; } appLogger.warn( 'Login attempt ${attempt + 1} timed out after ${timeoutSeconds}s', @@ -156,7 +158,13 @@ class _RepeaterLoginDialogState extends State { } if (loginResult != true) { - throw Exception('Wrong password or node is unreachable'); + if (mounted) { + setState(() { + _isLoggingIn = false; + _loginError = context.l10n.login_failedMessage; + }); + } + return; } // If we got a response, login succeeded @@ -182,13 +190,8 @@ class _RepeaterLoginDialogState extends State { if (mounted) { setState(() { _isLoggingIn = false; + _loginError = context.l10n.login_failedMessage; }); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(context.l10n.login_failed(e.toString())), - backgroundColor: Colors.red, - ), - ); } } } @@ -271,6 +274,25 @@ class _RepeaterLoginDialogState extends State { style: const TextStyle(fontSize: 14), ), const SizedBox(height: 16), + if (_loginError != null) ...[ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Icon(Icons.error, size: 18, color: Theme.of(context).colorScheme.error), + const SizedBox(width: 8), + Expanded( + child: Text( + _loginError!, + style: TextStyle( + color: Theme.of(context).colorScheme.error, + fontSize: 13, + ), + ), + ), + ], + ), + const SizedBox(height: 12), + ], TextField( controller: _passwordController, obscureText: _obscurePassword, @@ -292,6 +314,13 @@ class _RepeaterLoginDialogState extends State { }, ), ), + onChanged: (_) { + if (_loginError != null && mounted) { + setState(() { + _loginError = null; + }); + } + }, onSubmitted: (_) => _handleLogin(), autofocus: _passwordController.text.isEmpty, ),