diff --git a/lib/data/model/app/error.dart b/lib/data/model/app/error.dart index f2d56e96..159e7303 100644 --- a/lib/data/model/app/error.dart +++ b/lib/data/model/app/error.dart @@ -1,3 +1,5 @@ +import 'package:toolbox/core/extension/context/locale.dart'; + enum ErrFrom { unknown, apt, @@ -15,18 +17,35 @@ abstract class Err { final T type; final String? message; + String? get solution; + Err({required this.from, required this.type, this.message}); } enum SSHErrType { unknown, connect, - noPrivateKey; + auth, + noPrivateKey, + chdir, + segements, + writeScript, + getStatus, + ; } class SSHErr extends Err { SSHErr({required super.type, super.message}) : super(from: ErrFrom.ssh); + @override + String? get solution => switch (type) { + SSHErrType.chdir => l10n.needHomeDir, + SSHErrType.auth => l10n.authFailTip, + SSHErrType.writeScript => l10n.writeScriptFailTip, + SSHErrType.noPrivateKey => l10n.noPrivateKeyTip, + _ => null, + }; + @override String toString() { return 'SSHErr<$type>: $message'; @@ -49,6 +68,9 @@ class ContainerErr extends Err { ContainerErr({required super.type, super.message}) : super(from: ErrFrom.docker); + @override + String? get solution => null; + @override String toString() { return 'ContainerErr<$type>: $message'; @@ -64,6 +86,9 @@ enum ICloudErrType { class ICloudErr extends Err { ICloudErr({required super.type, super.message}) : super(from: ErrFrom.icloud); + @override + String? get solution => null; + @override String toString() { return 'ICloudErr<$type>: $message'; @@ -79,6 +104,9 @@ enum WebdavErrType { class WebdavErr extends Err { WebdavErr({required super.type, super.message}) : super(from: ErrFrom.webdav); + @override + String? get solution => null; + @override String toString() { return 'WebdavErr<$type>: $message'; @@ -95,6 +123,9 @@ enum PveErrType { class PveErr extends Err { PveErr({required super.type, super.message}) : super(from: ErrFrom.status); + @override + String? get solution => null; + @override String toString() { return 'PveErr<$type>: $message'; diff --git a/lib/data/model/server/server.dart b/lib/data/model/server/server.dart index 46b0c623..ab767827 100644 --- a/lib/data/model/server/server.dart +++ b/lib/data/model/server/server.dart @@ -1,6 +1,7 @@ import 'package:dartssh2/dartssh2.dart'; import 'package:toolbox/core/extension/context/locale.dart'; import 'package:toolbox/core/extension/listx.dart'; +import 'package:toolbox/data/model/app/error.dart'; import 'package:toolbox/data/model/app/shell_func.dart'; import 'package:toolbox/data/model/server/battery.dart'; import 'package:toolbox/data/model/server/conn.dart'; @@ -55,7 +56,7 @@ class ServerStatus { NetSpeed netSpeed; Temperatures temps; SystemType system; - String? err; + Err? err; DiskIO diskIO; List? nvidia; final List batteries = []; diff --git a/lib/data/model/server/server.ext.dart b/lib/data/model/server/server.ext.dart index 6e771e5d..dfdbd2ad 100644 --- a/lib/data/model/server/server.ext.dart +++ b/lib/data/model/server/server.ext.dart @@ -53,7 +53,7 @@ extension ServerX on Server { case ServerConn.connecting: return l10n.serverTabConnecting; case ServerConn.failed: - return status.err ?? l10n.serverTabFailed; + return status.err != null ? l10n.viewErr : l10n.serverTabFailed; } } } diff --git a/lib/data/provider/server.dart b/lib/data/provider/server.dart index 1fdaca36..2757a4ec 100644 --- a/lib/data/provider/server.dart +++ b/lib/data/provider/server.dart @@ -8,6 +8,7 @@ import 'package:toolbox/core/extension/ssh_client.dart'; import 'package:toolbox/core/extension/stringx.dart'; import 'package:toolbox/core/utils/ssh_auth.dart'; import 'package:toolbox/core/utils/platform/path.dart'; +import 'package:toolbox/data/model/app/error.dart'; import 'package:toolbox/data/model/app/shell_func.dart'; import 'package:toolbox/data/model/server/system.dart'; import 'package:toolbox/data/model/sftp/req.dart'; @@ -290,7 +291,7 @@ class ServerProvider extends ChangeNotifier { } } catch (e) { TryLimiter.inc(sid); - s.status.err = e.toString(); + s.status.err = SSHErr(type: SSHErrType.connect, message: e.toString()); _setServerState(s, ServerConn.failed); /// In order to keep privacy, print [spi.name] instead of [spi.id] @@ -313,12 +314,12 @@ class ServerProvider extends ChangeNotifier { ); } on SSHAuthAbortError catch (e) { TryLimiter.inc(sid); - s.status.err = e.toString(); + s.status.err = SSHErr(type: SSHErrType.auth, message: e.toString()); _setServerState(s, ServerConn.failed); return; } on SSHAuthFailError catch (e) { TryLimiter.inc(sid); - s.status.err = e.toString(); + s.status.err = SSHErr(type: SSHErrType.auth, message: e.toString()); _setServerState(s, ServerConn.failed); return; } catch (e) { @@ -344,11 +345,14 @@ class ServerProvider extends ChangeNotifier { if (err != null) { throw err; } - } catch (e) { + } catch (ee) { TryLimiter.inc(sid); - s.status.err = e.toString(); + s.status.err = SSHErr( + type: SSHErrType.writeScript, + message: '$e\n\n$ee', + ); _setServerState(s, ServerConn.failed); - Loggers.app.warning('Write script to ${spi.name} by sftp', e); + Loggers.app.warning('Write script to ${spi.name} by sftp', ee); return; } finally { if (await file.exists()) await file.delete(); @@ -379,13 +383,16 @@ class ServerProvider extends ChangeNotifier { } } TryLimiter.inc(sid); - s.status.err = 'Seperate segments failed, raw:\n$raw'; + s.status.err = SSHErr( + type: SSHErrType.segements, + message: 'Seperate segments failed, raw:\n$raw', + ); _setServerState(s, ServerConn.failed); return; } } catch (e) { TryLimiter.inc(sid); - s.status.err = e.toString(); + s.status.err = SSHErr(type: SSHErrType.getStatus, message: e.toString()); _setServerState(s, ServerConn.failed); Loggers.app.warning('Get status from ${spi.name} failed', e); return; @@ -395,10 +402,17 @@ class ServerProvider extends ChangeNotifier { final customCmdLen = spi.custom?.cmds?.length ?? 0; if (!systemType.isSegmentsLenMatch(segments.length - customCmdLen)) { TryLimiter.inc(sid); + if (raw.contains('Could not chdir to home directory /var/services/')) { + s.status.err = SSHErr(type: SSHErrType.chdir, message: raw); + _setServerState(s, ServerConn.failed); + return; + } final expected = systemType.segmentsLen; final actual = segments.length; - final err = 'Segments: expect $expected, got $actual, raw:\n\n$raw'; - s.status.err = err; + s.status.err = SSHErr( + type: SSHErrType.segements, + message: 'Segments: expect $expected, got $actual, raw:\n\n$raw', + ); _setServerState(s, ServerConn.failed); return; } @@ -418,7 +432,10 @@ class ServerProvider extends ChangeNotifier { ); } catch (e, trace) { TryLimiter.inc(sid); - s.status.err = 'Parse failed: $e\n\n$raw'; + s.status.err = SSHErr( + type: SSHErrType.getStatus, + message: 'Parse failed: $e\n\n$raw', + ); _setServerState(s, ServerConn.failed); Loggers.parse.warning('Server status', e, trace); return; diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index dd5b6e82..ad81d7fc 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -13,6 +13,7 @@ "alterUrl": "Url ändern", "askContinue": "{msg}. Weiter?", "attention": "Achtung", + "authFailTip": "Authentifizierung fehlgeschlagen, bitte überprüfen Sie, ob das Passwort/Schlüssel/Host/Benutzer usw. falsch sind.", "authRequired": "Autorisierung erforderlich", "auto": "System folgen", "autoBackupConflict": "Es kann nur eine automatische Sicherung gleichzeitig aktiviert werden.", @@ -166,6 +167,7 @@ "moveOutServerFuncBtnsHelp": "Ein: kann unter jeder Karte auf der Registerkarte \"Server\" angezeigt werden. Aus: kann oben auf der Seite \"Serverdetails\" angezeigt werden.", "ms": "ms", "name": "Name", + "needHomeDir": "Wenn Sie ein Synology-Benutzer sind, [sehen Sie hier](https://kb.synology.com/DSM/tutorial/user_enable_home_service). Benutzer anderer Systeme müssen suchen, wie man ein Home-Verzeichnis erstellt.", "needRestart": "App muss neugestartet werden", "net": "Netz", "netViewType": "Netzwerkansicht Typ", @@ -175,6 +177,7 @@ "noLineChart": "Verwenden Sie keine Liniendiagramme", "noNotiPerm": "Keine Benachrichtigungsrechte, möglicherweise keine Fortschrittsanzeige beim Herunterladen von App-Updates.", "noOptions": "Keine Optionen verfügbar", + "noPrivateKeyTip": "Der private Schlüssel existiert nicht, möglicherweise wurde er gelöscht oder es liegt ein Konfigurationsfehler vor.", "noPromptAgain": "Nicht mehr nachfragen", "noResult": "Kein Ergebnis", "noSavedPrivateKey": "Keine gespeicherten Private Keys", @@ -325,5 +328,6 @@ "webdavSettingEmpty": "Webdav-Einstellungen sind leer", "whenOpenApp": "Beim Öffnen der App", "willTakEeffectImmediately": "Wird sofort angewendet", - "write": "Schreiben" + "write": "Schreiben", + "writeScriptFailTip": "Das Schreiben des Skripts ist fehlgeschlagen, möglicherweise aufgrund fehlender Berechtigungen oder das Verzeichnis existiert nicht." } \ No newline at end of file diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 2bc28a04..48c1eba1 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -13,6 +13,7 @@ "alterUrl": "Alter url", "askContinue": "{msg}. Continue?", "attention": "Attention", + "authFailTip": "Authentication failed, please check if the password/key/host/user, etc., are incorrect.", "authRequired": "Auth required", "auto": "Auto", "autoBackupConflict": "Only one automatic backup can be turned on at the same time.", @@ -166,6 +167,7 @@ "moveOutServerFuncBtnsHelp": "On: can be displayed below each card on the Server Tab page. Off: can be displayed at the top of the Server Details page.", "ms": "ms", "name": "Name", + "needHomeDir": "If you are a Synology user, [see here](https://kb.synology.com/DSM/tutorial/user_enable_home_service). Users of other systems need to search for how to create a home directory.", "needRestart": "Need to restart app", "net": "Net", "netViewType": "Net view type", @@ -175,6 +177,7 @@ "noLineChart": "Do not use line charts", "noNotiPerm": "No notification permissions, possibly no progress indication when downloading app updates.", "noOptions": "No options", + "noPrivateKeyTip": "The private key does not exist, it may have been deleted or there is a configuration error.", "noPromptAgain": "Do not prompt again", "noResult": "No result", "noSavedPrivateKey": "No saved private keys.", @@ -325,5 +328,6 @@ "webdavSettingEmpty": "Webdav setting is empty", "whenOpenApp": "When opening the app", "willTakEeffectImmediately": "Will take effect immediately", - "write": "Write" + "write": "Write", + "writeScriptFailTip": "Writing to the script failed, possibly due to lack of permissions or the directory does not exist." } \ No newline at end of file diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 97cab162..d732883a 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -13,6 +13,7 @@ "alterUrl": "URL alternativa", "askContinue": "{msg}, ¿continuar?", "attention": "Atención", + "authFailTip": "La autenticación ha fallado, por favor verifica si la contraseña/llave/host/usuario, etc., son incorrectos.", "authRequired": "Autenticación requerida", "auto": "Automático", "autoBackupConflict": "Solo se puede activar una copia de seguridad automática a la vez", @@ -166,6 +167,7 @@ "moveOutServerFuncBtnsHelp": "Activado: se mostrará debajo de cada tarjeta en la página de servidores. Desactivado: se mostrará en la parte superior de los detalles del servidor.", "ms": "milisegundos", "name": "Nombre", + "needHomeDir": "Si eres usuario de Synology, [consulta aquí](https://kb.synology.com/DSM/tutorial/user_enable_home_service). Los usuarios de otros sistemas deben buscar cómo crear un directorio home.", "needRestart": "Necesita reiniciar la app", "net": "Red", "netViewType": "Tipo de vista de red", @@ -175,6 +177,7 @@ "noLineChart": "No utilice gráficos de líneas", "noNotiPerm": "Sin permisos de notificación, posiblemente sin indicación de progreso al descargar actualizaciones de la aplicación.", "noOptions": "Sin opciones disponibles", + "noPrivateKeyTip": "La clave privada no existe, puede haber sido eliminada o hay un error de configuración.", "noPromptAgain": "No volver a preguntar", "noResult": "Sin resultados", "noSavedPrivateKey": "No hay llaves privadas guardadas.", @@ -325,5 +328,6 @@ "webdavSettingEmpty": "La configuración de Webdav está vacía", "whenOpenApp": "Al abrir la App", "willTakEeffectImmediately": "Los cambios tendrán efecto inmediatamente", - "write": "Escribir" + "write": "Escribir", + "writeScriptFailTip": "La escritura en el script falló, posiblemente por falta de permisos o porque el directorio no existe." } \ No newline at end of file diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index 2d269160..f6027ea1 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -13,6 +13,7 @@ "alterUrl": "Modifier l'URL", "askContinue": "{msg}. Continuer?", "attention": "Attention", + "authFailTip": "Échec de l'authentification, veuillez vérifier si le mot de passe/clé/hôte/utilisateur, etc., sont incorrects.", "authRequired": "Authentification requise", "auto": "Auto", "autoBackupConflict": "Une seule sauvegarde automatique peut être activée à la fois.", @@ -166,6 +167,7 @@ "moveOutServerFuncBtnsHelp": "Activé : peut être affiché sous chaque carte sur la page de l'onglet Serveur. Désactivé : peut être affiché en haut de la page Détails du serveur.", "ms": "ms", "name": "Nom", + "needHomeDir": "Si vous êtes utilisateur de Synology, [voir ici](https://kb.synology.com/DSM/tutorial/user_enable_home_service). Les utilisateurs d'autres systèmes doivent rechercher comment créer un répertoire personnel.", "needRestart": "Redémarrage de l'application nécessaire", "net": "Réseau", "netViewType": "Type de vue réseau", @@ -175,6 +177,7 @@ "noLineChart": "N'utilisez pas de graphiques en ligne", "noNotiPerm": "Pas de permissions de notification, il est possible qu'il n'y ait pas de notification de progression lors du téléchargement des mises à jour des applications.", "noOptions": "Aucune option", + "noPrivateKeyTip": "La clé privée n'existe pas, elle a peut-être été supprimée ou il y a une erreur de configuration.", "noPromptAgain": "Ne plus demander", "noResult": "Aucun résultat", "noSavedPrivateKey": "Aucune clé privée enregistrée.", @@ -325,5 +328,6 @@ "webdavSettingEmpty": "La configuration Webdav est vide", "whenOpenApp": "À l'ouverture de l'application", "willTakEeffectImmediately": "Prendra effet immédiatement", - "write": "Écrire" + "write": "Écrire", + "writeScriptFailTip": "L'écriture du script a échoué, peut-être en raison d'un manque de permissions ou parce que le répertoire n'existe pas." } \ No newline at end of file diff --git a/lib/l10n/app_id.arb b/lib/l10n/app_id.arb index 092e32d0..4101f13f 100644 --- a/lib/l10n/app_id.arb +++ b/lib/l10n/app_id.arb @@ -13,6 +13,7 @@ "alterUrl": "Alter url", "askContinue": "{msg}, lanjutkan?", "attention": "Perhatian", + "authFailTip": "Otentikasi gagal, silakan periksa apakah kata sandi/kunci/host/pengguna, dll, salah.", "authRequired": "Auth diperlukan", "auto": "Auto", "autoBackupConflict": "Hanya satu pencadangan otomatis yang dapat diaktifkan pada saat yang bersamaan.", @@ -166,6 +167,7 @@ "moveOutServerFuncBtnsHelp": "Aktif: dapat ditampilkan di bawah setiap kartu pada halaman Tab Server. Nonaktif: dapat ditampilkan di bagian atas halaman Rincian Server.", "ms": "MS", "name": "Nama", + "needHomeDir": "Jika Anda pengguna Synology, [lihat di sini](https://kb.synology.com/DSM/tutorial/user_enable_home_service). Pengguna sistem lain perlu mencari cara membuat direktori home.", "needRestart": "Perlu memulai ulang aplikasi", "net": "Net", "netViewType": "Jenis tampilan bersih", @@ -175,6 +177,7 @@ "noLineChart": "Jangan gunakan grafik garis", "noNotiPerm": "Tidak ada izin notifikasi, mungkin tidak ada indikasi kemajuan saat mengunduh pembaruan aplikasi.", "noOptions": "Tidak ada opsi", + "noPrivateKeyTip": "Kunci privat tidak ada, mungkin telah dihapus atau ada kesalahan konfigurasi.", "noPromptAgain": "Jangan tanya lagi", "noResult": "Tidak ada hasil", "noSavedPrivateKey": "Tidak ada kunci pribadi yang disimpan.", @@ -325,5 +328,6 @@ "webdavSettingEmpty": "Pengaturan webdav kosong", "whenOpenApp": "Saat membuka aplikasi", "willTakEeffectImmediately": "Akan segera berlaku", - "write": "Tulis" + "write": "Tulis", + "writeScriptFailTip": "Penulisan ke skrip gagal, mungkin karena tidak ada izin atau direktori tidak ada." } \ No newline at end of file diff --git a/lib/l10n/app_ja.arb b/lib/l10n/app_ja.arb index 9bf5f51c..42c2f6ed 100644 --- a/lib/l10n/app_ja.arb +++ b/lib/l10n/app_ja.arb @@ -13,6 +13,7 @@ "alterUrl": "代替リンク", "askContinue": "{msg}、続行しますか?", "attention": "注意", + "authFailTip": "認証に失敗しました。パスワード/鍵/ホスト/ユーザーなどが間違っていないか確認してください。", "authRequired": "認証が必要", "auto": "自動", "autoBackupConflict": "自動バックアップは一度に一つしか開始できません", @@ -166,6 +167,7 @@ "moveOutServerFuncBtnsHelp": "有効にする:サーバータブの各カードの下に表示されます。無効にする:サーバーの詳細ページの上部に表示されます。", "ms": "ミリ秒", "name": "名前", + "needHomeDir": "Synologyユーザーの場合は、[こちらをご覧ください](https://kb.synology.com/DSM/tutorial/user_enable_home_service)。他のシステムのユーザーは、ホームディレクトリの作成方法を検索する必要があります。", "needRestart": "アプリを再起動する必要があります", "net": "ネットワーク", "netViewType": "ネットワークビュータイプ", @@ -175,6 +177,7 @@ "noLineChart": "折れ線グラフを使用しない", "noNotiPerm": "通知の権限がないため、アプリの更新のダウンロード中に進行状況が表示されない場合があります。", "noOptions": "選択肢がありません", + "noPrivateKeyTip": "私有鍵が存在しません。削除されたか、設定ミスがある可能性があります。", "noPromptAgain": "再度確認しない", "noResult": "結果なし", "noSavedPrivateKey": "保存されたプライベートキーがありません。", @@ -325,5 +328,6 @@ "webdavSettingEmpty": "Webdavの設定が空です", "whenOpenApp": "アプリを開くとき", "willTakEeffectImmediately": "変更は即座に有効になります", - "write": "書き込み" + "write": "書き込み", + "writeScriptFailTip": "スクリプトの書き込みに失敗しました。権限がないかディレクトリが存在しない可能性があります。" } \ No newline at end of file diff --git a/lib/l10n/app_nl.arb b/lib/l10n/app_nl.arb index 7b1fbaf1..4aabdd9d 100644 --- a/lib/l10n/app_nl.arb +++ b/lib/l10n/app_nl.arb @@ -13,6 +13,7 @@ "alterUrl": "Url wijzigen", "askContinue": "{msg}. Doorgaan?", "attention": "Let op", + "authFailTip": "Authenticatie mislukt, controleer of het wachtwoord/sleutel/host/gebruiker, enz., incorrect zijn.", "authRequired": "Authenticatie vereist", "auto": "Auto", "autoBackupConflict": "Er kan slechts één automatische back-up tegelijk worden ingeschakeld.", @@ -166,6 +167,7 @@ "moveOutServerFuncBtnsHelp": "Aan: kan worden weergegeven onder elke kaart op de Server-tabbladpagina. Uit: kan worden weergegeven bovenaan de Serverdetails-pagina.", "ms": "ms", "name": "Naam", + "needHomeDir": "Als u een Synology-gebruiker bent, [zie hier](https://kb.synology.com/DSM/tutorial/user_enable_home_service). Gebruikers van andere systemen moeten zoeken hoe ze een home directory kunnen creëren.", "needRestart": "App moet opnieuw worden gestart", "net": "Netwerk", "netViewType": "Netweergavetype", @@ -174,6 +176,7 @@ "noInterface": "Geen interface", "noNotiPerm": "Geen meldingsmachtigingen, mogelijk geen voortgangsindicatie bij het downloaden van app-updates.", "noOptions": "Geen opties", + "noPrivateKeyTip": "De privésleutel bestaat niet, deze is mogelijk verwijderd of er is een configuratiefout.", "noPromptAgain": "Niet meer vragen", "noResult": "Geen resultaat", "noSavedPrivateKey": "Geen opgeslagen privésleutels.", @@ -324,5 +327,6 @@ "webdavSettingEmpty": "Webdav-instelling is leeg", "whenOpenApp": "Bij het openen van de app", "willTakEeffectImmediately": "Zal onmiddellijk van kracht worden", - "write": "Schrijven" + "write": "Schrijven", + "writeScriptFailTip": "Het schrijven naar het script is mislukt, mogelijk door gebrek aan rechten of omdat de map niet bestaat." } \ No newline at end of file diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index 1d129a9c..d54d6764 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -13,6 +13,7 @@ "alterUrl": "URL alternativa", "askContinue": "{msg}, continuar?", "attention": "Atenção", + "authFailTip": "Autenticação falhou, por favor verifique se a senha/chave/host/usuário, etc., estão incorretos.", "authRequired": "Autenticação necessária", "auto": "Automático", "autoBackupConflict": "Apenas um backup automático pode ser ativado por vez", @@ -166,6 +167,7 @@ "moveOutServerFuncBtnsHelp": "Ativado: Mostra abaixo de cada cartão na aba do servidor. Desativado: Mostra no topo da página de detalhes do servidor.", "ms": "ms", "name": "Nome", + "needHomeDir": "Se você é usuário de Synology, [veja aqui](https://kb.synology.com/DSM/tutorial/user_enable_home_service). Usuários de outros sistemas precisam pesquisar como criar um diretório home.", "needRestart": "Necessita reiniciar o app", "net": "Rede", "netViewType": "Tipo de visualização de rede", @@ -175,6 +177,7 @@ "noLineChart": "Gebruik geen lijndiagrammen", "noNotiPerm": "Sem permissão de notificação, possivelmente sem indicação de progresso ao baixar atualizações de aplicativos.", "noOptions": "Sem opções", + "noPrivateKeyTip": "A chave privada não existe, pode ter sido deletada ou há um erro de configuração.", "noPromptAgain": "Não perguntar novamente", "noResult": "Sem resultados", "noSavedPrivateKey": "Nenhuma chave privada salva.", @@ -325,5 +328,6 @@ "webdavSettingEmpty": "Configurações de Webdav estão vazias", "whenOpenApp": "Ao abrir o app", "willTakEeffectImmediately": "As alterações serão aplicadas imediatamente", - "write": "Escrita" + "write": "Escrita", + "writeScriptFailTip": "Falha ao escrever no script, possivelmente devido à falta de permissões ou o diretório não existe." } \ No newline at end of file diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb index 21ac79e5..68a3289e 100644 --- a/lib/l10n/app_ru.arb +++ b/lib/l10n/app_ru.arb @@ -13,6 +13,7 @@ "alterUrl": "альтернативная ссылка", "askContinue": "{msg}, продолжить?", "attention": "внимание", + "authFailTip": "Аутентификация не удалась, пожалуйста, проверьте, правильны ли пароль/ключ/хост/пользователь и т.д.", "authRequired": "требуется аутентификация", "auto": "авто", "autoBackupConflict": "Может быть включено только одно автоматическое резервное копирование", @@ -166,6 +167,7 @@ "moveOutServerFuncBtnsHelp": "Включено: кнопки функций сервера отображаются под каждой карточкой на вкладке сервера. Выключено: отображается в верхней части страницы деталей сервера.", "ms": "мс", "name": "имя", + "needHomeDir": "Если вы пользователь Synology, [смотрите здесь](https://kb.synology.com/DSM/tutorial/user_enable_home_service). Пользователям других систем нужно искать, как создать домашний каталог.", "needRestart": "требуется перезапуск приложения", "net": "сеть", "netViewType": "тип визуализации сети", @@ -175,6 +177,7 @@ "noLineChart": "Não use gráficos de linha", "noNotiPerm": "Нет разрешения на уведомления, возможно отсутствие индикации прогресса при загрузке обновлений приложений.", "noOptions": "нет доступных опций", + "noPrivateKeyTip": "Приватный ключ не существует, возможно, он был удален или есть ошибка в настройках.", "noPromptAgain": "Больше не спрашивать", "noResult": "нет результатов", "noSavedPrivateKey": "Нет сохраненных приватных ключей.", @@ -325,5 +328,6 @@ "webdavSettingEmpty": "Настройки Webdav пусты", "whenOpenApp": "при открытии приложения", "willTakEeffectImmediately": "Изменения вступят в силу немедленно", - "write": "запись" + "write": "запись", + "writeScriptFailTip": "Запись в скрипт не удалась, возможно, из-за отсутствия прав или директории не существует." } \ No newline at end of file diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index cb8b5227..f7813f18 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -13,6 +13,7 @@ "alterUrl": "备选链接", "askContinue": "{msg},继续吗?", "attention": "注意", + "authFailTip": "认证失败,请检查密码/密钥/主机/用户等是否错误", "authRequired": "需要认证", "auto": "自动", "autoBackupConflict": "只能同时开启一个自动备份", @@ -166,6 +167,7 @@ "moveOutServerFuncBtnsHelp": "开启:可以在服务器 Tab 页的每个卡片下方显示。关闭:在服务器详情页顶部显示。", "ms": "毫秒", "name": "名称", + "needHomeDir": "如果你是群晖用户,[看这里](https://kb.synology.cn/zh-cn/DSM/tutorial/ssh_could_not_chdir_to_home_directory)。其他系统用户,需搜索如何创建家目录(home directory).", "needRestart": "需要重启 App", "net": "网络", "netViewType": "网络视图类型", @@ -175,6 +177,7 @@ "noLineChart": "不使用折线图", "noNotiPerm": "无通知权限,可能下载App更新时无进度提示。", "noOptions": "无可选项", + "noPrivateKeyTip": "私钥不存在,可能已被删除/配置错误", "noPromptAgain": "不再提示", "noResult": "无结果", "noSavedPrivateKey": "没有已保存的私钥。", @@ -325,5 +328,6 @@ "webdavSettingEmpty": "Webdav 设置项为空", "whenOpenApp": "当打开 App 时", "willTakEeffectImmediately": "更改将会立即生效", - "write": "写" + "write": "写", + "writeScriptFailTip": "写入脚本失败,可能是没有权限/目录不存在等" } \ No newline at end of file diff --git a/lib/l10n/app_zh_tw.arb b/lib/l10n/app_zh_tw.arb index 81741624..5c5bd4ec 100644 --- a/lib/l10n/app_zh_tw.arb +++ b/lib/l10n/app_zh_tw.arb @@ -13,6 +13,7 @@ "alterUrl": "備選鏈接", "askContinue": "{msg},繼續嗎?", "attention": "注意", + "authFailTip": "認證失敗,請檢查密碼/密鑰/主機/用戶等是否錯誤。", "authRequired": "需要認證", "auto": "自動", "autoBackupConflict": "只能同時開啓壹個自動備份", @@ -166,6 +167,7 @@ "moveOutServerFuncBtnsHelp": "開啟:可以在服務器 Tab 頁的每個卡片下方顯示。關閉:在服務器詳情頁頂部顯示。", "ms": "毫秒", "name": "名稱", + "needHomeDir": "如果你是群暉用戶,[看這裡](https://kb.synology.com/DSM/tutorial/user_enable_home_service)。其他系統用戶,需搜索如何創建家目錄(home directory)。", "needRestart": "需要重啓 App", "net": "網絡", "netViewType": "網絡視圖類型", @@ -175,6 +177,7 @@ "noLineChart": "不使用折線圖", "noNotiPerm": "無通知權限,可能在下載應用程式更新時沒有進度提示。", "noOptions": "無可選項", + "noPrivateKeyTip": "私鑰不存在,可能已被刪除/配置錯誤。", "noPromptAgain": "不再提示", "noResult": "無結果", "noSavedPrivateKey": "沒有已保存的私鑰。", @@ -325,5 +328,6 @@ "webdavSettingEmpty": "Webdav 設置項爲空", "whenOpenApp": "當打開 App 時", "willTakEeffectImmediately": "更改將會立即生效", - "write": "写" + "write": "写", + "writeScriptFailTip": "寫入腳本失敗,可能是沒有權限/目錄不存在等。" } \ No newline at end of file diff --git a/lib/view/page/server/tab.dart b/lib/view/page/server/tab.dart index 0f1d3228..8109f2af 100644 --- a/lib/view/page/server/tab.dart +++ b/lib/view/page/server/tab.dart @@ -19,6 +19,7 @@ import 'package:toolbox/data/res/color.dart'; import 'package:toolbox/data/res/provider.dart'; import 'package:toolbox/data/res/store.dart'; import 'package:toolbox/view/widget/auto_hide.dart'; +import 'package:toolbox/view/widget/markdown.dart'; import 'package:toolbox/view/widget/percent_circle.dart'; import '../../../core/route.dart'; @@ -516,21 +517,25 @@ class _ServerPageState extends State _showFailReason(s.status); }, child: Text( - hasErr ? l10n.viewErr : s.getTopRightStr(s.spi), + s.getTopRightStr(s.spi), style: UIs.text13Grey, ), ); } void _showFailReason(ServerStatus ss) { + final md = ''' +${ss.err?.solution ?? l10n.unknown} + +```sh +${ss.err?.message ?? l10n.unknownError} +'''; context.showRoundDialog( title: Text(l10n.error), - child: SingleChildScrollView( - child: Text(ss.err ?? l10n.unknownError), - ), + child: SingleChildScrollView(child: SimpleMarkdown(data: md)), actions: [ TextButton( - onPressed: () => Shares.copy(ss.err ?? l10n.unknownError), + onPressed: () => Shares.copy(md), child: Text(l10n.copy), ) ], diff --git a/lib/view/widget/auto_hide.dart b/lib/view/widget/auto_hide.dart index 691a2b56..dac2ec6a 100644 --- a/lib/view/widget/auto_hide.dart +++ b/lib/view/widget/auto_hide.dart @@ -41,7 +41,6 @@ final class _AutoHideState extends State { void _setupTimer() { _timer?.cancel(); _timer = Timer.periodic(const Duration(seconds: 3), (_) { - debugPrint('[AutoHideFab._timer] trigger timer'); if (_isScrolling) return; if (!_visible) return; if (!widget.controller.positions.any((e) => e.maxScrollExtent >= 0)) {