diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 58e3c93a..315c5092 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -690,7 +690,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 1018; + CURRENT_PROJECT_VERSION = 1021; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_BITCODE = NO; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; @@ -700,7 +700,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.1018; + MARKETING_VERSION = 1.0.1021; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -826,7 +826,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 1018; + CURRENT_PROJECT_VERSION = 1021; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_BITCODE = NO; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; @@ -836,7 +836,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.1018; + MARKETING_VERSION = 1.0.1021; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -854,7 +854,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 1018; + CURRENT_PROJECT_VERSION = 1021; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_BITCODE = NO; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; @@ -864,7 +864,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.1018; + MARKETING_VERSION = 1.0.1021; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -885,7 +885,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1018; + CURRENT_PROJECT_VERSION = 1021; DEVELOPMENT_TEAM = BA88US33G6; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; @@ -898,7 +898,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.0.1018; + MARKETING_VERSION = 1.0.1021; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget; @@ -924,7 +924,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1018; + CURRENT_PROJECT_VERSION = 1021; DEVELOPMENT_TEAM = BA88US33G6; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; @@ -937,7 +937,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.0.1018; + MARKETING_VERSION = 1.0.1021; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -960,7 +960,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1018; + CURRENT_PROJECT_VERSION = 1021; DEVELOPMENT_TEAM = BA88US33G6; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; @@ -973,7 +973,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.0.1018; + MARKETING_VERSION = 1.0.1021; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -996,7 +996,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1018; + CURRENT_PROJECT_VERSION = 1021; DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_PREVIEWS = YES; @@ -1008,7 +1008,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.1018; + MARKETING_VERSION = 1.0.1021; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd; @@ -1037,7 +1037,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1018; + CURRENT_PROJECT_VERSION = 1021; DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_PREVIEWS = YES; @@ -1049,7 +1049,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.1018; + MARKETING_VERSION = 1.0.1021; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd; PRODUCT_NAME = ServerBox; @@ -1075,7 +1075,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1018; + CURRENT_PROJECT_VERSION = 1021; DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_PREVIEWS = YES; @@ -1087,7 +1087,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.1018; + MARKETING_VERSION = 1.0.1021; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd; PRODUCT_NAME = ServerBox; diff --git a/lib/data/model/app/shell_func.dart b/lib/data/model/app/shell_func.dart index 88360693..9a37f019 100644 --- a/lib/data/model/app/shell_func.dart +++ b/lib/data/model/app/shell_func.dart @@ -19,43 +19,24 @@ enum ShellFunc { /// srvboxm -> ServerBox Mobile static const scriptFile = 'srvboxm_v${BuildData.script}.sh'; - static const scriptPathShm = '/dev/shm/$scriptFile'; - static const scriptPathHome = '~/.config/server_box/$scriptFile'; + static const scriptDir = '~/.config/server_box'; + static const scriptPath = '$scriptDir/$scriptFile'; - static final _scriptPathMap = {}; - static String getScriptPath(String id) { - return _scriptPathMap.putIfAbsent(id, () => scriptPathShm); - } - - static String setScriptPath(String id, String path) { - return _scriptPathMap[id] = path; - } - static String installShellCmd(String id) { - final path = getScriptPath(id); - return """ -cat > $path -chmod 744 $path + static const String installShellCmd = """ +cat > $scriptPath +chmod 744 $scriptPath """; - } - String get flag { - switch (this) { - case ShellFunc.status: - return 's'; - // case ShellFunc.docker: - // return 'd'; - case ShellFunc.process: - return 'p'; - case ShellFunc.shutdown: - return 'sd'; - case ShellFunc.reboot: - return 'r'; - case ShellFunc.suspend: - return 'sp'; - } - } + String get flag => switch (this) { + ShellFunc.process => 'p', + ShellFunc.shutdown => 'sd', + ShellFunc.reboot => 'r', + ShellFunc.suspend => 'sp', + ShellFunc.status => 's', + // ShellFunc.docker=> 'd', + }; - String exec(String id) => 'sh ${getScriptPath(id)} -$flag'; + String get exec => 'sh $scriptPath -$flag'; String get name { switch (this) { diff --git a/lib/data/provider/server.dart b/lib/data/provider/server.dart index 7b6798db..768c5807 100644 --- a/lib/data/provider/server.dart +++ b/lib/data/provider/server.dart @@ -315,23 +315,14 @@ class ServerProvider extends ChangeNotifier { final scriptRaw = ShellFunc.allScript(spi.custom?.cmds).uint8List; - Future fn(String scriptPath) async { + try { await s.client?.runForOutput( - scriptPath, + ShellFunc.installShellCmd, action: (session) async { session.stdin.add(scriptRaw); session.stdin.close(); }, ); - ShellFunc.setScriptPath(spi.id, scriptPath); - } - - try { - try { - await fn(ShellFunc.scriptPathShm); - } catch (_) { - await fn(ShellFunc.scriptPathHome); - } } on SSHAuthAbortError catch (e) { TryLimiter.inc(sid); s.status.err = SSHErr(type: SSHErrType.auth, message: e.toString()); @@ -343,10 +334,11 @@ class ServerProvider extends ChangeNotifier { _setServerState(s, ServerConn.failed); return; } catch (e) { + final err = e.toString(); TryLimiter.inc(sid); - s.status.err = SSHErr(type: SSHErrType.auth, message: e.toString()); + s.status.err = SSHErr(type: SSHErrType.writeScript, message: err); _setServerState(s, ServerConn.failed); - Loggers.app.warning('Write script to ${spi.name} by shell', e); + Loggers.app.warning('Write script to ${spi.name} by shell', err); } } @@ -363,7 +355,7 @@ class ServerProvider extends ChangeNotifier { String? raw; try { - raw = await s.client?.run(ShellFunc.status.exec(spi.id)).string; + raw = await s.client?.run(ShellFunc.status.exec).string; segments = raw?.split(ShellFunc.seperator).map((e) => e.trim()).toList(); if (raw == null || raw.isEmpty || segments == null || segments.isEmpty) { if (Stores.setting.keepStatusWhenErr.fetch()) { diff --git a/lib/data/res/build_data.dart b/lib/data/res/build_data.dart index acd422c9..c12759e7 100644 --- a/lib/data/res/build_data.dart +++ b/lib/data/res/build_data.dart @@ -2,6 +2,6 @@ class BuildData { static const String name = "ServerBox"; - static const int build = 1018; - static const int script = 51; + static const int build = 1021; + static const int script = 53; } diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 670a0430..69aaa7b6 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -340,5 +340,6 @@ "willTakEeffectImmediately": "Wird sofort angewendet", "wolTip": "Nach der Konfiguration von WOL (Wake-on-LAN) wird jedes Mal, wenn der Server verbunden wird, eine WOL-Anfrage gesendet.", "write": "Schreiben", - "writeScriptFailTip": "Das Schreiben des Skripts ist fehlgeschlagen, möglicherweise aufgrund fehlender Berechtigungen oder das Verzeichnis existiert nicht." + "writeScriptFailTip": "Das Schreiben des Skripts ist fehlgeschlagen, möglicherweise aufgrund fehlender Berechtigungen oder das Verzeichnis existiert nicht.", + "writeScriptTip": "Nach der Verbindung mit dem Server wird ein Skript in ~/.config/server_box geschrieben, um den Systemstatus zu überwachen. Sie können den Skriptinhalt überprüfen." } \ No newline at end of file diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 204f6481..324f0d54 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -340,5 +340,6 @@ "willTakEeffectImmediately": "Will take effect immediately", "wolTip": "After configuring WOL (Wake-on-LAN), a WOL request is sent each time the server is connected.", "write": "Write", - "writeScriptFailTip": "Writing to the script failed, possibly due to lack of permissions or the directory does not exist." + "writeScriptFailTip": "Writing to the script failed, possibly due to lack of permissions or the directory does not exist.", + "writeScriptTip": "After connecting to the server, a script will be written to ~/.config/server_box to monitor the system status. You can review the script content." } \ No newline at end of file diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 6b97b0bb..25806b7a 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -340,5 +340,6 @@ "willTakEeffectImmediately": "Los cambios tendrán efecto inmediatamente", "wolTip": "Después de configurar WOL (Wake-on-LAN), se envía una solicitud de WOL cada vez que se conecta el servidor.", "write": "Escribir", - "writeScriptFailTip": "La escritura en el script falló, posiblemente por falta de permisos o porque el directorio no existe." + "writeScriptFailTip": "La escritura en el script falló, posiblemente por falta de permisos o porque el directorio no existe.", + "writeScriptTip": "Después de conectarse al servidor, se escribirá un script en ~/.config/server_box para monitorear el estado del sistema. Puedes revisar el contenido del script." } \ No newline at end of file diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index ebe5dae6..4c57f6ab 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -340,5 +340,6 @@ "willTakEeffectImmediately": "Prendra effet immédiatement", "wolTip": "Après avoir configuré le WOL (Wake-on-LAN), une requête WOL est envoyée chaque fois que le serveur est connecté.", "write": "Écrire", - "writeScriptFailTip": "Échec de l'écriture dans le script, probablement en raison d'un manque de permissions ou que le répertoire n'existe pas." + "writeScriptFailTip": "Échec de l'écriture dans le script, probablement en raison d'un manque de permissions ou que le répertoire n'existe pas.", + "writeScriptTip": "Après la connexion au serveur, un script sera écrit dans ~/.config/server_box pour surveiller l’état du système. Vous pouvez examiner le contenu du script." } \ No newline at end of file diff --git a/lib/l10n/app_id.arb b/lib/l10n/app_id.arb index bd6dd99a..b022ef35 100644 --- a/lib/l10n/app_id.arb +++ b/lib/l10n/app_id.arb @@ -340,5 +340,6 @@ "willTakEeffectImmediately": "Akan segera berlaku", "wolTip": "Setelah mengonfigurasi WOL (Wake-on-LAN), permintaan WOL dikirim setiap kali server terhubung.", "write": "Tulis", - "writeScriptFailTip": "Penulisan ke skrip gagal, mungkin karena tidak ada izin atau direktori tidak ada." + "writeScriptFailTip": "Penulisan ke skrip gagal, mungkin karena tidak ada izin atau direktori tidak ada.", + "writeScriptTip": "Setelah terhubung ke server, sebuah skrip akan ditulis ke ~/.config/server_box untuk memantau status sistem. Anda dapat meninjau konten skrip tersebut." } \ No newline at end of file diff --git a/lib/l10n/app_ja.arb b/lib/l10n/app_ja.arb index a7db9c99..6f513831 100644 --- a/lib/l10n/app_ja.arb +++ b/lib/l10n/app_ja.arb @@ -340,5 +340,6 @@ "willTakEeffectImmediately": "変更は即座に有効になります", "wolTip": "WOL(Wake-on-LAN)を設定した後、サーバーに接続するたびにWOLリクエストが送信されます。", "write": "書き込み", - "writeScriptFailTip": "スクリプトの書き込みに失敗しました。権限がないかディレクトリが存在しない可能性があります。" + "writeScriptFailTip": "スクリプトの書き込みに失敗しました。権限がないかディレクトリが存在しない可能性があります。", + "writeScriptTip": "サーバーに接続すると、システムの状態を監視するためのスクリプトが ~/.config/server_box に書き込まれます。スクリプトの内容を確認できます。" } \ No newline at end of file diff --git a/lib/l10n/app_nl.arb b/lib/l10n/app_nl.arb index ca23701e..abdfd224 100644 --- a/lib/l10n/app_nl.arb +++ b/lib/l10n/app_nl.arb @@ -340,5 +340,6 @@ "willTakEeffectImmediately": "Zal onmiddellijk van kracht worden", "wolTip": "Na het configureren van WOL (Wake-on-LAN), wordt elke keer dat de server wordt verbonden een WOL-verzoek verzonden.", "write": "Schrijven", - "writeScriptFailTip": "Het schrijven naar het script is mislukt, mogelijk door gebrek aan rechten of omdat de map niet bestaat." + "writeScriptFailTip": "Het schrijven naar het script is mislukt, mogelijk door gebrek aan rechten of omdat de map niet bestaat.", + "writeScriptTip": "Na het verbinden met de server wordt een script geschreven naar ~/.config/server_box om de systeemstatus te monitoren. U kunt de inhoud van het script controleren." } \ No newline at end of file diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index cf8ba845..71c2c03c 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -340,5 +340,6 @@ "willTakEeffectImmediately": "As alterações serão aplicadas imediatamente", "wolTip": "Após configurar o WOL (Wake-on-LAN), um pedido de WOL é enviado cada vez que o servidor é conectado.", "write": "Escrita", - "writeScriptFailTip": "Falha ao escrever no script, possivelmente devido à falta de permissões ou o diretório não existe." + "writeScriptFailTip": "Falha ao escrever no script, possivelmente devido à falta de permissões ou o diretório não existe.", + "writeScriptTip": "Após conectar ao servidor, um script será escrito em ~/.config/server_box para monitorar o status do sistema. Você pode revisar o conteúdo do script." } \ No newline at end of file diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb index c69ddb4a..8ca0339b 100644 --- a/lib/l10n/app_ru.arb +++ b/lib/l10n/app_ru.arb @@ -340,5 +340,6 @@ "willTakEeffectImmediately": "Изменения вступят в силу немедленно", "wolTip": "После настройки WOL (Wake-on-LAN) при каждом подключении к серверу отправляется запрос WOL.", "write": "запись", - "writeScriptFailTip": "Запись в скрипт не удалась, возможно, из-за отсутствия прав или директории не существует." + "writeScriptFailTip": "Запись в скрипт не удалась, возможно, из-за отсутствия прав или директории не существует.", + "writeScriptTip": "После подключения к серверу скрипт будет записан в ~/.config/server_box для мониторинга состояния системы. Вы можете проверить содержимое скрипта." } \ No newline at end of file diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index 875d1986..edf4ac0d 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -340,5 +340,6 @@ "willTakEeffectImmediately": "更改将会立即生效", "wolTip": "在配置 WOL 后,每次连接服务器都会先发送一次 WOL 请求", "write": "写", - "writeScriptFailTip": "写入脚本失败,可能是没有权限/目录不存在等" + "writeScriptFailTip": "写入脚本失败,可能是没有权限/目录不存在等", + "writeScriptTip": "在连接服务器后,会向 ~/.config/server_box 写入脚本来监测系统状态,你可以审查脚本内容。" } \ No newline at end of file diff --git a/lib/l10n/app_zh_tw.arb b/lib/l10n/app_zh_tw.arb index 5b0a05d1..8ca6c225 100644 --- a/lib/l10n/app_zh_tw.arb +++ b/lib/l10n/app_zh_tw.arb @@ -340,5 +340,6 @@ "willTakEeffectImmediately": "更改將會立即生效", "wolTip": "在配置 WOL(網絡喚醒)後,每次連接伺服器都會先發送一次 WOL 請求。", "write": "写", - "writeScriptFailTip": "寫入腳本失敗,可能是沒有權限/目錄不存在等。" + "writeScriptFailTip": "寫入腳本失敗,可能是沒有權限/目錄不存在等。", + "writeScriptTip": "連接到伺服器後,將會在 ~/.config/server_box 中寫入一個腳本來監測系統狀態。你可以審查腳本內容。" } \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index 1985fd0a..582b62c1 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -9,7 +9,6 @@ import 'package:flutter_displaymode/flutter_displaymode.dart'; import 'package:hive_flutter/hive_flutter.dart'; import 'package:logging/logging.dart'; import 'package:provider/provider.dart'; -import 'package:shared_preferences/shared_preferences.dart'; import 'package:server_box/app.dart'; import 'package:server_box/core/utils/sync/icloud.dart'; import 'package:server_box/core/utils/sync/webdav.dart'; @@ -95,11 +94,7 @@ Future _initData() async { Hive.registerAdapter(ServerCustomAdapter()); // 7 Hive.registerAdapter(WakeOnLanCfgAdapter()); // 8 - try { - /// Apps' data on other platforms are stored in a container that prevents - /// access by other apps. Therefore, there is no need to encrypt the data. - if (isLinux || isWindows) await SecureStore.init(); - } catch (_) {} + await SharedPref.init(); // Call this before accessing any store await Stores.setting.init(); await Stores.server.init(); @@ -127,8 +122,6 @@ void _setupDebug() { void _doPlatformRelated() async { if (isAndroid) { - // SharedPreferences is only used on Android for saving home widgets settings. - SharedPreferences.setPrefix(''); // try switch to highest refresh rate FlutterDisplayMode.setHighRefreshRate(); } diff --git a/lib/view/page/backup.dart b/lib/view/page/backup.dart index 667db7a3..f24f83d0 100644 --- a/lib/view/page/backup.dart +++ b/lib/view/page/backup.dart @@ -305,6 +305,8 @@ class BackupPage extends StatelessWidget { final url = TextEditingController(text: Stores.setting.webdavUrl.fetch()); final user = TextEditingController(text: Stores.setting.webdavUser.fetch()); final pwd = TextEditingController(text: Stores.setting.webdavPwd.fetch()); + final nodeUser = FocusNode(); + final nodePwd = FocusNode(); final result = await context.showRoundDialog( title: 'WebDAV', child: Column( @@ -314,14 +316,19 @@ class BackupPage extends StatelessWidget { label: 'URL', hint: 'https://example.com/webdav/', controller: url, + onSubmitted: (p0) => FocusScope.of(context).requestFocus(nodeUser), ), Input( label: l10n.user, controller: user, + node: nodeUser, + onSubmitted: (p0) => FocusScope.of(context).requestFocus(nodePwd), ), Input( label: l10n.pwd, controller: pwd, + node: nodePwd, + onSubmitted: (_) => context.pop(true), ), ], ), diff --git a/lib/view/page/private_key/edit.dart b/lib/view/page/private_key/edit.dart index 8ef61ea0..ed05449a 100644 --- a/lib/view/page/private_key/edit.dart +++ b/lib/view/page/private_key/edit.dart @@ -118,32 +118,7 @@ class _PrivateKeyEditPageState extends State { Widget _buildFAB() { return FloatingActionButton( tooltip: l10n.save, - onPressed: () async { - final name = _nameController.text; - final key = _standardizeLineSeparators(_keyController.text.trim()); - final pwd = _pwdController.text; - if (name.isEmpty || key.isEmpty) { - context.showSnackBar(l10n.fieldMustNotEmpty); - return; - } - FocusScope.of(context).unfocus(); - _loading.value = UIs.centerSizedLoading; - try { - final decrypted = await Computer.shared.start(decyptPem, [key, pwd]); - final pki = PrivateKeyInfo(id: name, key: decrypted); - if (widget.pki != null) { - Pros.key.update(widget.pki!, pki); - } else { - Pros.key.add(pki); - } - } catch (e) { - context.showSnackBar(e.toString()); - rethrow; - } finally { - _loading.value = null; - } - context.pop(); - }, + onPressed: _onTapSave, child: const Icon(Icons.save), ); } @@ -206,6 +181,7 @@ class _PrivateKeyEditPageState extends State { obscureText: true, label: l10n.pwd, icon: Icons.password, + onSubmitted: (_) => _onTapSave(), ), SizedBox(height: MediaQuery.of(context).size.height * 0.1), ValBuilder( @@ -215,4 +191,31 @@ class _PrivateKeyEditPageState extends State { ], ); } + + void _onTapSave() async { + final name = _nameController.text; + final key = _standardizeLineSeparators(_keyController.text.trim()); + final pwd = _pwdController.text; + if (name.isEmpty || key.isEmpty) { + context.showSnackBar(l10n.fieldMustNotEmpty); + return; + } + FocusScope.of(context).unfocus(); + _loading.value = UIs.centerSizedLoading; + try { + final decrypted = await Computer.shared.start(decyptPem, [key, pwd]); + final pki = PrivateKeyInfo(id: name, key: decrypted); + if (widget.pki != null) { + Pros.key.update(widget.pki!, pki); + } else { + Pros.key.add(pki); + } + } catch (e) { + context.showSnackBar(e.toString()); + rethrow; + } finally { + _loading.value = null; + } + context.pop(); + } } diff --git a/lib/view/page/process.dart b/lib/view/page/process.dart index e2907a95..667faad9 100644 --- a/lib/view/page/process.dart +++ b/lib/view/page/process.dart @@ -52,7 +52,7 @@ class _ProcessPageState extends State { Future _refresh() async { if (mounted) { final result = - await _client?.run(ShellFunc.process.exec(widget.spi.id)).string; + await _client?.run(ShellFunc.process.exec).string; if (result == null || result.isEmpty) { context.showSnackBar(l10n.noResult); return; diff --git a/lib/view/page/server/edit.dart b/lib/view/page/server/edit.dart index 3e9e4c24..00bcad9b 100644 --- a/lib/view/page/server/edit.dart +++ b/lib/view/page/server/edit.dart @@ -174,6 +174,7 @@ class _ServerEditPageState extends State { Widget _buildForm() { final children = [ + _buildWriteScriptTip(), Input( autoFocus: true, controller: _nameController, @@ -638,4 +639,19 @@ class _ServerEditPageState extends State { context.pop(); } + + Widget _buildWriteScriptTip() { + return ListTile( + leading: const Icon(Icons.tips_and_updates).paddingOnly(left: 13), + title: Text(l10n.attention), + onTap: () { + context.showRoundDialog( + title: l10n.attention, + child: SimpleMarkdown(data: l10n.writeScriptTip), + actions: Btns.oks(onTap: () => context.pop(true)), + ); + }, + trailing: const Icon(Icons.keyboard_arrow_right), + ).cardx; + } } diff --git a/lib/view/page/server/tab.dart b/lib/view/page/server/tab.dart index b1c04821..fab8d657 100644 --- a/lib/view/page/server/tab.dart +++ b/lib/view/page/server/tab.dart @@ -356,7 +356,7 @@ class _ServerPageState extends State Stores.setting.showSuspendTip.put(false); } srv.client?.execWithPwd( - ShellFunc.suspend.exec(srv.id), + ShellFunc.suspend.exec, context: context, id: srv.id, ); @@ -370,7 +370,7 @@ class _ServerPageState extends State IconTextBtn( onPressed: () => _askFor( func: () => srv.client?.execWithPwd( - ShellFunc.shutdown.exec(srv.id), + ShellFunc.shutdown.exec, context: context, id: srv.id, ), @@ -383,7 +383,7 @@ class _ServerPageState extends State IconTextBtn( onPressed: () => _askFor( func: () => srv.client?.execWithPwd( - ShellFunc.reboot.exec(srv.id), + ShellFunc.reboot.exec, context: context, id: srv.id, ), diff --git a/lib/view/page/storage/sftp.dart b/lib/view/page/storage/sftp.dart index 4f890a24..5406e6c4 100644 --- a/lib/view/page/storage/sftp.dart +++ b/lib/view/page/storage/sftp.dart @@ -581,6 +581,35 @@ class _SftpPageState extends State with AfterLayoutMixin { void _mkdir() { context.pop(); final textController = TextEditingController(); + + void onSubmitted() async { + if (textController.text.isEmpty) { + context.showRoundDialog( + child: Text(l10n.fieldMustNotEmpty), + actions: [ + TextButton( + onPressed: () => context.pop(), + child: Text(l10n.ok), + ), + ], + ); + return; + } + context.pop(); + try { + await context.showLoadingDialog( + fn: () async { + final dir = '${_status.path!.path}/${textController.text}'; + await _status.client!.mkdir(dir); + }, + onErr: (e, s) {}, + ); + _listDir(); + } catch (e, s) { + context.showErrDialog(e: e, s: s, operation: l10n.createFolder); + } + } + context.showRoundDialog( title: l10n.createFolder, child: Input( @@ -588,6 +617,7 @@ class _SftpPageState extends State with AfterLayoutMixin { icon: Icons.folder, controller: textController, label: l10n.name, + onSubmitted: (_) => onSubmitted(), ), actions: [ TextButton( @@ -595,33 +625,7 @@ class _SftpPageState extends State with AfterLayoutMixin { child: Text(l10n.cancel), ), TextButton( - onPressed: () async { - if (textController.text.isEmpty) { - context.showRoundDialog( - child: Text(l10n.fieldMustNotEmpty), - actions: [ - TextButton( - onPressed: () => context.pop(), - child: Text(l10n.ok), - ), - ], - ); - return; - } - context.pop(); - try { - await context.showLoadingDialog( - fn: () async { - final dir = '${_status.path!.path}/${textController.text}'; - await _status.client!.mkdir(dir); - }, - onErr: (e, s) {}, - ); - _listDir(); - } catch (e, s) { - context.showErrDialog(e: e, s: s, operation: l10n.createFolder); - } - }, + onPressed: onSubmitted, child: Text(l10n.ok, style: UIs.textRed), ), ], @@ -631,6 +635,36 @@ class _SftpPageState extends State with AfterLayoutMixin { void _newFile() { context.pop(); final textController = TextEditingController(); + + void onSubmitted() async { + if (textController.text.isEmpty) { + context.showRoundDialog( + title: l10n.attention, + child: Text(l10n.fieldMustNotEmpty), + actions: [ + TextButton( + onPressed: () => context.pop(), + child: Text(l10n.ok), + ), + ], + ); + return; + } + context.pop(); + try { + await context.showLoadingDialog( + fn: () async { + final path = '${_status.path!.path}/${textController.text}'; + await _client!.run('touch "$path"'); + }, + onErr: (e, s) {}, + ); + _listDir(); + } catch (e, s) { + context.showErrDialog(e: e, s: s, operation: l10n.createFile); + } + } + context.showRoundDialog( title: l10n.createFile, child: Input( @@ -638,37 +672,11 @@ class _SftpPageState extends State with AfterLayoutMixin { icon: Icons.insert_drive_file, controller: textController, label: l10n.name, + onSubmitted: (_) => onSubmitted(), ), actions: [ TextButton( - onPressed: () async { - if (textController.text.isEmpty) { - context.showRoundDialog( - title: l10n.attention, - child: Text(l10n.fieldMustNotEmpty), - actions: [ - TextButton( - onPressed: () => context.pop(), - child: Text(l10n.ok), - ), - ], - ); - return; - } - context.pop(); - try { - await context.showLoadingDialog( - fn: () async { - final path = '${_status.path!.path}/${textController.text}'; - await _client!.run('touch "$path"'); - }, - onErr: (e, s) {}, - ); - _listDir(); - } catch (e, s) { - context.showErrDialog(e: e, s: s, operation: l10n.createFile); - } - }, + onPressed: onSubmitted, child: Text(l10n.ok, style: UIs.textRed), ), ], @@ -678,6 +686,36 @@ class _SftpPageState extends State with AfterLayoutMixin { void _rename(SftpName file) { context.pop(); final textController = TextEditingController(text: file.filename); + + void onSubmitted() async { + if (textController.text.isEmpty) { + context.showRoundDialog( + title: l10n.attention, + child: Text(l10n.fieldMustNotEmpty), + actions: [ + TextButton( + onPressed: () => context.pop(), + child: Text(l10n.ok), + ), + ], + ); + return; + } + context.pop(); + try { + await context.showLoadingDialog( + fn: () async { + final newName = textController.text; + await _status.client?.rename(file.filename, newName); + }, + onErr: (e, s) {}, + ); + _listDir(); + } catch (e, s) { + context.showErrDialog(e: e, s: s, operation: l10n.rename); + } + } + context.showRoundDialog( title: l10n.rename, child: Input( @@ -685,38 +723,12 @@ class _SftpPageState extends State with AfterLayoutMixin { icon: Icons.abc, controller: textController, label: l10n.name, + onSubmitted: (_) => onSubmitted(), ), actions: [ TextButton(onPressed: () => context.pop(), child: Text(l10n.cancel)), TextButton( - onPressed: () async { - if (textController.text.isEmpty) { - context.showRoundDialog( - title: l10n.attention, - child: Text(l10n.fieldMustNotEmpty), - actions: [ - TextButton( - onPressed: () => context.pop(), - child: Text(l10n.ok), - ), - ], - ); - return; - } - context.pop(); - try { - await context.showLoadingDialog( - fn: () async { - final newName = textController.text; - await _status.client?.rename(file.filename, newName); - }, - onErr: (e, s) {}, - ); - _listDir(); - } catch (e, s) { - context.showErrDialog(e: e, s: s, operation: l10n.rename); - } - }, + onPressed: onSubmitted, child: Text(l10n.rename, style: UIs.textRed), ), ], diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj index 12a9926b..ba182405 100644 --- a/macos/Runner.xcodeproj/project.pbxproj +++ b/macos/Runner.xcodeproj/project.pbxproj @@ -471,7 +471,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1018; + CURRENT_PROJECT_VERSION = 1021; DEVELOPMENT_TEAM = BA88US33G6; INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = "Server Box"; @@ -481,7 +481,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 10.15; - MARKETING_VERSION = 1.0.1018; + MARKETING_VERSION = 1.0.1021; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "Server Box"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -608,7 +608,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1018; + CURRENT_PROJECT_VERSION = 1021; DEVELOPMENT_TEAM = BA88US33G6; INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = "Server Box"; @@ -618,7 +618,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 10.15; - MARKETING_VERSION = 1.0.1018; + MARKETING_VERSION = 1.0.1021; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "Server Box"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -638,7 +638,7 @@ "CODE_SIGN_IDENTITY[sdk=macosx*]" = "3rd Party Mac Developer Application"; CODE_SIGN_STYLE = Manual; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1018; + CURRENT_PROJECT_VERSION = 1021; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=macosx*]" = BA88US33G6; INFOPLIST_FILE = Runner/Info.plist; @@ -649,7 +649,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 10.15; - MARKETING_VERSION = 1.0.1018; + MARKETING_VERSION = 1.0.1021; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "Server Box"; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/pubspec.lock b/pubspec.lock index 8b35ae6b..d4459f0b 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -385,8 +385,8 @@ packages: dependency: "direct main" description: path: "." - ref: "v1.0.74" - resolved-ref: "42000d49fd62ee202a4b37d0a97c29f77c83d0d8" + ref: "v1.0.77" + resolved-ref: "57c4c0187673ea9c38b39889ac467be4a8bbddba" url: "https://github.com/lppcg/fl_lib" source: git version: "0.0.1" diff --git a/pubspec.yaml b/pubspec.yaml index 4603efcd..2f1c635d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: server_box description: server status & toolbox app. publish_to: 'none' -version: 1.0.1018+1018 +version: 1.0.1021+1021 environment: sdk: ">=3.0.0" @@ -61,11 +61,11 @@ dependencies: fl_lib: git: url: https://github.com/lppcg/fl_lib - ref: v1.0.74 + ref: v1.0.77 dependency_overrides: -# dartssh2: -# path: ../dartssh2 + # dartssh2: + # path: ../dartssh2 # fl_lib: # path: ../fl_lib # xterm: