Show repeater login error in login dialog

This commit is contained in:
Michael Lynch
2026-01-16 09:35:02 -05:00
parent a14462978d
commit 2a04ebb8b6
28 changed files with 120 additions and 8 deletions
+2
View File
@@ -821,6 +821,8 @@
} }
} }
}, },
"login_failedMessage": "Входът не беше успешен. Или паролата е грешна, или повторителят е недостъпен.",
"common_reload": "Презареди", "common_reload": "Презареди",
"common_clear": "Изчисти", "common_clear": "Изчисти",
"path_currentPath": "Текущ път: {path}", "path_currentPath": "Текущ път: {path}",
+2
View File
@@ -821,6 +821,8 @@
} }
} }
}, },
"login_failedMessage": "Anmeldung fehlgeschlagen. Entweder ist das Passwort falsch oder der Repeater ist nicht erreichbar.",
"common_reload": "Neu laden", "common_reload": "Neu laden",
"common_clear": "Löschen", "common_clear": "Löschen",
"path_currentPath": "Aktiger Pfad: {path}", "path_currentPath": "Aktiger Pfad: {path}",
+2
View File
@@ -711,6 +711,8 @@
"error": {"type": "String"} "error": {"type": "String"}
} }
}, },
"login_failedMessage": "Login failed. Either the password is incorrect or the repeater is unreachable.",
"common_reload": "Reload", "common_reload": "Reload",
"common_clear": "Clear", "common_clear": "Clear",
+2
View File
@@ -821,6 +821,8 @@
} }
} }
}, },
"login_failedMessage": "Inicio fallido. La contraseña es incorrecta o el repetidor no está disponible.",
"common_reload": "Recargar", "common_reload": "Recargar",
"common_clear": "Borrar", "common_clear": "Borrar",
"path_currentPath": "Ruta actual: {path}", "path_currentPath": "Ruta actual: {path}",
+2
View File
@@ -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_reload": "Recharger",
"common_clear": "Effacer", "common_clear": "Effacer",
"path_currentPath": "Chemin actuel : {path}", "path_currentPath": "Chemin actuel : {path}",
+2
View File
@@ -821,6 +821,8 @@
} }
} }
}, },
"login_failedMessage": "Accesso fallito. La password non è corretta oppure il ripetitore non è raggiungibile.",
"common_reload": "Ricaricare", "common_reload": "Ricaricare",
"common_clear": "Cancella", "common_clear": "Cancella",
"path_currentPath": "Percorso corrente: {path}", "path_currentPath": "Percorso corrente: {path}",
+6
View File
@@ -2687,6 +2687,12 @@ abstract class AppLocalizations {
/// **'Login failed: {error}'** /// **'Login failed: {error}'**
String login_failed(String 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. /// No description provided for @common_reload.
/// ///
/// In en, this message translates to: /// In en, this message translates to:
+4
View File
@@ -1475,6 +1475,10 @@ class AppLocalizationsBg extends AppLocalizations {
return 'Входът не беше успешен: $error'; return 'Входът не беше успешен: $error';
} }
@override
String get login_failedMessage =>
'Входът не беше успешен. Или паролата е грешна, или повторителят е недостъпен.';
@override @override
String get common_reload => 'Презареди'; String get common_reload => 'Презареди';
+4
View File
@@ -1474,6 +1474,10 @@ class AppLocalizationsDe extends AppLocalizations {
return 'Anmeldung fehlgeschlagen: $error'; return 'Anmeldung fehlgeschlagen: $error';
} }
@override
String get login_failedMessage =>
'Anmeldung fehlgeschlagen. Entweder ist das Passwort falsch oder der Repeater ist nicht erreichbar.';
@override @override
String get common_reload => 'Neu laden'; String get common_reload => 'Neu laden';
+4
View File
@@ -1453,6 +1453,10 @@ class AppLocalizationsEn extends AppLocalizations {
return 'Login failed: $error'; return 'Login failed: $error';
} }
@override
String get login_failedMessage =>
'Login failed. Either the password is incorrect or the repeater is unreachable.';
@override @override
String get common_reload => 'Reload'; String get common_reload => 'Reload';
+4
View File
@@ -1472,6 +1472,10 @@ class AppLocalizationsEs extends AppLocalizations {
return 'Inicio fallido: $error'; return 'Inicio fallido: $error';
} }
@override
String get login_failedMessage =>
'Inicio fallido. La contraseña es incorrecta o el repetidor no está disponible.';
@override @override
String get common_reload => 'Recargar'; String get common_reload => 'Recargar';
+4
View File
@@ -1478,6 +1478,10 @@ class AppLocalizationsFr extends AppLocalizations {
return 'Connexion échouée : $error'; 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 @override
String get common_reload => 'Recharger'; String get common_reload => 'Recharger';
+4
View File
@@ -1470,6 +1470,10 @@ class AppLocalizationsIt extends AppLocalizations {
return 'Accesso fallito: $error'; return 'Accesso fallito: $error';
} }
@override
String get login_failedMessage =>
'Accesso fallito. La password non è corretta oppure il ripetitore non è raggiungibile.';
@override @override
String get common_reload => 'Ricaricare'; String get common_reload => 'Ricaricare';
+4
View File
@@ -1466,6 +1466,10 @@ class AppLocalizationsNl extends AppLocalizations {
return 'Inloggen mislukt: $error'; return 'Inloggen mislukt: $error';
} }
@override
String get login_failedMessage =>
'Inloggen mislukt. Het wachtwoord is onjuist of de repeater is niet bereikbaar.';
@override @override
String get common_reload => 'Opnieuw laden'; String get common_reload => 'Opnieuw laden';
+4
View File
@@ -1474,6 +1474,10 @@ class AppLocalizationsPl extends AppLocalizations {
return 'Zalogowanie się nie powiodło: $error'; 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 @override
String get common_reload => 'Ponownie załadować'; String get common_reload => 'Ponownie załadować';
+4
View File
@@ -1472,6 +1472,10 @@ class AppLocalizationsPt extends AppLocalizations {
return 'Login falhou: $error'; return 'Login falhou: $error';
} }
@override
String get login_failedMessage =>
'Falha no login. A senha está incorreta ou o repetidor está inacessível.';
@override @override
String get common_reload => 'Recarregar'; String get common_reload => 'Recarregar';
+4
View File
@@ -1468,6 +1468,10 @@ class AppLocalizationsSk extends AppLocalizations {
return 'Prihlásenie zlyhalo: $error'; return 'Prihlásenie zlyhalo: $error';
} }
@override
String get login_failedMessage =>
'Prihlásenie zlyhalo. Heslo je nesprávne alebo je opakovač nedostupný.';
@override @override
String get common_reload => 'Načítať'; String get common_reload => 'Načítať';
+4
View File
@@ -1469,6 +1469,10 @@ class AppLocalizationsSl extends AppLocalizations {
return 'Prijava je bila neuspešna: $error'; 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 @override
String get common_reload => 'Ponovno naloži'; String get common_reload => 'Ponovno naloži';
+4
View File
@@ -1457,6 +1457,10 @@ class AppLocalizationsSv extends AppLocalizations {
return 'Inloggning misslyckades: $error'; 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 @override
String get common_reload => 'Ladda om'; String get common_reload => 'Ladda om';
+3
View File
@@ -1411,6 +1411,9 @@ class AppLocalizationsZh extends AppLocalizations {
return '登录失败:$error'; return '登录失败:$error';
} }
@override
String get login_failedMessage => '登录失败。密码不正确或中继器不可达。';
@override @override
String get common_reload => '重新加载'; String get common_reload => '重新加载';
+2
View File
@@ -821,6 +821,8 @@
} }
} }
}, },
"login_failedMessage": "Inloggen mislukt. Het wachtwoord is onjuist of de repeater is niet bereikbaar.",
"common_reload": "Opnieuw laden", "common_reload": "Opnieuw laden",
"common_clear": "Schoonmaken", "common_clear": "Schoonmaken",
"path_currentPath": "Huidige pad: {path}", "path_currentPath": "Huidige pad: {path}",
+2
View File
@@ -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_reload": "Ponownie załadować",
"common_clear": "Wyczyść", "common_clear": "Wyczyść",
"path_currentPath": "Aktualny ścieżka: {path}", "path_currentPath": "Aktualny ścieżka: {path}",
+2
View File
@@ -821,6 +821,8 @@
} }
} }
}, },
"login_failedMessage": "Falha no login. A senha está incorreta ou o repetidor está inacessível.",
"common_reload": "Recarregar", "common_reload": "Recarregar",
"common_clear": "Limpar", "common_clear": "Limpar",
"path_currentPath": "Caminho atual: {path}", "path_currentPath": "Caminho atual: {path}",
+2
View File
@@ -821,6 +821,8 @@
} }
} }
}, },
"login_failedMessage": "Prihlásenie zlyhalo. Heslo je nesprávne alebo je opakovač nedostupný.",
"common_reload": "Načítať", "common_reload": "Načítať",
"common_clear": "Zmazať", "common_clear": "Zmazať",
"path_currentPath": "Aktívna cesta: {path}", "path_currentPath": "Aktívna cesta: {path}",
+2
View File
@@ -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_reload": "Ponovno naloži",
"common_clear": "Ponoviti", "common_clear": "Ponoviti",
"path_currentPath": "Trenutna pot: {path}", "path_currentPath": "Trenutna pot: {path}",
+2
View File
@@ -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_reload": "Ladda om",
"common_clear": "Rensa", "common_clear": "Rensa",
"path_currentPath": "Nuvarande sökväg: {path}", "path_currentPath": "Nuvarande sökväg: {path}",
+2
View File
@@ -821,6 +821,8 @@
} }
} }
}, },
"login_failedMessage": "登录失败。密码不正确或中继器不可达。",
"common_reload": "重新加载", "common_reload": "重新加载",
"common_clear": "清除", "common_clear": "清除",
"path_currentPath": "当前路径:{path}", "path_currentPath": "当前路径:{path}",
+37 -8
View File
@@ -31,6 +31,7 @@ class _RepeaterLoginDialogState extends State<RepeaterLoginDialog> {
bool _savePassword = false; bool _savePassword = false;
bool _isLoading = true; bool _isLoading = true;
bool _obscurePassword = true; bool _obscurePassword = true;
String? _loginError;
late MeshCoreConnector _connector; late MeshCoreConnector _connector;
int _currentAttempt = 0; int _currentAttempt = 0;
static const int _maxAttempts = 5; static const int _maxAttempts = 5;
@@ -79,6 +80,7 @@ class _RepeaterLoginDialogState extends State<RepeaterLoginDialog> {
setState(() { setState(() {
_isLoggingIn = true; _isLoggingIn = true;
_currentAttempt = 0; _currentAttempt = 0;
_loginError = null;
}); });
try { try {
@@ -134,7 +136,7 @@ class _RepeaterLoginDialogState extends State<RepeaterLoginDialog> {
'Login failed for ${repeater.name}', 'Login failed for ${repeater.name}',
tag: 'RepeaterLogin', tag: 'RepeaterLogin',
); );
throw Exception('Wrong password or node is unreachable'); break;
} }
appLogger.warn( appLogger.warn(
'Login attempt ${attempt + 1} timed out after ${timeoutSeconds}s', 'Login attempt ${attempt + 1} timed out after ${timeoutSeconds}s',
@@ -156,7 +158,13 @@ class _RepeaterLoginDialogState extends State<RepeaterLoginDialog> {
} }
if (loginResult != true) { 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 // If we got a response, login succeeded
@@ -182,13 +190,8 @@ class _RepeaterLoginDialogState extends State<RepeaterLoginDialog> {
if (mounted) { if (mounted) {
setState(() { setState(() {
_isLoggingIn = false; _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<RepeaterLoginDialog> {
style: const TextStyle(fontSize: 14), style: const TextStyle(fontSize: 14),
), ),
const SizedBox(height: 16), 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( TextField(
controller: _passwordController, controller: _passwordController,
obscureText: _obscurePassword, obscureText: _obscurePassword,
@@ -292,6 +314,13 @@ class _RepeaterLoginDialogState extends State<RepeaterLoginDialog> {
}, },
), ),
), ),
onChanged: (_) {
if (_loginError != null && mounted) {
setState(() {
_loginError = null;
});
}
},
onSubmitted: (_) => _handleLogin(), onSubmitted: (_) => _handleLogin(),
autofocus: _passwordController.text.isEmpty, autofocus: _passwordController.text.isEmpty,
), ),