From 682a6e4f2d4488bac365621b3e0f9bcafcf7e986 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?lollipopkit=F0=9F=8F=B3=EF=B8=8F=E2=80=8D=E2=9A=A7?= =?UTF-8?q?=EF=B8=8F?= <10864310+lollipopkit@users.noreply.github.com> Date: Fri, 25 Jul 2025 16:38:28 +0800 Subject: [PATCH] feat: custom pwd of bak (#827) --- lib/core/utils/ssh_auth.dart | 3 +- lib/data/model/app/bak/backup2.dart | 18 +- lib/data/model/app/bak/backup_service.dart | 198 +++++++++++++++++++++ lib/data/model/app/bak/backup_source.dart | 62 +++++++ lib/data/model/app/bak/utils.dart | 4 +- lib/data/store/setting.dart | 3 + lib/generated/l10n/l10n.dart | 50 +++++- lib/generated/l10n/l10n_de.dart | 27 ++- lib/generated/l10n/l10n_en.dart | 27 ++- lib/generated/l10n/l10n_es.dart | 27 ++- lib/generated/l10n/l10n_fr.dart | 27 ++- lib/generated/l10n/l10n_id.dart | 27 ++- lib/generated/l10n/l10n_ja.dart | 27 ++- lib/generated/l10n/l10n_nl.dart | 27 ++- lib/generated/l10n/l10n_pt.dart | 27 ++- lib/generated/l10n/l10n_ru.dart | 27 ++- lib/generated/l10n/l10n_tr.dart | 27 ++- lib/generated/l10n/l10n_uk.dart | 27 ++- lib/generated/l10n/l10n_zh.dart | 52 +++++- lib/l10n/app_de.arb | 10 +- lib/l10n/app_en.arb | 10 +- lib/l10n/app_es.arb | 10 +- lib/l10n/app_fr.arb | 10 +- lib/l10n/app_id.arb | 10 +- lib/l10n/app_ja.arb | 10 +- lib/l10n/app_nl.arb | 10 +- lib/l10n/app_pt.arb | 10 +- lib/l10n/app_ru.arb | 10 +- lib/l10n/app_tr.arb | 10 +- lib/l10n/app_uk.arb | 10 +- lib/l10n/app_zh.arb | 10 +- lib/l10n/app_zh_tw.arb | 10 +- lib/view/page/backup.dart | 184 +++++-------------- lib/view/page/private_key/edit.dart | 2 +- lib/view/page/server/edit.dart | 6 +- pubspec.lock | 4 +- pubspec.yaml | 2 +- 37 files changed, 779 insertions(+), 236 deletions(-) create mode 100644 lib/data/model/app/bak/backup_service.dart create mode 100644 lib/data/model/app/bak/backup_source.dart diff --git a/lib/core/utils/ssh_auth.dart b/lib/core/utils/ssh_auth.dart index c489712e..1280be9a 100644 --- a/lib/core/utils/ssh_auth.dart +++ b/lib/core/utils/ssh_auth.dart @@ -2,7 +2,6 @@ import 'dart:async'; import 'package:fl_lib/fl_lib.dart'; import 'package:flutter/material.dart'; -import 'package:server_box/core/extension/context/locale.dart'; import 'package:server_box/data/model/server/server_private_info.dart'; import 'package:server_box/data/provider/app.dart'; @@ -13,7 +12,7 @@ abstract final class KeybordInteractive { }) async { try { final res = await (ctx ?? AppProvider.ctx)?.showPwdDialog( - title: l10n.pwd, + title: libL10n.pwd, id: spi.id, label: spi.id, ); diff --git a/lib/data/model/app/bak/backup2.dart b/lib/data/model/app/bak/backup2.dart index 80f6b75a..efe6629d 100644 --- a/lib/data/model/app/bak/backup2.dart +++ b/lib/data/model/app/bak/backup2.dart @@ -74,15 +74,27 @@ abstract class BackupV2 with _$BackupV2 implements Mergeable { ); } - static Future backup([String? name]) async { + static Future backup([String? name, String? password]) async { final bak = await BackupV2.loadFromStore(); - final result = json.encode(bak.toJson()); + var result = json.encode(bak.toJson()); + + if (password != null && password.isNotEmpty) { + result = Cryptor.encrypt(result, password); + } + final path = Paths.doc.joinPath(name ?? Miscs.bakFileName); await File(path).writeAsString(result); return path; } - factory BackupV2.fromJsonString(String jsonString) { + factory BackupV2.fromJsonString(String jsonString, [String? password]) { + if (Cryptor.isEncrypted(jsonString)) { + if (password == null || password.isEmpty) { + throw Exception('Backup is encrypted but no password provided'); + } + jsonString = Cryptor.decrypt(jsonString, password); + } + final map = json.decode(jsonString) as Map; return BackupV2.fromJson(map); } diff --git a/lib/data/model/app/bak/backup_service.dart b/lib/data/model/app/bak/backup_service.dart new file mode 100644 index 00000000..fd31bcc8 --- /dev/null +++ b/lib/data/model/app/bak/backup_service.dart @@ -0,0 +1,198 @@ +import 'package:computer/computer.dart'; +import 'package:fl_lib/fl_lib.dart'; +import 'package:flutter/material.dart'; +import 'package:server_box/core/extension/context/locale.dart'; +import 'package:server_box/data/model/app/bak/backup2.dart'; +import 'package:server_box/data/model/app/bak/backup_source.dart'; +import 'package:server_box/data/model/app/bak/utils.dart'; +import 'package:server_box/data/res/store.dart'; + +/// Service class for handling backup operations +class BackupService { + /// Perform backup operation with the given source + static Future backup(BuildContext context, BackupSource source) async { + final password = await _getBackupPassword(context); + if (password == null) return; + + try { + final path = await BackupV2.backup(null, password.isEmpty ? null : password); + await source.saveContent(path); + + // Show success message for clipboard source + if (source is ClipboardBackupSource) { + context.showSnackBar(libL10n.success); + } + } catch (e, s) { + context.showErrDialog(e, s, libL10n.backup); + } + } + + /// Perform restore operation with the given source + static Future restore(BuildContext context, BackupSource source) async { + final text = await source.getContent(); + if (text == null) { + // Show empty message for clipboard source + if (source is ClipboardBackupSource) { + context.showSnackBar(libL10n.empty); + } + return; + } + + await restoreFromText(context, text); + } + + /// Handle password dialog for backup operations + static Future _getBackupPassword(BuildContext context) async { + final savedPassword = await Stores.setting.backupasswd.read(); + String? password; + + if (savedPassword != null && savedPassword.isNotEmpty) { + // Use saved password or ask for custom password + final useCustom = await context.showRoundDialog( + title: l10n.backupPassword, + child: Text(l10n.backupPasswordTip), + actions: [ + Btn.cancel(), + TextButton(onPressed: () => context.pop(false), child: Text(l10n.backupPasswordSet)), + TextButton(onPressed: () => context.pop(true), child: Text(libL10n.custom)), + ], + ); + + if (useCustom == null) return null; + + if (useCustom) { + password = await _showPasswordDialog(context, initial: savedPassword); + } else { + password = savedPassword; + } + } else { + // No saved password, ask if user wants to set one + password = await _showPasswordDialog(context); + } + + return password; + } + + /// Handle restore from text with decryption support + static Future restoreFromText(BuildContext context, String text) async { + // Check if backup is encrypted + final isEncrypted = Cryptor.isEncrypted(text); + String? password; + + if (!isEncrypted) { + try { + final (backup, err) = await context.showLoadingDialog( + fn: () => Computer.shared.start(MergeableUtils.fromJsonString, text), + ); + if (err != null || backup == null) return; + + await _confirmAndRestore(context, backup); + } catch (e, s) { + Loggers.app.warning('Import backup failed', e, s); + context.showErrDialog(e, s, libL10n.restore); + } + return; + } + + // Try with saved password first + final savedPassword = await Stores.setting.backupasswd.read(); + if (savedPassword != null && savedPassword.isNotEmpty) { + try { + final (backup, err) = await context.showLoadingDialog( + fn: () => Computer.shared.start((args) => MergeableUtils.fromJsonString(args.$1, args.$2), ( + text, + savedPassword, + )), + ); + if (err == null && backup != null) { + await _confirmAndRestore(context, backup); + return; + } + } catch (e) { + // Saved password failed, will prompt for manual input + } + } + + // Prompt for password with retry logic + while (true) { + password = await _showPasswordDialog(context, title: libL10n.pwd, hint: l10n.backupEncrypted); + if (password == null) return; // User cancelled + + try { + final (backup, err) = await context.showLoadingDialog( + fn: () => Computer.shared.start((args) => MergeableUtils.fromJsonString(args.$1, args.$2), ( + text, + password, + )), + ); + if (err != null || backup == null) continue; + + await _confirmAndRestore(context, backup); + return; + } catch (e) { + if (e.toString().contains('incorrect password') || e.toString().contains('Failed to decrypt')) { + final retry = await context.showRoundDialog( + title: l10n.backupPasswordWrong, + child: Text(l10n.backupPasswordWrong), + actions: [ + TextButton(onPressed: () => context.pop(false), child: Text(libL10n.cancel)), + TextButton(onPressed: () => context.pop(true), child: Text(libL10n.retry)), + ], + ); + if (retry != true) return; + continue; // Try again + } else { + // Other error, show and exit + context.showErrDialog(e, null, libL10n.restore); + return; + } + } + } + } + + /// Confirm and execute restore operation + static Future _confirmAndRestore(BuildContext context, (dynamic, String) backup) async { + await context.showRoundDialog( + title: libL10n.restore, + child: Text(libL10n.askContinue('${libL10n.restore} ${libL10n.backup}(${backup.$2})')), + actions: Btn.ok( + onTap: () async { + await backup.$1.merge(force: true); + context.pop(); + }, + ).toList, + ); + } + + /// Show password input dialog + static Future _showPasswordDialog( + BuildContext context, { + String? initial, + String? title, + String? hint, + }) async { + final controller = TextEditingController(text: initial ?? ''); + final result = await context.showRoundDialog( + title: title ?? libL10n.pwd, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text(hint ?? l10n.backupPasswordTip, style: UIs.textGrey), + UIs.height13, + Input( + label: l10n.backupPassword, + controller: controller, + obscureText: true, + onSubmitted: (_) => context.pop(controller.text), + ), + ], + ), + actions: [ + Btn.cancel(), + TextButton(onPressed: () => context.pop(controller.text), child: Text(libL10n.ok)), + ], + ); + controller.dispose(); + return result; + } +} diff --git a/lib/data/model/app/bak/backup_source.dart b/lib/data/model/app/bak/backup_source.dart new file mode 100644 index 00000000..44c8a545 --- /dev/null +++ b/lib/data/model/app/bak/backup_source.dart @@ -0,0 +1,62 @@ +import 'dart:io'; + +import 'package:fl_lib/fl_lib.dart'; +import 'package:flutter/material.dart'; + +/// Abstract interface for backup content sources +abstract class BackupSource { + /// Get content from this source for restore + Future getContent(); + + /// Save content to this source for backup + Future saveContent(String filePath); + + /// Display name for this source + String get displayName; + + /// Icon for this source + IconData get icon; +} + +/// File-based backup source +class FileBackupSource implements BackupSource { + @override + Future getContent() async { + return await Pfs.pickFileString(); + } + + @override + Future saveContent(String filePath) async { + await Pfs.sharePaths(paths: [filePath]); + } + + @override + String get displayName => libL10n.file; + + @override + IconData get icon => Icons.file_open; +} + +/// Clipboard-based backup source +class ClipboardBackupSource implements BackupSource { + @override + Future getContent() async { + final text = await Pfs.paste(); + if (text == null || text.isEmpty) { + return null; + } + return text.trim(); + } + + @override + Future saveContent(String filePath) async { + final content = await File(filePath).readAsString(); + Pfs.copy(content); + } + + @override + String get displayName => libL10n.clipboard; + + @override + IconData get icon => Icons.content_paste; +} \ No newline at end of file diff --git a/lib/data/model/app/bak/utils.dart b/lib/data/model/app/bak/utils.dart index e378cfeb..bdb3b318 100644 --- a/lib/data/model/app/bak/utils.dart +++ b/lib/data/model/app/bak/utils.dart @@ -3,9 +3,9 @@ import 'package:server_box/data/model/app/bak/backup.dart'; import 'package:server_box/data/model/app/bak/backup2.dart'; abstract final class MergeableUtils { - static (Mergeable, String) fromJsonString(String json) { + static (Mergeable, String) fromJsonString(String json, [String? password]) { try { - final bak = BackupV2.fromJsonString(json); + final bak = BackupV2.fromJsonString(json, password); return (bak, DateTime.fromMillisecondsSinceEpoch(bak.date).hms()); } catch (e) { final bak = Backup.fromJsonString(json); diff --git a/lib/data/store/setting.dart b/lib/data/store/setting.dart index 6ff84dca..8a9dfe2c 100644 --- a/lib/data/store/setting.dart +++ b/lib/data/store/setting.dart @@ -270,4 +270,7 @@ class SettingStore extends HiveStore { /// Have notified user for notificaiton permission or not late final noNotiPerm = propertyDefault('noNotiPerm', false); + + /// The backup password + late final backupasswd = SecureProp('bakPasswd'); } diff --git a/lib/generated/l10n/l10n.dart b/lib/generated/l10n/l10n.dart index 403e504c..b4b85409 100644 --- a/lib/generated/l10n/l10n.dart +++ b/lib/generated/l10n/l10n.dart @@ -188,7 +188,7 @@ abstract class AppLocalizations { /// No description provided for @backupTip. /// /// In en, this message translates to: - /// **'The exported data is weakly encrypted. \nPlease keep it safe.'** + /// **'The exported data can be encrypted with password. \nPlease keep it safe.'** String get backupTip; /// No description provided for @backupVersionNotMatch. @@ -197,6 +197,48 @@ abstract class AppLocalizations { /// **'Backup version is not match.'** String get backupVersionNotMatch; + /// No description provided for @backupPassword. + /// + /// In en, this message translates to: + /// **'Backup password'** + String get backupPassword; + + /// No description provided for @backupPasswordTip. + /// + /// In en, this message translates to: + /// **'Set a password to encrypt backup files. Leave empty to disable encryption.'** + String get backupPasswordTip; + + /// No description provided for @backupPasswordWrong. + /// + /// In en, this message translates to: + /// **'Incorrect backup password'** + String get backupPasswordWrong; + + /// No description provided for @backupEncrypted. + /// + /// In en, this message translates to: + /// **'Backup is encrypted'** + String get backupEncrypted; + + /// No description provided for @backupNotEncrypted. + /// + /// In en, this message translates to: + /// **'Backup is not encrypted'** + String get backupNotEncrypted; + + /// No description provided for @backupPasswordSet. + /// + /// In en, this message translates to: + /// **'Backup password set'** + String get backupPasswordSet; + + /// No description provided for @backupPasswordRemoved. + /// + /// In en, this message translates to: + /// **'Backup password removed'** + String get backupPasswordRemoved; + /// No description provided for @battery. /// /// In en, this message translates to: @@ -944,12 +986,6 @@ abstract class AppLocalizations { /// **'This feature is currently in the testing phase and has only been tested on PVE 8+. Please use it with caution.'** String get pveVersionLow; - /// No description provided for @pwd. - /// - /// In en, this message translates to: - /// **'Password'** - String get pwd; - /// No description provided for @read. /// /// In en, this message translates to: diff --git a/lib/generated/l10n/l10n_de.dart b/lib/generated/l10n/l10n_de.dart index b1a83a66..a1935a69 100644 --- a/lib/generated/l10n/l10n_de.dart +++ b/lib/generated/l10n/l10n_de.dart @@ -47,12 +47,34 @@ class AppLocalizationsDe extends AppLocalizations { @override String get backupTip => - 'Das Backup wird nur einfach verschlüsselt.\nBitte bewahre die Datei sicher auf.'; + 'Die exportierten Daten können mit einem Passwort verschlüsselt werden. \nBitte sicher aufbewahren.'; @override String get backupVersionNotMatch => 'Die Backup-Version stimmt nicht überein.'; + @override + String get backupPassword => 'Backup-Passwort'; + + @override + String get backupPasswordTip => + 'Setzen Sie ein Passwort, um Backup-Dateien zu verschlüsseln. Leer lassen, um Verschlüsselung zu deaktivieren.'; + + @override + String get backupPasswordWrong => 'Falsches Backup-Passwort'; + + @override + String get backupEncrypted => 'Backup ist verschlüsselt'; + + @override + String get backupNotEncrypted => 'Backup ist nicht verschlüsselt'; + + @override + String get backupPasswordSet => 'Backup-Passwort gesetzt'; + + @override + String get backupPasswordRemoved => 'Backup-Passwort entfernt'; + @override String get battery => 'Batterie'; @@ -470,9 +492,6 @@ class AppLocalizationsDe extends AppLocalizations { String get pveVersionLow => 'Diese Funktion befindet sich derzeit in der Testphase und wurde nur auf PVE 8+ getestet. Bitte verwenden Sie sie mit Vorsicht.'; - @override - String get pwd => 'Passwort'; - @override String get read => 'Lesen'; diff --git a/lib/generated/l10n/l10n_en.dart b/lib/generated/l10n/l10n_en.dart index af98fe06..9b15229a 100644 --- a/lib/generated/l10n/l10n_en.dart +++ b/lib/generated/l10n/l10n_en.dart @@ -47,11 +47,33 @@ class AppLocalizationsEn extends AppLocalizations { @override String get backupTip => - 'The exported data is weakly encrypted. \nPlease keep it safe.'; + 'The exported data can be encrypted with password. \nPlease keep it safe.'; @override String get backupVersionNotMatch => 'Backup version is not match.'; + @override + String get backupPassword => 'Backup password'; + + @override + String get backupPasswordTip => + 'Set a password to encrypt backup files. Leave empty to disable encryption.'; + + @override + String get backupPasswordWrong => 'Incorrect backup password'; + + @override + String get backupEncrypted => 'Backup is encrypted'; + + @override + String get backupNotEncrypted => 'Backup is not encrypted'; + + @override + String get backupPasswordSet => 'Backup password set'; + + @override + String get backupPasswordRemoved => 'Backup password removed'; + @override String get battery => 'Battery'; @@ -468,9 +490,6 @@ class AppLocalizationsEn extends AppLocalizations { String get pveVersionLow => 'This feature is currently in the testing phase and has only been tested on PVE 8+. Please use it with caution.'; - @override - String get pwd => 'Password'; - @override String get read => 'Read'; diff --git a/lib/generated/l10n/l10n_es.dart b/lib/generated/l10n/l10n_es.dart index 64b8e6cc..d13e9203 100644 --- a/lib/generated/l10n/l10n_es.dart +++ b/lib/generated/l10n/l10n_es.dart @@ -47,12 +47,34 @@ class AppLocalizationsEs extends AppLocalizations { @override String get backupTip => - 'Los datos exportados solo están encriptados de manera básica, por favor guárdalos en un lugar seguro.'; + 'Los datos exportados pueden ser encriptados con contraseña. \nPor favor guárdalos en un lugar seguro.'; @override String get backupVersionNotMatch => 'La versión de la copia de seguridad no coincide, no se puede restaurar'; + @override + String get backupPassword => 'Contraseña de respaldo'; + + @override + String get backupPasswordTip => + 'Establece una contraseña para encriptar archivos de respaldo. Déjalo vacío para desactivar la encriptación.'; + + @override + String get backupPasswordWrong => 'Contraseña de respaldo incorrecta'; + + @override + String get backupEncrypted => 'El respaldo está encriptado'; + + @override + String get backupNotEncrypted => 'El respaldo no está encriptado'; + + @override + String get backupPasswordSet => 'Contraseña de respaldo establecida'; + + @override + String get backupPasswordRemoved => 'Contraseña de respaldo eliminada'; + @override String get battery => 'Batería'; @@ -472,9 +494,6 @@ class AppLocalizationsEs extends AppLocalizations { String get pveVersionLow => 'Esta función está actualmente en fase de prueba y solo se ha probado en PVE 8+. Úsela con precaución.'; - @override - String get pwd => 'Contraseña'; - @override String get read => 'Leer'; diff --git a/lib/generated/l10n/l10n_fr.dart b/lib/generated/l10n/l10n_fr.dart index 292db93b..6015bb74 100644 --- a/lib/generated/l10n/l10n_fr.dart +++ b/lib/generated/l10n/l10n_fr.dart @@ -47,12 +47,34 @@ class AppLocalizationsFr extends AppLocalizations { @override String get backupTip => - 'Les données exportées sont simplement chiffrées. \nVeuillez les garder en sécurité.'; + 'Les données exportées peuvent être chiffrées avec un mot de passe. \nVeuillez les garder en sécurité.'; @override String get backupVersionNotMatch => 'La version de sauvegarde ne correspond pas.'; + @override + String get backupPassword => 'Mot de passe de sauvegarde'; + + @override + String get backupPasswordTip => + 'Définissez un mot de passe pour chiffrer les fichiers de sauvegarde. Laissez vide pour désactiver le chiffrement.'; + + @override + String get backupPasswordWrong => 'Mot de passe de sauvegarde incorrect'; + + @override + String get backupEncrypted => 'La sauvegarde est chiffrée'; + + @override + String get backupNotEncrypted => 'La sauvegarde n\'est pas chiffrée'; + + @override + String get backupPasswordSet => 'Mot de passe de sauvegarde défini'; + + @override + String get backupPasswordRemoved => 'Mot de passe de sauvegarde supprimé'; + @override String get battery => 'Batterie'; @@ -473,9 +495,6 @@ class AppLocalizationsFr extends AppLocalizations { String get pveVersionLow => 'Cette fonctionnalité est actuellement en phase de test et n\'a été testée que sur PVE 8+. Veuillez l\'utiliser avec prudence.'; - @override - String get pwd => 'Mot de passe'; - @override String get read => 'Lire'; diff --git a/lib/generated/l10n/l10n_id.dart b/lib/generated/l10n/l10n_id.dart index 37db2aba..9d436769 100644 --- a/lib/generated/l10n/l10n_id.dart +++ b/lib/generated/l10n/l10n_id.dart @@ -47,11 +47,33 @@ class AppLocalizationsId extends AppLocalizations { @override String get backupTip => - 'Data yang diekspor hanya dienkripsi.\nTolong jaga keamanannya.'; + 'Data yang diekspor dapat dienkripsi dengan kata sandi. \nHarap jaga keamanannya.'; @override String get backupVersionNotMatch => 'Versi cadangan tidak cocok.'; + @override + String get backupPassword => 'Kata sandi cadangan'; + + @override + String get backupPasswordTip => + 'Setel kata sandi untuk mengenkripsi file cadangan. Biarkan kosong untuk menonaktifkan enkripsi.'; + + @override + String get backupPasswordWrong => 'Kata sandi cadangan salah'; + + @override + String get backupEncrypted => 'Cadangan telah dienkripsi'; + + @override + String get backupNotEncrypted => 'Cadangan tidak dienkripsi'; + + @override + String get backupPasswordSet => 'Kata sandi cadangan ditetapkan'; + + @override + String get backupPasswordRemoved => 'Kata sandi cadangan dihapus'; + @override String get battery => 'Baterai'; @@ -468,9 +490,6 @@ class AppLocalizationsId extends AppLocalizations { String get pveVersionLow => 'Fitur ini saat ini sedang dalam tahap pengujian dan hanya diuji pada PVE 8+. Gunakan dengan hati-hati.'; - @override - String get pwd => 'Kata sandi'; - @override String get read => 'Baca'; diff --git a/lib/generated/l10n/l10n_ja.dart b/lib/generated/l10n/l10n_ja.dart index 4ee4d7bf..ce52a247 100644 --- a/lib/generated/l10n/l10n_ja.dart +++ b/lib/generated/l10n/l10n_ja.dart @@ -43,11 +43,33 @@ class AppLocalizationsJa extends AppLocalizations { String get autoUpdateHomeWidget => 'ホームウィジェットを自動更新'; @override - String get backupTip => 'エクスポートされたデータは簡単に暗号化されています。適切に保管してください。'; + String get backupTip => 'エクスポートされたデータはパスワードで暗号化できます。 \n適切に保管してください。'; @override String get backupVersionNotMatch => 'バックアップバージョンが一致しないため、復元できません'; + @override + String get backupPassword => 'バックアップパスワード'; + + @override + String get backupPasswordTip => + 'バックアップファイルを暗号化するためのパスワードを設定してください。暗号化を無効にするには空白のままにしてください。'; + + @override + String get backupPasswordWrong => 'バックアップパスワードが間違っています'; + + @override + String get backupEncrypted => 'バックアップは暗号化されています'; + + @override + String get backupNotEncrypted => 'バックアップは暗号化されていません'; + + @override + String get backupPasswordSet => 'バックアップパスワードが設定されました'; + + @override + String get backupPasswordRemoved => 'バックアップパスワードが削除されました'; + @override String get battery => 'バッテリー'; @@ -453,9 +475,6 @@ class AppLocalizationsJa extends AppLocalizations { @override String get pveVersionLow => 'この機能は現在テスト段階にあり、PVE 8+でのみテストされています。ご利用の際は慎重に。'; - @override - String get pwd => 'パスワード'; - @override String get read => '読み取り'; diff --git a/lib/generated/l10n/l10n_nl.dart b/lib/generated/l10n/l10n_nl.dart index 6b4bf61e..bbd05159 100644 --- a/lib/generated/l10n/l10n_nl.dart +++ b/lib/generated/l10n/l10n_nl.dart @@ -47,11 +47,33 @@ class AppLocalizationsNl extends AppLocalizations { @override String get backupTip => - 'De geëxporteerde gegevens zijn simpelweg versleuteld. \nBewaar deze aub veilig.'; + 'De geëxporteerde gegevens kunnen worden versleuteld met een wachtwoord. \nBewaar deze aub veilig.'; @override String get backupVersionNotMatch => 'Back-upversie komt niet overeen.'; + @override + String get backupPassword => 'Back-up wachtwoord'; + + @override + String get backupPasswordTip => + 'Stel een wachtwoord in om back-upbestanden te versleutelen. Laat leeg om versleuteling uit te schakelen.'; + + @override + String get backupPasswordWrong => 'Onjuist back-up wachtwoord'; + + @override + String get backupEncrypted => 'Back-up is versleuteld'; + + @override + String get backupNotEncrypted => 'Back-up is niet versleuteld'; + + @override + String get backupPasswordSet => 'Back-up wachtwoord ingesteld'; + + @override + String get backupPasswordRemoved => 'Back-up wachtwoord verwijderd'; + @override String get battery => 'Batterij'; @@ -469,9 +491,6 @@ class AppLocalizationsNl extends AppLocalizations { String get pveVersionLow => 'Deze functie bevindt zich momenteel in de testfase en is alleen getest op PVE 8+. Gebruik het met voorzichtigheid.'; - @override - String get pwd => 'Wachtwoord'; - @override String get read => 'Lezen'; diff --git a/lib/generated/l10n/l10n_pt.dart b/lib/generated/l10n/l10n_pt.dart index d70bb94b..f5f7aca7 100644 --- a/lib/generated/l10n/l10n_pt.dart +++ b/lib/generated/l10n/l10n_pt.dart @@ -47,12 +47,34 @@ class AppLocalizationsPt extends AppLocalizations { @override String get backupTip => - 'Os dados exportados são criptografados de forma simples, por favor, guarde-os com segurança.'; + 'Os dados exportados podem ser criptografados com senha. \nPor favor, guarde-os com segurança.'; @override String get backupVersionNotMatch => 'Versão de backup não compatível, não é possível restaurar'; + @override + String get backupPassword => 'Senha de backup'; + + @override + String get backupPasswordTip => + 'Defina uma senha para criptografar arquivos de backup. Deixe vazio para desabilitar a criptografia.'; + + @override + String get backupPasswordWrong => 'Senha de backup incorreta'; + + @override + String get backupEncrypted => 'Backup está criptografado'; + + @override + String get backupNotEncrypted => 'Backup não está criptografado'; + + @override + String get backupPasswordSet => 'Senha de backup definida'; + + @override + String get backupPasswordRemoved => 'Senha de backup removida'; + @override String get battery => 'Bateria'; @@ -469,9 +491,6 @@ class AppLocalizationsPt extends AppLocalizations { String get pveVersionLow => 'Esta funcionalidade está atualmente em fase de teste e foi testada apenas no PVE 8+. Por favor, use com cautela.'; - @override - String get pwd => 'Senha'; - @override String get read => 'Leitura'; diff --git a/lib/generated/l10n/l10n_ru.dart b/lib/generated/l10n/l10n_ru.dart index bc8203c3..9bdd64e0 100644 --- a/lib/generated/l10n/l10n_ru.dart +++ b/lib/generated/l10n/l10n_ru.dart @@ -47,12 +47,34 @@ class AppLocalizationsRu extends AppLocalizations { @override String get backupTip => - 'Экспортированные данные зашифрованы простым способом \nПожалуйста, храните их в безопасности.'; + 'Экспортированные данные могут быть зашифрованы паролем. \nПожалуйста, храните их в безопасности.'; @override String get backupVersionNotMatch => 'Версия резервной копии не совпадает, восстановление невозможно'; + @override + String get backupPassword => 'Пароль резервной копии'; + + @override + String get backupPasswordTip => + 'Установите пароль для шифрования файлов резервных копий. Оставьте пустым, чтобы отключить шифрование.'; + + @override + String get backupPasswordWrong => 'Неверный пароль резервной копии'; + + @override + String get backupEncrypted => 'Резервная копия зашифрована'; + + @override + String get backupNotEncrypted => 'Резервная копия не зашифрована'; + + @override + String get backupPasswordSet => 'Пароль резервной копии установлен'; + + @override + String get backupPasswordRemoved => 'Пароль резервной копии удален'; + @override String get battery => 'Батарея'; @@ -470,9 +492,6 @@ class AppLocalizationsRu extends AppLocalizations { String get pveVersionLow => 'Эта функция в настоящее время находится на стадии тестирования и была протестирована только на PVE 8+. Используйте ее с осторожностью.'; - @override - String get pwd => 'Пароль'; - @override String get read => 'Чтение'; diff --git a/lib/generated/l10n/l10n_tr.dart b/lib/generated/l10n/l10n_tr.dart index ce09b6ba..7b2d0f98 100644 --- a/lib/generated/l10n/l10n_tr.dart +++ b/lib/generated/l10n/l10n_tr.dart @@ -46,11 +46,33 @@ class AppLocalizationsTr extends AppLocalizations { @override String get backupTip => - 'Dışa aktarılan veriler zayıf bir şekilde şifrelenmiştir. \nLütfen güvenli bir şekilde saklayın.'; + 'Dışa aktarılan veriler parola ile şifrelenebilir. \nLütfen güvenli bir şekilde saklayın.'; @override String get backupVersionNotMatch => 'Yedekleme sürümü eşleşmiyor.'; + @override + String get backupPassword => 'Yedekleme parolası'; + + @override + String get backupPasswordTip => + 'Yedekleme dosyalarını şifrelemek için bir parola belirleyin. Şifrelemeyi devre dışı bırakmak için boş bırakın.'; + + @override + String get backupPasswordWrong => 'Yanlış yedekleme parolası'; + + @override + String get backupEncrypted => 'Yedekleme şifrelenmiş'; + + @override + String get backupNotEncrypted => 'Yedekleme şifreli değil'; + + @override + String get backupPasswordSet => 'Yedekleme parolası ayarlandı'; + + @override + String get backupPasswordRemoved => 'Yedekleme parolası kaldırıldı'; + @override String get battery => 'Pil'; @@ -467,9 +489,6 @@ class AppLocalizationsTr extends AppLocalizations { String get pveVersionLow => 'Bu özellik şu anda test aşamasında ve yalnızca PVE 8+ üzerinde test edildi. Lütfen dikkatli kullanın.'; - @override - String get pwd => 'Şifre'; - @override String get read => 'Oku'; diff --git a/lib/generated/l10n/l10n_uk.dart b/lib/generated/l10n/l10n_uk.dart index 114f7eaf..bd5b102a 100644 --- a/lib/generated/l10n/l10n_uk.dart +++ b/lib/generated/l10n/l10n_uk.dart @@ -47,12 +47,34 @@ class AppLocalizationsUk extends AppLocalizations { @override String get backupTip => - 'Експортовані дані слабо зашифровані. \nБудь ласка, зберігайте їх у безпеці.'; + 'Експортовані дані можуть бути зашифровані паролем. \nБудь ласка, зберігайте їх у безпеці.'; @override String get backupVersionNotMatch => 'Версія резервного копіювання не збіглася.'; + @override + String get backupPassword => 'Пароль резервного копіювання'; + + @override + String get backupPasswordTip => + 'Встановіть пароль для шифрування файлів резервного копіювання. Залиште порожнім для відключення шифрування.'; + + @override + String get backupPasswordWrong => 'Неправильний пароль резервного копіювання'; + + @override + String get backupEncrypted => 'Резервна копія зашифрована'; + + @override + String get backupNotEncrypted => 'Резервна копія не зашифрована'; + + @override + String get backupPasswordSet => 'Пароль резервного копіювання встановлено'; + + @override + String get backupPasswordRemoved => 'Пароль резервного копіювання видалено'; + @override String get battery => 'Акумулятор'; @@ -472,9 +494,6 @@ class AppLocalizationsUk extends AppLocalizations { String get pveVersionLow => 'Ця функція наразі перебуває на стадії тестування та випробувалася лише на PVE 8+. Будь ласка, використовуйте її з обережністю.'; - @override - String get pwd => 'Пароль'; - @override String get read => 'Читати'; diff --git a/lib/generated/l10n/l10n_zh.dart b/lib/generated/l10n/l10n_zh.dart index 61213141..2dd065b5 100644 --- a/lib/generated/l10n/l10n_zh.dart +++ b/lib/generated/l10n/l10n_zh.dart @@ -42,11 +42,32 @@ class AppLocalizationsZh extends AppLocalizations { String get autoUpdateHomeWidget => '自动更新桌面小部件'; @override - String get backupTip => '导出的数据仅进行了简单加密,请妥善保管。'; + String get backupTip => '导出的数据可以使用密码加密,请妥善保管。'; @override String get backupVersionNotMatch => '备份版本不匹配,无法恢复'; + @override + String get backupPassword => '备份密码'; + + @override + String get backupPasswordTip => '设置密码以加密备份文件。留空则禁用加密。'; + + @override + String get backupPasswordWrong => '备份密码错误'; + + @override + String get backupEncrypted => '备份已加密'; + + @override + String get backupNotEncrypted => '备份未加密'; + + @override + String get backupPasswordSet => '备份密码已设置'; + + @override + String get backupPasswordRemoved => '备份密码已移除'; + @override String get battery => '电池'; @@ -446,9 +467,6 @@ class AppLocalizationsZh extends AppLocalizations { @override String get pveVersionLow => '当前该功能处于测试阶段,仅在 PVE 8+ 上测试过,请谨慎使用'; - @override - String get pwd => '密码'; - @override String get read => '读'; @@ -776,11 +794,32 @@ class AppLocalizationsZhTw extends AppLocalizationsZh { String get autoUpdateHomeWidget => '自動更新桌面小工具'; @override - String get backupTip => '匯出的資料僅進行了簡單加密,請妥善保管。'; + String get backupTip => '匯出的資料可以使用密碼加密。 \n請妥善保管。'; @override String get backupVersionNotMatch => '備份版本不相符,無法還原'; + @override + String get backupPassword => '備份密碼'; + + @override + String get backupPasswordTip => '設定密碼來加密備份檔案。留空則停用加密。'; + + @override + String get backupPasswordWrong => '備份密碼錯誤'; + + @override + String get backupEncrypted => '備份已加密'; + + @override + String get backupNotEncrypted => '備份未加密'; + + @override + String get backupPasswordSet => '備份密碼已設定'; + + @override + String get backupPasswordRemoved => '備份密碼已移除'; + @override String get battery => '電池'; @@ -1180,9 +1219,6 @@ class AppLocalizationsZhTw extends AppLocalizationsZh { @override String get pveVersionLow => '此功能目前處於測試階段,僅在 PVE 8+ 上進行過測試。請謹慎使用。'; - @override - String get pwd => '密碼'; - @override String get read => '讀取'; diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 23ce70ec..dc578e4b 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -11,8 +11,15 @@ "autoConnect": "Automatisch verbinden", "autoRun": "Automatischer Start", "autoUpdateHomeWidget": "Home-Widget automatisch aktualisieren", - "backupTip": "Das Backup wird nur einfach verschlüsselt.\nBitte bewahre die Datei sicher auf.", + "backupTip": "Die exportierten Daten können mit einem Passwort verschlüsselt werden. \nBitte sicher aufbewahren.", "backupVersionNotMatch": "Die Backup-Version stimmt nicht überein.", + "backupPassword": "Backup-Passwort", + "backupPasswordTip": "Setzen Sie ein Passwort, um Backup-Dateien zu verschlüsseln. Leer lassen, um Verschlüsselung zu deaktivieren.", + "backupPasswordWrong": "Falsches Backup-Passwort", + "backupEncrypted": "Backup ist verschlüsselt", + "backupNotEncrypted": "Backup ist nicht verschlüsselt", + "backupPasswordSet": "Backup-Passwort gesetzt", + "backupPasswordRemoved": "Backup-Passwort entfernt", "battery": "Batterie", "bgRun": "Hintergrundaktualisierung", "bgRunTip": "Dieser Schalter bedeutet nur, dass die App versuchen wird, im Hintergrund zu laufen. Ob sie im Hintergrund laufen kann, hängt davon ab, ob die Berechtigungen aktiviert sind oder nicht. Bei nativem Android deaktivieren Sie bitte \"Batterieoptimierung\" in dieser App, und bei miui ändern Sie bitte die Energiesparrichtlinie auf \"Unbegrenzt\".", @@ -137,7 +144,6 @@ "pveIgnoreCertTip": "Nicht empfohlen, Achten Sie auf Sicherheitsrisiken! Wenn Sie das Standardzertifikat von PVE verwenden, müssen Sie diese Option aktivieren.", "pveLoginFailed": "Anmeldung fehlgeschlagen. Kann nicht mit Benutzername/Passwort aus der Serverkonfiguration angemeldet werden, um sich über Linux PAM anzumelden.", "pveVersionLow": "Diese Funktion befindet sich derzeit in der Testphase und wurde nur auf PVE 8+ getestet. Bitte verwenden Sie sie mit Vorsicht.", - "pwd": "Passwort", "read": "Lesen", "reboot": "Neustart", "rememberPwdInMem": "Passwort im Speicher behalten", diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 62114417..ea8423c5 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -11,8 +11,15 @@ "autoConnect": "Auto connect", "autoRun": "Auto run", "autoUpdateHomeWidget": "Automatic home widget update", - "backupTip": "The exported data is weakly encrypted. \nPlease keep it safe.", + "backupTip": "The exported data can be encrypted with password. \nPlease keep it safe.", "backupVersionNotMatch": "Backup version is not match.", + "backupPassword": "Backup password", + "backupPasswordTip": "Set a password to encrypt backup files. Leave empty to disable encryption.", + "backupPasswordWrong": "Incorrect backup password", + "backupEncrypted": "Backup is encrypted", + "backupNotEncrypted": "Backup is not encrypted", + "backupPasswordSet": "Backup password set", + "backupPasswordRemoved": "Backup password removed", "battery": "Battery", "bgRun": "Run in background", "bgRunTip": "This switch only means the program will try to run in the background. Whether it can run in the background depends on whether the permission is enabled or not. For AOSP-based Android ROMs, please disable \"Battery Optimization\" in this app. For MIUI / HyperOS, please change the power saving policy to \"Unlimited\".", @@ -137,7 +144,6 @@ "pveIgnoreCertTip": "Not recommended to enable, beware of security risks! If you are using the default certificate from PVE, you need to enable this option.", "pveLoginFailed": "Login failed. Unable to authenticate with username/password from server configuration for Linux PAM login.", "pveVersionLow": "This feature is currently in the testing phase and has only been tested on PVE 8+. Please use it with caution.", - "pwd": "Password", "read": "Read", "reboot": "Reboot", "rememberPwdInMem": "Remember password in memory", diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index c2632dda..deb87b43 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -11,8 +11,15 @@ "autoConnect": "Conexión automática", "autoRun": "Ejecución automática", "autoUpdateHomeWidget": "Actualizar automáticamente el widget del escritorio", - "backupTip": "Los datos exportados solo están encriptados de manera básica, por favor guárdalos en un lugar seguro.", + "backupTip": "Los datos exportados pueden ser encriptados con contraseña. \nPor favor guárdalos en un lugar seguro.", "backupVersionNotMatch": "La versión de la copia de seguridad no coincide, no se puede restaurar", + "backupPassword": "Contraseña de respaldo", + "backupPasswordTip": "Establece una contraseña para encriptar archivos de respaldo. Déjalo vacío para desactivar la encriptación.", + "backupPasswordWrong": "Contraseña de respaldo incorrecta", + "backupEncrypted": "El respaldo está encriptado", + "backupNotEncrypted": "El respaldo no está encriptado", + "backupPasswordSet": "Contraseña de respaldo establecida", + "backupPasswordRemoved": "Contraseña de respaldo eliminada", "battery": "Batería", "bgRun": "Ejecución en segundo plano", "bgRunTip": "Este interruptor solo indica que la aplicación intentará correr en segundo plano, si puede hacerlo o no depende de si tiene el permiso correspondiente. En Android puro, por favor desactiva la “optimización de batería” para esta app, en MIUI por favor cambia la estrategia de ahorro de energía a “Sin restricciones”.", @@ -137,7 +144,6 @@ "pveIgnoreCertTip": "No se recomienda activarlo, ¡tenga cuidado con los riesgos de seguridad! Si está utilizando el certificado predeterminado de PVE, debe habilitar esta opción.", "pveLoginFailed": "Fallo al iniciar sesión. No se puede autenticar con el nombre de usuario/contraseña de la configuración del servidor para el inicio de sesión de Linux PAM.", "pveVersionLow": "Esta función está actualmente en fase de prueba y solo se ha probado en PVE 8+. Úsela con precaución.", - "pwd": "Contraseña", "read": "Leer", "reboot": "Reiniciar", "rememberPwdInMem": "Recordar contraseña en la memoria", diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index d50a7d1a..6ab3bb1f 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -11,8 +11,15 @@ "autoConnect": "Connexion automatique", "autoRun": "Exécution automatique", "autoUpdateHomeWidget": "Mise à jour automatique du widget d'accueil", - "backupTip": "Les données exportées sont simplement chiffrées. \nVeuillez les garder en sécurité.", + "backupTip": "Les données exportées peuvent être chiffrées avec un mot de passe. \nVeuillez les garder en sécurité.", "backupVersionNotMatch": "La version de sauvegarde ne correspond pas.", + "backupPassword": "Mot de passe de sauvegarde", + "backupPasswordTip": "Définissez un mot de passe pour chiffrer les fichiers de sauvegarde. Laissez vide pour désactiver le chiffrement.", + "backupPasswordWrong": "Mot de passe de sauvegarde incorrect", + "backupEncrypted": "La sauvegarde est chiffrée", + "backupNotEncrypted": "La sauvegarde n'est pas chiffrée", + "backupPasswordSet": "Mot de passe de sauvegarde défini", + "backupPasswordRemoved": "Mot de passe de sauvegarde supprimé", "battery": "Batterie", "bgRun": "Exécution en arrière-plan", "bgRunTip": "Cette option signifie seulement que le programme essaiera de s'exécuter en arrière-plan, que cela soit possible dépend de l'autorisation activée ou non. Pour Android natif, veuillez désactiver l'« Optimisation de la batterie » dans cette application, et pour MIUI, veuillez changer la politique d'économie d'énergie en « Illimité ».", @@ -137,7 +144,6 @@ "pveIgnoreCertTip": "Il n'est pas recommandé de l'activer, attention aux risques de sécurité ! Si vous utilisez le certificat par défaut de PVE, vous devez activer cette option.", "pveLoginFailed": "Échec de la connexion. Impossible d'authentifier avec le nom d'utilisateur / mot de passe de la configuration du serveur pour la connexion Linux PAM.", "pveVersionLow": "Cette fonctionnalité est actuellement en phase de test et n'a été testée que sur PVE 8+. Veuillez l'utiliser avec prudence.", - "pwd": "Mot de passe", "read": "Lire", "reboot": "Redémarrer", "rememberPwdInMem": "Mémoriser le mot de passe en mémoire", diff --git a/lib/l10n/app_id.arb b/lib/l10n/app_id.arb index d2084db9..5fd1a3f6 100644 --- a/lib/l10n/app_id.arb +++ b/lib/l10n/app_id.arb @@ -11,8 +11,15 @@ "autoConnect": "Hubungkan otomatis", "autoRun": "Berjalan Otomatis", "autoUpdateHomeWidget": "Widget Rumah Pembaruan Otomatis", - "backupTip": "Data yang diekspor hanya dienkripsi.\nTolong jaga keamanannya.", + "backupTip": "Data yang diekspor dapat dienkripsi dengan kata sandi. \nHarap jaga keamanannya.", "backupVersionNotMatch": "Versi cadangan tidak cocok.", + "backupPassword": "Kata sandi cadangan", + "backupPasswordTip": "Setel kata sandi untuk mengenkripsi file cadangan. Biarkan kosong untuk menonaktifkan enkripsi.", + "backupPasswordWrong": "Kata sandi cadangan salah", + "backupEncrypted": "Cadangan telah dienkripsi", + "backupNotEncrypted": "Cadangan tidak dienkripsi", + "backupPasswordSet": "Kata sandi cadangan ditetapkan", + "backupPasswordRemoved": "Kata sandi cadangan dihapus", "battery": "Baterai", "bgRun": "Jalankan di Backgroud", "bgRunTip": "Sakelar ini hanya berarti aplikasi akan mencoba berjalan di latar belakang, apakah aplikasi dapat berjalan di latar belakang tergantung pada apakah izin diaktifkan atau tidak. Untuk Android asli, nonaktifkan \"Pengoptimalan Baterai\" di aplikasi ini, dan untuk miui, ubah kebijakan penghematan daya ke \"Tidak Terbatas\".", @@ -137,7 +144,6 @@ "pveIgnoreCertTip": "Tidak disarankan untuk diaktifkan, waspadai risiko keamanan! Jika Anda menggunakan sertifikat default dari PVE, Anda perlu mengaktifkan opsi ini.", "pveLoginFailed": "Login gagal. Tidak dapat mengautentikasi dengan nama pengguna/kata sandi dari konfigurasi server untuk login Linux PAM.", "pveVersionLow": "Fitur ini saat ini sedang dalam tahap pengujian dan hanya diuji pada PVE 8+. Gunakan dengan hati-hati.", - "pwd": "Kata sandi", "read": "Baca", "reboot": "Reboot", "rememberPwdInMem": "Ingat kata sandi di dalam memori", diff --git a/lib/l10n/app_ja.arb b/lib/l10n/app_ja.arb index fdea0ddd..a07ae09b 100644 --- a/lib/l10n/app_ja.arb +++ b/lib/l10n/app_ja.arb @@ -11,8 +11,15 @@ "autoConnect": "自動接続", "autoRun": "自動実行", "autoUpdateHomeWidget": "ホームウィジェットを自動更新", - "backupTip": "エクスポートされたデータは簡単に暗号化されています。適切に保管してください。", + "backupTip": "エクスポートされたデータはパスワードで暗号化できます。 \n適切に保管してください。", "backupVersionNotMatch": "バックアップバージョンが一致しないため、復元できません", + "backupPassword": "バックアップパスワード", + "backupPasswordTip": "バックアップファイルを暗号化するためのパスワードを設定してください。暗号化を無効にするには空白のままにしてください。", + "backupPasswordWrong": "バックアップパスワードが間違っています", + "backupEncrypted": "バックアップは暗号化されています", + "backupNotEncrypted": "バックアップは暗号化されていません", + "backupPasswordSet": "バックアップパスワードが設定されました", + "backupPasswordRemoved": "バックアップパスワードが削除されました", "battery": "バッテリー", "bgRun": "バックグラウンド実行", "bgRunTip": "このスイッチはプログラムがバックグラウンドで実行を試みることを意味しますが、実際にバックグラウンドで実行できるかどうかは、権限が有効になっているかに依存します。AOSPベースのAndroid ROMでは、このアプリの「バッテリー最適化」をオフにしてください。MIUIでは、省エネモードを「無制限」に変更してください。", @@ -137,7 +144,6 @@ "pveIgnoreCertTip": "オプションを有効にすることは推奨されません、セキュリティリスクに注意してください!PVEのデフォルト証明書を使用している場合は、このオプションを有効にする必要があります。", "pveLoginFailed": "ログインに失敗しました。Linux PAMログインのためにサーバー構成からのユーザー名/パスワードで認証できません。", "pveVersionLow": "この機能は現在テスト段階にあり、PVE 8+でのみテストされています。ご利用の際は慎重に。", - "pwd": "パスワード", "read": "読み取り", "reboot": "再起動", "rememberPwdInMem": "メモリにパスワードを記憶する", diff --git a/lib/l10n/app_nl.arb b/lib/l10n/app_nl.arb index f4f262ff..9bc4a2d3 100644 --- a/lib/l10n/app_nl.arb +++ b/lib/l10n/app_nl.arb @@ -11,8 +11,15 @@ "autoConnect": "Automatisch verbinden", "autoRun": "Automatisch uitvoeren", "autoUpdateHomeWidget": "Automatische update van home-widget", - "backupTip": "De geëxporteerde gegevens zijn simpelweg versleuteld. \nBewaar deze aub veilig.", + "backupTip": "De geëxporteerde gegevens kunnen worden versleuteld met een wachtwoord. \nBewaar deze aub veilig.", "backupVersionNotMatch": "Back-upversie komt niet overeen.", + "backupPassword": "Back-up wachtwoord", + "backupPasswordTip": "Stel een wachtwoord in om back-upbestanden te versleutelen. Laat leeg om versleuteling uit te schakelen.", + "backupPasswordWrong": "Onjuist back-up wachtwoord", + "backupEncrypted": "Back-up is versleuteld", + "backupNotEncrypted": "Back-up is niet versleuteld", + "backupPasswordSet": "Back-up wachtwoord ingesteld", + "backupPasswordRemoved": "Back-up wachtwoord verwijderd", "battery": "Batterij", "bgRun": "Uitvoeren op de achtergrond", "bgRunTip": "Deze schakelaar betekent alleen dat het programma zal proberen op de achtergrond uit te voeren, of het in de achtergrond kan worden uitgevoerd, hangt af van of de toestemming is ingeschakeld of niet. Voor native Android, schakel \"Batterijoptimalisatie\" uit in deze app, en voor miui, wijzig de energiebesparingsbeleid naar \"Onbeperkt\".", @@ -137,7 +144,6 @@ "pveIgnoreCertTip": "Niet aanbevolen om in te schakelen, let op beveiligingsrisico's! Als u de standaardcertificaat van PVE gebruikt, moet u deze optie inschakelen.", "pveLoginFailed": "Aanmelden mislukt. Kan niet authenticeren met gebruikersnaam/wachtwoord van serverconfiguratie voor Linux PAM-login.", "pveVersionLow": "Deze functie bevindt zich momenteel in de testfase en is alleen getest op PVE 8+. Gebruik het met voorzichtigheid.", - "pwd": "Wachtwoord", "read": "Lezen", "reboot": "Herstart", "rememberPwdInMem": "Wachtwoord onthouden in geheugen", diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index fe3e7e4f..c52b8d14 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -11,8 +11,15 @@ "autoConnect": "Conexão automática", "autoRun": "Execução automática", "autoUpdateHomeWidget": "Atualização automática do widget da tela inicial", - "backupTip": "Os dados exportados são criptografados de forma simples, por favor, guarde-os com segurança.", + "backupTip": "Os dados exportados podem ser criptografados com senha. \nPor favor, guarde-os com segurança.", "backupVersionNotMatch": "Versão de backup não compatível, não é possível restaurar", + "backupPassword": "Senha de backup", + "backupPasswordTip": "Defina uma senha para criptografar arquivos de backup. Deixe vazio para desabilitar a criptografia.", + "backupPasswordWrong": "Senha de backup incorreta", + "backupEncrypted": "Backup está criptografado", + "backupNotEncrypted": "Backup não está criptografado", + "backupPasswordSet": "Senha de backup definida", + "backupPasswordRemoved": "Senha de backup removida", "battery": "Bateria", "bgRun": "Execução em segundo plano", "bgRunTip": "Este interruptor indica que o programa tentará rodar em segundo plano, mas a capacidade de fazer isso depende das permissões concedidas. No Android nativo, desative a 'Otimização de bateria' para este app, no MIUI, altere a estratégia de economia de energia para 'Sem restrições'.", @@ -137,7 +144,6 @@ "pveIgnoreCertTip": "Não recomendado para ativar, cuidado com os riscos de segurança! Se estiver usando o certificado padrão do PVE, você precisa habilitar esta opção.", "pveLoginFailed": "Falha no login. Não é possível autenticar com o nome de usuário/senha da configuração do servidor para login no Linux PAM.", "pveVersionLow": "Esta funcionalidade está atualmente em fase de teste e foi testada apenas no PVE 8+. Por favor, use com cautela.", - "pwd": "Senha", "read": "Leitura", "reboot": "Reiniciar", "rememberPwdInMem": "Lembrar senha na memória", diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb index e88fc685..d2e5c669 100644 --- a/lib/l10n/app_ru.arb +++ b/lib/l10n/app_ru.arb @@ -11,8 +11,15 @@ "autoConnect": "Автоматическое подключение", "autoRun": "Автозапуск", "autoUpdateHomeWidget": "Автоматическое обновление виджета на главном экране", - "backupTip": "Экспортированные данные зашифрованы простым способом \nПожалуйста, храните их в безопасности.", + "backupTip": "Экспортированные данные могут быть зашифрованы паролем. \nПожалуйста, храните их в безопасности.", "backupVersionNotMatch": "Версия резервной копии не совпадает, восстановление невозможно", + "backupPassword": "Пароль резервной копии", + "backupPasswordTip": "Установите пароль для шифрования файлов резервных копий. Оставьте пустым, чтобы отключить шифрование.", + "backupPasswordWrong": "Неверный пароль резервной копии", + "backupEncrypted": "Резервная копия зашифрована", + "backupNotEncrypted": "Резервная копия не зашифрована", + "backupPasswordSet": "Пароль резервной копии установлен", + "backupPasswordRemoved": "Пароль резервной копии удален", "battery": "Батарея", "bgRun": "Работа в фоновом режиме", "bgRunTip": "Этот переключатель означает, что программа будет пытаться работать в фоновом режиме, но фактическое выполнение зависит от того, включено ли разрешение. Для нативного Android отключите «Оптимизацию батареи» для этого приложения, для MIUI измените контроль активности на «Нет ограничений».", @@ -137,7 +144,6 @@ "pveIgnoreCertTip": "Не рекомендуется включать, обратите внимание на риски безопасности! Если вы используете стандартный сертификат от PVE, вам нужно включить эту опцию.", "pveLoginFailed": "Ошибка входа. Невозможно аутентифицироваться с помощью имени пользователя/пароля из конфигурации сервера для входа в Linux PAM.", "pveVersionLow": "Эта функция в настоящее время находится на стадии тестирования и была протестирована только на PVE 8+. Используйте ее с осторожностью.", - "pwd": "Пароль", "read": "Чтение", "reboot": "Перезагрузка", "rememberPwdInMem": "Запомнить пароль в памяти", diff --git a/lib/l10n/app_tr.arb b/lib/l10n/app_tr.arb index f0555699..43926367 100644 --- a/lib/l10n/app_tr.arb +++ b/lib/l10n/app_tr.arb @@ -11,8 +11,15 @@ "autoConnect": "Otomatik bağlan", "autoRun": "Otomatik çalıştır", "autoUpdateHomeWidget": "Ana ekran bileşenini otomatik güncelle", - "backupTip": "Dışa aktarılan veriler zayıf bir şekilde şifrelenmiştir. \nLütfen güvenli bir şekilde saklayın.", + "backupTip": "Dışa aktarılan veriler parola ile şifrelenebilir. \nLütfen güvenli bir şekilde saklayın.", "backupVersionNotMatch": "Yedekleme sürümü eşleşmiyor.", + "backupPassword": "Yedekleme parolası", + "backupPasswordTip": "Yedekleme dosyalarını şifrelemek için bir parola belirleyin. Şifrelemeyi devre dışı bırakmak için boş bırakın.", + "backupPasswordWrong": "Yanlış yedekleme parolası", + "backupEncrypted": "Yedekleme şifrelenmiş", + "backupNotEncrypted": "Yedekleme şifreli değil", + "backupPasswordSet": "Yedekleme parolası ayarlandı", + "backupPasswordRemoved": "Yedekleme parolası kaldırıldı", "battery": "Pil", "bgRun": "Arka planda çalıştır", "bgRunTip": "Bu anahtar yalnızca programın arka planda çalışmayı deneyeceği anlamına gelir. Arka planda çalışıp çalışamayacağı, iznin etkinleştirilip etkinleştirilmediğine bağlıdır. AOSP tabanlı Android ROM'lar için lütfen bu uygulamada \"Pil Optimizasyonu\"nu devre dışı bırakın. MIUI / HyperOS için lütfen güç tasarrufu politikasını \"Sınırsız\" olarak değiştirin.", @@ -137,7 +144,6 @@ "pveIgnoreCertTip": "Etkinleştirilmesi önerilmez, güvenlik risklerine dikkat edin! PVE'den varsayılan sertifikayı kullanıyorsanız, bu seçeneği etkinleştirmeniz gerekir.", "pveLoginFailed": "Giriş başarısız. Linux PAM girişi için sunucu yapılandırmasındaki kullanıcı adı/şifre ile kimlik doğrulama yapılamadı.", "pveVersionLow": "Bu özellik şu anda test aşamasında ve yalnızca PVE 8+ üzerinde test edildi. Lütfen dikkatli kullanın.", - "pwd": "Şifre", "read": "Oku", "reboot": "Yeniden başlat", "rememberPwdInMem": "Şifreyi bellekte hatırla", diff --git a/lib/l10n/app_uk.arb b/lib/l10n/app_uk.arb index 521949d1..994c69d8 100644 --- a/lib/l10n/app_uk.arb +++ b/lib/l10n/app_uk.arb @@ -11,8 +11,15 @@ "autoConnect": "Авто підключення", "autoRun": "Авто запуск", "autoUpdateHomeWidget": "Автоматичне оновлення віджетів на головному екрані", - "backupTip": "Експортовані дані слабо зашифровані. \nБудь ласка, зберігайте їх у безпеці.", + "backupTip": "Експортовані дані можуть бути зашифровані паролем. \nБудь ласка, зберігайте їх у безпеці.", "backupVersionNotMatch": "Версія резервного копіювання не збіглася.", + "backupPassword": "Пароль резервного копіювання", + "backupPasswordTip": "Встановіть пароль для шифрування файлів резервного копіювання. Залиште порожнім для відключення шифрування.", + "backupPasswordWrong": "Неправильний пароль резервного копіювання", + "backupEncrypted": "Резервна копія зашифрована", + "backupNotEncrypted": "Резервна копія не зашифрована", + "backupPasswordSet": "Пароль резервного копіювання встановлено", + "backupPasswordRemoved": "Пароль резервного копіювання видалено", "battery": "Акумулятор", "bgRun": "Запуск у фоновому режимі", "bgRunTip": "Цей перемикач лише вказує на те, що програма намагатиметься працювати у фоновому режимі. Чи може вона працювати у фоновому режимі, залежить від прав доступу. Для AOSP-орієнтованих Android ROM, будь ласка, вимкніть \"Оптимізацію акумулятора\" в цьому додатку. Для MIUI / HyperOS, будь ласка, змініть політику економії енергії на \"Нескінченна\".", @@ -137,7 +144,6 @@ "pveIgnoreCertTip": "Не рекомендується включати, будьте обережні з ризиками безпеки! Якщо ви використовуєте стандартний сертифікат від PVE, вам потрібно увімкнути цю опцію.", "pveLoginFailed": "Не вдалося увійти. Неможливо пройти аутентифікацію за допомогою імені користувача/пароля з конфігурації сервера для входу Linux PAM.", "pveVersionLow": "Ця функція наразі перебуває на стадії тестування та випробувалася лише на PVE 8+. Будь ласка, використовуйте її з обережністю.", - "pwd": "Пароль", "read": "Читати", "reboot": "Перезавантажити", "rememberPwdInMem": "Запам'ятати пароль у пам'яті", diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index f334be74..e699ab9b 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -11,8 +11,15 @@ "autoConnect": "自动连接", "autoRun": "自动运行", "autoUpdateHomeWidget": "自动更新桌面小部件", - "backupTip": "导出的数据仅进行了简单加密,请妥善保管。", + "backupTip": "导出的数据可以使用密码加密,请妥善保管。", "backupVersionNotMatch": "备份版本不匹配,无法恢复", + "backupPassword": "备份密码", + "backupPasswordTip": "设置密码以加密备份文件。留空则禁用加密。", + "backupPasswordWrong": "备份密码错误", + "backupEncrypted": "备份已加密", + "backupNotEncrypted": "备份未加密", + "backupPasswordSet": "备份密码已设置", + "backupPasswordRemoved": "备份密码已移除", "battery": "电池", "bgRun": "后台运行", "bgRunTip": "此开关只代表程序会尝试在后台运行,具体能否后台运行取决于是否开启了权限。原生 Android 请关闭本 App 的“电池优化”,MIUI / HyperOS 请修改省电策略为“无限制”。", @@ -137,7 +144,6 @@ "pveIgnoreCertTip": "不推荐开启,注意安全隐患!如果你使用的 PVE 默认证书,需要开启该选项", "pveLoginFailed": "登录失败。无法使用服务器配置内的用户/密码,以 Linux PAM 方式登录。", "pveVersionLow": "当前该功能处于测试阶段,仅在 PVE 8+ 上测试过,请谨慎使用", - "pwd": "密码", "read": "读", "reboot": "重启", "rememberPwdInMem": "在内存中记住密码", diff --git a/lib/l10n/app_zh_tw.arb b/lib/l10n/app_zh_tw.arb index 348be6c7..fa1e2290 100644 --- a/lib/l10n/app_zh_tw.arb +++ b/lib/l10n/app_zh_tw.arb @@ -11,8 +11,15 @@ "autoConnect": "自動連線", "autoRun": "自動執行", "autoUpdateHomeWidget": "自動更新桌面小工具", - "backupTip": "匯出的資料僅進行了簡單加密,請妥善保管。", + "backupTip": "匯出的資料可以使用密碼加密。 \n請妥善保管。", "backupVersionNotMatch": "備份版本不相符,無法還原", + "backupPassword": "備份密碼", + "backupPasswordTip": "設定密碼來加密備份檔案。留空則停用加密。", + "backupPasswordWrong": "備份密碼錯誤", + "backupEncrypted": "備份已加密", + "backupNotEncrypted": "備份未加密", + "backupPasswordSet": "備份密碼已設定", + "backupPasswordRemoved": "備份密碼已移除", "battery": "電池", "bgRun": "背景執行", "bgRunTip": "此開關只代表程式會嘗試在背景執行,具體能否在後臺執行取決於是否開啟了權限。 原生 Android 請關閉本 App 的“電池最佳化”,MIUI / HyperOS 請修改省電策略為“無限制”。", @@ -137,7 +144,6 @@ "pveIgnoreCertTip": "不建議啟用,請注意安全風險!如果您使用的是 PVE 的預設憑證,則需要啟用此選項。", "pveLoginFailed": "登錄失敗。無法使用伺服器配置中的使用者名稱/密碼以 Linux PAM 方式登錄。", "pveVersionLow": "此功能目前處於測試階段,僅在 PVE 8+ 上進行過測試。請謹慎使用。", - "pwd": "密碼", "read": "讀取", "reboot": "重開", "rememberPwdInMem": "在記憶體中記住密碼", diff --git a/lib/view/page/backup.dart b/lib/view/page/backup.dart index ad33c308..9b2bc164 100644 --- a/lib/view/page/backup.dart +++ b/lib/view/page/backup.dart @@ -8,7 +8,8 @@ import 'package:icons_plus/icons_plus.dart'; import 'package:server_box/core/extension/context/locale.dart'; import 'package:server_box/core/sync.dart'; import 'package:server_box/data/model/app/bak/backup2.dart'; -import 'package:server_box/data/model/app/bak/utils.dart'; +import 'package:server_box/data/model/app/bak/backup_service.dart'; +import 'package:server_box/data/model/app/bak/backup_source.dart'; import 'package:server_box/data/model/server/server_private_info.dart'; import 'package:server_box/data/model/server/snippet.dart'; import 'package:server_box/data/provider/snippet.dart'; @@ -22,10 +23,7 @@ class BackupPage extends StatefulWidget { @override State createState() => _BackupPageState(); - static const route = AppRouteNoArg( - page: BackupPage.new, - path: '/backup', - ); + static const route = AppRouteNoArg(page: BackupPage.new, path: '/backup'); } final class _BackupPageState extends State with AutomaticKeepAliveClientMixin { @@ -40,33 +38,27 @@ final class _BackupPageState extends State with AutomaticKeepAliveCl @override Widget build(BuildContext context) { super.build(context); - return Scaffold( - body: _buildBody(context), - ); + return Scaffold(body: _buildBody); } - Widget _buildBody(BuildContext context) { + Widget get _buildBody { return MultiList( widthDivider: 2, children: [ [ CenterGreyTitle(libL10n.sync), - _buildTip(), - if (isMacOS || isIOS) _buildIcloud(context), - _buildWebdav(context), - _buildFile(context), - _buildClipboard(context), - ], - [ - CenterGreyTitle(libL10n.import), - _buildBulkImportServers(context), - _buildImportSnippet(context), + _buildTip, + if (isMacOS || isIOS) _buildIcloud, + _buildWebdav, + _buildFile, + _buildClipboard, ], + [CenterGreyTitle(libL10n.import), _buildBulkImportServers, _buildImportSnippet], ], ); } - Widget _buildTip() { + Widget get _buildTip { return CardX( child: ListTile( leading: const Icon(Icons.warning), @@ -76,7 +68,7 @@ final class _BackupPageState extends State with AutomaticKeepAliveCl ); } - Widget _buildFile(BuildContext context) { + Widget get _buildFile { return CardX( child: ExpandTile( leading: const Icon(Icons.file_open), @@ -84,24 +76,21 @@ final class _BackupPageState extends State with AutomaticKeepAliveCl initiallyExpanded: false, children: [ ListTile( - title: Text(libL10n.backup), - trailing: const Icon(Icons.save), - onTap: () async { - final path = await BackupV2.backup(); - await Pfs.sharePaths(paths: [path]); - }, + title: Text(libL10n.backup), + trailing: const Icon(Icons.save), + onTap: () => BackupService.backup(context, FileBackupSource()) ), ListTile( trailing: const Icon(Icons.restore), title: Text(libL10n.restore), - onTap: () async => _onTapFileRestore(context), + onTap: () => BackupService.restore(context, FileBackupSource()), ), ], ), ); } - Widget _buildIcloud(BuildContext context) { + Widget get _buildIcloud { return CardX( child: ListTile( leading: const Icon(Icons.cloud), @@ -123,7 +112,7 @@ final class _BackupPageState extends State with AutomaticKeepAliveCl ); } - Widget _buildWebdav(BuildContext context) { + Widget get _buildWebdav { return CardX( child: ExpandTile( leading: const Icon(Icons.storage), @@ -171,33 +160,25 @@ final class _BackupPageState extends State with AutomaticKeepAliveCl ), ListTile( title: Text(l10n.manual), - trailing: webdavLoading.listenVal( - (loading) { - if (loading) return SizedLoading.small; + trailing: webdavLoading.listenVal((loading) { + if (loading) return SizedLoading.small; - return Row( - mainAxisSize: MainAxisSize.min, - children: [ - TextButton( - onPressed: () async => _onTapWebdavDl(context), - child: Text(libL10n.restore), - ), - UIs.width7, - TextButton( - onPressed: () async => _onTapWebdavUp(context), - child: Text(libL10n.backup), - ), - ], - ); - }, - ), + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + TextButton(onPressed: () async => _onTapWebdavDl(context), child: Text(libL10n.restore)), + UIs.width7, + TextButton(onPressed: () async => _onTapWebdavUp(context), child: Text(libL10n.backup)), + ], + ); + }), ), ], ), ); } - Widget _buildClipboard(BuildContext context) { + Widget get _buildClipboard { return CardX( child: ExpandTile( leading: const Icon(Icons.content_paste), @@ -206,23 +187,19 @@ final class _BackupPageState extends State with AutomaticKeepAliveCl ListTile( title: Text(libL10n.backup), trailing: const Icon(Icons.save), - onTap: () async { - final path = await BackupV2.backup(); - Pfs.copy(await File(path).readAsString()); - context.showSnackBar(libL10n.success); - }, + onTap: () => BackupService.backup(context, ClipboardBackupSource()), ), ListTile( trailing: const Icon(Icons.restore), title: Text(libL10n.restore), - onTap: () async => _onTapClipboardRestore(context), + onTap: () => BackupService.restore(context, ClipboardBackupSource()), ), ], ), ); } - Widget _buildBulkImportServers(BuildContext context) { + Widget get _buildBulkImportServers { return CardX( child: ListTile( title: Text(l10n.server), @@ -233,16 +210,13 @@ final class _BackupPageState extends State with AutomaticKeepAliveCl ); } - Widget _buildImportSnippet(BuildContext context) { + Widget get _buildImportSnippet { return ListTile( title: Text(l10n.snippet), leading: const Icon(MingCute.code_line), trailing: const Icon(Icons.keyboard_arrow_right), onTap: () async { - final data = await context.showImportDialog( - title: l10n.snippet, - modelDef: Snippet.example.toJson(), - ); + final data = await context.showImportDialog(title: l10n.snippet, modelDef: Snippet.example.toJson()); if (data == null) return; final str = String.fromCharCodes(data); final (list, _) = await context.showLoadingDialog( @@ -275,11 +249,7 @@ final class _BackupPageState extends State with AutomaticKeepAliveCl final snippetNames = snippets.map((e) => e.name).join(', '); context.showRoundDialog( title: libL10n.attention, - child: SingleChildScrollView( - child: Text( - libL10n.askContinue('${libL10n.import} [$snippetNames]'), - ), - ), + child: SingleChildScrollView(child: Text(libL10n.askContinue('${libL10n.import} [$snippetNames]'))), actions: Btn.ok( onTap: () { for (final snippet in snippets) { @@ -294,33 +264,6 @@ final class _BackupPageState extends State with AutomaticKeepAliveCl ).cardx; } - Future _onTapFileRestore(BuildContext context) async { - final text = await Pfs.pickFileString(); - if (text == null) return; - - try { - final (backup, err) = await context.showLoadingDialog( - fn: () => Computer.shared.start(MergeableUtils.fromJsonString, text.trim()), - ); - if (err != null || backup == null) return; - - await context.showRoundDialog( - title: libL10n.restore, - child: Text(libL10n.askContinue( - '${libL10n.restore} ${libL10n.backup}(${backup.$2})', - )), - actions: Btn.ok( - onTap: () async { - await backup.$1.merge(force: true); - context.pop(); - }, - ).toList, - ); - } catch (e, s) { - Loggers.app.warning('Import backup failed', e, s); - context.showErrDialog(e, s, libL10n.restore); - } - } Future _onTapWebdavDl(BuildContext context) async { webdavLoading.value = true; @@ -328,16 +271,12 @@ final class _BackupPageState extends State with AutomaticKeepAliveCl final files = await Webdav.shared.list(); if (files.isEmpty) return context.showSnackBar(l10n.dirEmpty); - final fileName = await context.showPickSingleDialog( - title: libL10n.restore, - items: files, - ); + final fileName = await context.showPickSingleDialog(title: libL10n.restore, items: files); if (fileName == null) return; await Webdav.shared.download(relativePath: fileName); final dlFile = await File('${Paths.doc}/$fileName').readAsString(); - final dlBak = await Computer.shared.start(BackupV2.fromJsonString, dlFile); - await dlBak.merge(force: true); + await BackupService.restoreFromText(context, dlFile); } catch (e, s) { context.showErrDialog(e, s, libL10n.restore); Loggers.app.warning('Download webdav backup failed', e, s); @@ -351,7 +290,8 @@ final class _BackupPageState extends State with AutomaticKeepAliveCl final date = DateTime.now().ymdhms(ymdSep: '-', hmsSep: '-', sep: '-'); final bakName = '$date-${Miscs.bakFileName}'; try { - await BackupV2.backup(bakName); + final savedPassword = await Stores.setting.backupasswd.read(); + await BackupV2.backup(bakName, savedPassword); await Webdav.shared.upload(relativePath: bakName); Loggers.app.info('Upload webdav backup success'); } catch (e, s) { @@ -388,7 +328,7 @@ final class _BackupPageState extends State with AutomaticKeepAliveCl onSubmitted: (p0) => FocusScope.of(context).requestFocus(nodePwd), ), Input( - label: l10n.pwd, + label: libL10n.pwd, controller: pwd, node: nodePwd, suggestion: false, @@ -417,42 +357,9 @@ final class _BackupPageState extends State with AutomaticKeepAliveCl } } - void _onTapClipboardRestore(BuildContext context) async { - final text = await Pfs.paste(); - if (text == null || text.isEmpty) { - context.showSnackBar(libL10n.empty); - return; - } - - try { - final (backup, err) = await context.showLoadingDialog( - fn: () => Computer.shared.start(MergeableUtils.fromJsonString, text.trim()), - ); - if (err != null || backup == null) return; - - await context.showRoundDialog( - title: libL10n.restore, - child: Text(libL10n.askContinue( - '${libL10n.restore} ${libL10n.backup}(${backup.$2})', - )), - actions: Btn.ok( - onTap: () async { - await backup.$1.merge(force: true); - context.pop(); - }, - ).toList, - ); - } catch (e, s) { - Loggers.app.warning('Import backup failed', e, s); - context.showErrDialog(e, s, libL10n.restore); - } - } void _onBulkImportServers(BuildContext context) async { - final data = await context.showImportDialog( - title: l10n.server, - modelDef: Spix.example.toJson(), - ); + final data = await context.showImportDialog(title: l10n.server, modelDef: Spix.example.toJson()); if (data == null) return; final text = String.fromCharCodes(data); @@ -487,6 +394,11 @@ final class _BackupPageState extends State with AutomaticKeepAliveCl } } + + + + + @override bool get wantKeepAlive => true; } diff --git a/lib/view/page/private_key/edit.dart b/lib/view/page/private_key/edit.dart index 637980b1..7703dff8 100644 --- a/lib/view/page/private_key/edit.dart +++ b/lib/view/page/private_key/edit.dart @@ -190,7 +190,7 @@ class _PrivateKeyEditPageState extends State { type: TextInputType.text, node: _pwdNode, obscureText: true, - label: l10n.pwd, + label: libL10n.pwd, icon: Icons.password, suggestion: false, onSubmitted: (_) => _onTapSave(), diff --git a/lib/view/page/server/edit.dart b/lib/view/page/server/edit.dart index bc59c8a8..cad73425 100644 --- a/lib/view/page/server/edit.dart +++ b/lib/view/page/server/edit.dart @@ -208,9 +208,8 @@ class _ServerEditPageState extends State with AfterLayoutMixin { controller: _passwordController, obscureText: true, type: TextInputType.text, - label: l10n.pwd, + label: libL10n.pwd, icon: Icons.password, - hint: l10n.pwd, suggestion: false, onSubmitted: (_) => _onSave(), ), @@ -427,9 +426,8 @@ class _ServerEditPageState extends State with AfterLayoutMixin { controller: _wolPwdCtrl, type: TextInputType.text, obscureText: true, - label: l10n.pwd, + label: libL10n.pwd, icon: Icons.password, - hint: l10n.pwd, suggestion: false, ), ], diff --git a/pubspec.lock b/pubspec.lock index 9977a45f..e9f0015a 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -497,8 +497,8 @@ packages: dependency: "direct main" description: path: "." - ref: "v1.0.324" - resolved-ref: e64d5c46844605bbd85322d7c6f250b73977cdde + ref: "v1.0.327" + resolved-ref: "5075a679b814b10742f967066858ba4df92ea4ae" url: "https://github.com/lppcg/fl_lib" source: git version: "0.0.1" diff --git a/pubspec.yaml b/pubspec.yaml index 52fd46d1..ce0808fb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -63,7 +63,7 @@ dependencies: fl_lib: git: url: https://github.com/lppcg/fl_lib - ref: v1.0.324 + ref: v1.0.327 dependency_overrides: # webdav_client_plus: