diff --git a/lib/l10n/app_bg.arb b/lib/l10n/app_bg.arb index c17f117c..30a2c1b5 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 6c79f2d5..b6de02a2 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 8a647b48..203f64fb 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -723,6 +723,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 5a2672e0..b23cfcee 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 60ac827a..0e7b9528 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 08163c63..b77450fc 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 e0c1f8e5..bedd4072 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -2759,6 +2759,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 019566aa..cf2b35c8 100644 --- a/lib/l10n/app_localizations_bg.dart +++ b/lib/l10n/app_localizations_bg.dart @@ -1514,6 +1514,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 1ae2fb47..7c3fc930 100644 --- a/lib/l10n/app_localizations_de.dart +++ b/lib/l10n/app_localizations_de.dart @@ -1516,6 +1516,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 a98546ec..b8c4f905 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -1490,6 +1490,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 aa3926e7..21aad2cb 100644 --- a/lib/l10n/app_localizations_es.dart +++ b/lib/l10n/app_localizations_es.dart @@ -1512,6 +1512,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 f8e89cc2..21f63b52 100644 --- a/lib/l10n/app_localizations_fr.dart +++ b/lib/l10n/app_localizations_fr.dart @@ -1518,6 +1518,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 1b151482..1cc567c3 100644 --- a/lib/l10n/app_localizations_it.dart +++ b/lib/l10n/app_localizations_it.dart @@ -1510,6 +1510,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 0d9f807a..db1f68e3 100644 --- a/lib/l10n/app_localizations_nl.dart +++ b/lib/l10n/app_localizations_nl.dart @@ -1506,6 +1506,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 6626308a..e4373d1a 100644 --- a/lib/l10n/app_localizations_pl.dart +++ b/lib/l10n/app_localizations_pl.dart @@ -1514,6 +1514,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 614ff0d6..2aaa940c 100644 --- a/lib/l10n/app_localizations_pt.dart +++ b/lib/l10n/app_localizations_pt.dart @@ -1512,6 +1512,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 e3747f2f..ffd327a5 100644 --- a/lib/l10n/app_localizations_sk.dart +++ b/lib/l10n/app_localizations_sk.dart @@ -1507,6 +1507,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 4d2ad7f8..994b7fa6 100644 --- a/lib/l10n/app_localizations_sl.dart +++ b/lib/l10n/app_localizations_sl.dart @@ -1508,6 +1508,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 d170b4a6..a4765a90 100644 --- a/lib/l10n/app_localizations_sv.dart +++ b/lib/l10n/app_localizations_sv.dart @@ -1497,6 +1497,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 7d02bf53..99f4e90f 100644 --- a/lib/l10n/app_localizations_zh.dart +++ b/lib/l10n/app_localizations_zh.dart @@ -1447,6 +1447,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 f78fc684..b7e1a35a 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 24edcaf7..56fe869d 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 47f9cef7..99da3747 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 752c8d4c..1ffb197a 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 3e40f2d5..bac8b2b0 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 35ec92be..3c8d470e 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 33cd5179..fc5ac553 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 f4129cd5..54c01504 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, ),