From b802c97a8d1dddf8f53dee94837ae12e024044f2 Mon Sep 17 00:00:00 2001 From: lollipopkit Date: Sun, 18 Feb 2024 16:54:13 +0800 Subject: [PATCH] new: settings of `containerTrySudo` `usePodman` --- .dart_tool/flutter_gen/gen_l10n/l10n.dart | 20 +++++- .dart_tool/flutter_gen/gen_l10n/l10n_de.dart | 9 +++ .dart_tool/flutter_gen/gen_l10n/l10n_en.dart | 11 ++- .dart_tool/flutter_gen/gen_l10n/l10n_fr.dart | 9 +++ .dart_tool/flutter_gen/gen_l10n/l10n_id.dart | 9 +++ .dart_tool/flutter_gen/gen_l10n/l10n_zh.dart | 22 +++++- ios/Runner.xcodeproj/project.pbxproj | 36 +++++----- lib/data/model/app/backup.dart | 10 +-- lib/data/provider/container.dart | 73 +++++++++----------- lib/data/res/build_data.dart | 6 +- lib/data/res/store.dart | 4 +- lib/data/store/container.dart | 33 ++++++--- lib/data/store/setting.dart | 6 ++ lib/l10n/app_de.arb | 3 + lib/l10n/app_en.arb | 5 +- lib/l10n/app_fr.arb | 3 + lib/l10n/app_id.arb | 3 + lib/l10n/app_zh.arb | 5 +- lib/l10n/app_zh_tw.arb | 5 +- lib/locator.dart | 2 +- lib/view/page/container.dart | 6 +- lib/view/page/setting/entry.dart | 35 ++++++++-- macos/Runner.xcodeproj/project.pbxproj | 12 ++-- 23 files changed, 224 insertions(+), 103 deletions(-) diff --git a/.dart_tool/flutter_gen/gen_l10n/l10n.dart b/.dart_tool/flutter_gen/gen_l10n/l10n.dart index 2ae1ab9d..c68d32f7 100644 --- a/.dart_tool/flutter_gen/gen_l10n/l10n.dart +++ b/.dart_tool/flutter_gen/gen_l10n/l10n.dart @@ -352,6 +352,12 @@ abstract class S { /// **'Container status'** String get containerStatus; + /// No description provided for @containerTrySudoTip. + /// + /// In en, this message translates to: + /// **'For example: In the app, the user is set to aaa, but Docker is installed under the root user. In this case, you need to enable this option.'** + String get containerTrySudoTip; + /// No description provided for @convert. /// /// In en, this message translates to: @@ -1357,7 +1363,7 @@ abstract class S { /// No description provided for @sftpShowFoldersFirst. /// /// In en, this message translates to: - /// **'Disply folders first'** + /// **'Display folders first'** String get sftpShowFoldersFirst; /// No description provided for @showDistLogo. @@ -1546,6 +1552,12 @@ abstract class S { /// **'Traffic'** String get traffic; + /// No description provided for @trySudo. + /// + /// In en, this message translates to: + /// **'Try using sudo'** + String get trySudo; + /// No description provided for @ttl. /// /// In en, this message translates to: @@ -1636,6 +1648,12 @@ abstract class S { /// **'No password will be used'** String get useNoPwd; + /// No description provided for @usePodmanByDefault. + /// + /// In en, this message translates to: + /// **'Defaulting to Podman'** + String get usePodmanByDefault; + /// No description provided for @used. /// /// In en, this message translates to: diff --git a/.dart_tool/flutter_gen/gen_l10n/l10n_de.dart b/.dart_tool/flutter_gen/gen_l10n/l10n_de.dart index cd983a6e..42ade39f 100644 --- a/.dart_tool/flutter_gen/gen_l10n/l10n_de.dart +++ b/.dart_tool/flutter_gen/gen_l10n/l10n_de.dart @@ -132,6 +132,9 @@ class SDe extends S { @override String get containerStatus => 'Container Status'; + @override + String get containerTrySudoTip => 'Zum Beispiel: In der App ist der Benutzer auf aaa eingestellt, aber Docker ist unter dem Root-Benutzer installiert. In diesem Fall müssen Sie diese Option aktivieren'; + @override String get convert => 'Konvertieren'; @@ -759,6 +762,9 @@ class SDe extends S { @override String get traffic => 'Durchflussmenge'; + @override + String get trySudo => 'Versuche es mit sudo'; + @override String get ttl => 'ttl'; @@ -808,6 +814,9 @@ class SDe extends S { @override String get useNoPwd => 'Es wird kein Passwort verwendet'; + @override + String get usePodmanByDefault => 'Standardmäßige Verwendung von Podman'; + @override String get used => 'Gebraucht'; diff --git a/.dart_tool/flutter_gen/gen_l10n/l10n_en.dart b/.dart_tool/flutter_gen/gen_l10n/l10n_en.dart index 4d343a5a..b231275f 100644 --- a/.dart_tool/flutter_gen/gen_l10n/l10n_en.dart +++ b/.dart_tool/flutter_gen/gen_l10n/l10n_en.dart @@ -132,6 +132,9 @@ class SEn extends S { @override String get containerStatus => 'Container status'; + @override + String get containerTrySudoTip => 'For example: In the app, the user is set to aaa, but Docker is installed under the root user. In this case, you need to enable this option.'; + @override String get convert => 'Convert'; @@ -658,7 +661,7 @@ class SEn extends S { String get sftpSSHConnected => 'SFTP Connected'; @override - String get sftpShowFoldersFirst => 'Disply folders first'; + String get sftpShowFoldersFirst => 'Display folders first'; @override String get showDistLogo => 'Show distribution logo'; @@ -759,6 +762,9 @@ class SEn extends S { @override String get traffic => 'Traffic'; + @override + String get trySudo => 'Try using sudo'; + @override String get ttl => 'ttl'; @@ -808,6 +814,9 @@ class SEn extends S { @override String get useNoPwd => 'No password will be used'; + @override + String get usePodmanByDefault => 'Defaulting to Podman'; + @override String get used => 'Used'; diff --git a/.dart_tool/flutter_gen/gen_l10n/l10n_fr.dart b/.dart_tool/flutter_gen/gen_l10n/l10n_fr.dart index 42aab0ee..2376b9ec 100644 --- a/.dart_tool/flutter_gen/gen_l10n/l10n_fr.dart +++ b/.dart_tool/flutter_gen/gen_l10n/l10n_fr.dart @@ -132,6 +132,9 @@ class SFr extends S { @override String get containerStatus => 'Statut du conteneur'; + @override + String get containerTrySudoTip => 'Par exemple : dans l\'application, l\'utilisateur est défini comme aaa, mais Docker est installé en tant qu\'utilisateur root. Dans ce cas, vous devez activer cette option.'; + @override String get convert => 'Convertir'; @@ -759,6 +762,9 @@ class SFr extends S { @override String get traffic => 'Trafic'; + @override + String get trySudo => 'Essayez d\'utiliser sudo'; + @override String get ttl => 'ttl'; @@ -808,6 +814,9 @@ class SFr extends S { @override String get useNoPwd => 'Aucun mot de passe ne sera utilisé'; + @override + String get usePodmanByDefault => 'Utiliser Podman par défaut'; + @override String get used => 'Utilisé'; diff --git a/.dart_tool/flutter_gen/gen_l10n/l10n_id.dart b/.dart_tool/flutter_gen/gen_l10n/l10n_id.dart index 6e55c4e1..b95554ff 100644 --- a/.dart_tool/flutter_gen/gen_l10n/l10n_id.dart +++ b/.dart_tool/flutter_gen/gen_l10n/l10n_id.dart @@ -132,6 +132,9 @@ class SId extends S { @override String get containerStatus => 'Status wadah'; + @override + String get containerTrySudoTip => 'Contohnya: Di dalam aplikasi, pengguna diatur sebagai aaa, tetapi Docker diinstal di bawah pengguna root. Dalam kasus ini, Anda perlu mengaktifkan opsi ini.'; + @override String get convert => 'Mengubah'; @@ -759,6 +762,9 @@ class SId extends S { @override String get traffic => 'Lalu lintas'; + @override + String get trySudo => 'Cobalah menggunakan sudo'; + @override String get ttl => 'ttl'; @@ -808,6 +814,9 @@ class SId extends S { @override String get useNoPwd => 'Tidak ada kata sandi yang akan digunakan'; + @override + String get usePodmanByDefault => 'Menggunakan Podman sebagai bawaan'; + @override String get used => 'Digunakan'; diff --git a/.dart_tool/flutter_gen/gen_l10n/l10n_zh.dart b/.dart_tool/flutter_gen/gen_l10n/l10n_zh.dart index 2016ca19..c01c0ef5 100644 --- a/.dart_tool/flutter_gen/gen_l10n/l10n_zh.dart +++ b/.dart_tool/flutter_gen/gen_l10n/l10n_zh.dart @@ -132,6 +132,9 @@ class SZh extends S { @override String get containerStatus => '容器状态'; + @override + String get containerTrySudoTip => '例如:在应用内将用户设置为aaa,但是Docker安装在root用户下,这时就需要启用此选项'; + @override String get convert => '转换'; @@ -658,7 +661,7 @@ class SZh extends S { String get sftpSSHConnected => 'SFTP 已连接...'; @override - String get sftpShowFoldersFirst => '排序时文件夹显示在前'; + String get sftpShowFoldersFirst => '文件夹显示在前'; @override String get showDistLogo => '显示发行版 Logo'; @@ -759,6 +762,9 @@ class SZh extends S { @override String get traffic => '流量'; + @override + String get trySudo => '尝试使用sudo'; + @override String get ttl => '缓存时间'; @@ -808,6 +814,9 @@ class SZh extends S { @override String get useNoPwd => '将会使用无密码'; + @override + String get usePodmanByDefault => '默认使用 Podman'; + @override String get used => '已用'; @@ -989,6 +998,9 @@ class SZhTw extends SZh { @override String get containerStatus => '容器狀態'; + @override + String get containerTrySudoTip => '例如:App内设置用户为aaa,但是Docker安装在root用户,这时就需要开启此选项'; + @override String get convert => '轉換'; @@ -1515,7 +1527,7 @@ class SZhTw extends SZh { String get sftpSSHConnected => 'SFTP 已連接...'; @override - String get sftpShowFoldersFirst => '排序時文件夾顯示在前'; + String get sftpShowFoldersFirst => '文件夾顯示在前'; @override String get showDistLogo => '顯示發行版 Logo'; @@ -1616,6 +1628,9 @@ class SZhTw extends SZh { @override String get traffic => '流量'; + @override + String get trySudo => '嘗試使用sudo'; + @override String get ttl => '緩存時間'; @@ -1665,6 +1680,9 @@ class SZhTw extends SZh { @override String get useNoPwd => '将使用無密碼'; + @override + String get usePodmanByDefault => '默認使用 Podman'; + @override String get used => '已用'; diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 8ca5900e..ed55c06f 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -586,7 +586,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 761; + CURRENT_PROJECT_VERSION = 762; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_BITCODE = NO; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; @@ -596,7 +596,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.761; + MARKETING_VERSION = 1.0.762; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -720,7 +720,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 761; + CURRENT_PROJECT_VERSION = 762; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_BITCODE = NO; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; @@ -730,7 +730,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.761; + MARKETING_VERSION = 1.0.762; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -748,7 +748,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 761; + CURRENT_PROJECT_VERSION = 762; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_BITCODE = NO; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; @@ -758,7 +758,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.761; + MARKETING_VERSION = 1.0.762; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -779,7 +779,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 761; + CURRENT_PROJECT_VERSION = 762; DEVELOPMENT_TEAM = BA88US33G6; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; @@ -792,7 +792,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.0.761; + MARKETING_VERSION = 1.0.762; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget; @@ -818,7 +818,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 761; + CURRENT_PROJECT_VERSION = 762; DEVELOPMENT_TEAM = BA88US33G6; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; @@ -831,7 +831,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.0.761; + MARKETING_VERSION = 1.0.762; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -854,7 +854,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 761; + CURRENT_PROJECT_VERSION = 762; DEVELOPMENT_TEAM = BA88US33G6; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; @@ -867,7 +867,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.0.761; + MARKETING_VERSION = 1.0.762; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -890,7 +890,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 761; + CURRENT_PROJECT_VERSION = 762; DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_PREVIEWS = YES; @@ -902,7 +902,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.761; + MARKETING_VERSION = 1.0.762; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd; @@ -931,7 +931,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 761; + CURRENT_PROJECT_VERSION = 762; DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_PREVIEWS = YES; @@ -943,7 +943,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.761; + MARKETING_VERSION = 1.0.762; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd; PRODUCT_NAME = ServerBox; @@ -969,7 +969,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 761; + CURRENT_PROJECT_VERSION = 762; DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_PREVIEWS = YES; @@ -981,7 +981,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.761; + MARKETING_VERSION = 1.0.762; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd; PRODUCT_NAME = ServerBox; diff --git a/lib/data/model/app/backup.dart b/lib/data/model/app/backup.dart index ba9cb584..a0b45972 100644 --- a/lib/data/model/app/backup.dart +++ b/lib/data/model/app/backup.dart @@ -74,7 +74,7 @@ class Backup { spis = Stores.server.fetch(), snippets = Stores.snippet.fetch(), keys = Stores.key.fetch(), - container = Stores.docker.box.toJson(), + container = Stores.container.box.toJson(), settings = Stores.setting.box.toJson(), lastModTime = Stores.lastModTime, history = Stores.history.box.toJson(); @@ -176,19 +176,19 @@ class Backup { } // Container - final nowContainer = Stores.docker.box.keys.toSet(); + final nowContainer = Stores.container.box.keys.toSet(); final bakContainer = container.keys.toSet(); final newContainer = bakContainer.difference(nowContainer); final delContainer = nowContainer.difference(bakContainer); final updateContainer = nowContainer.intersection(bakContainer); for (final s in newContainer) { - Stores.docker.box.put(s, container[s]); + Stores.container.box.put(s, container[s]); } for (final s in delContainer) { - Stores.docker.box.delete(s); + Stores.container.box.delete(s); } for (final s in updateContainer) { - Stores.docker.box.put(s, container[s]); + Stores.container.box.put(s, container[s]); } Pros.reload(); diff --git a/lib/data/provider/container.dart b/lib/data/provider/container.dart index 0ee4c30b..2ba5b02f 100644 --- a/lib/data/provider/container.dart +++ b/lib/data/provider/container.dart @@ -17,48 +17,48 @@ final _dockerNotFound = RegExp(r"command not found|Unknown command|Command '\w+' not found"); class ContainerProvider extends ChangeNotifier { - SSHClient? client; - String? userName; + final SSHClient? client; + final String userName; + final String hostId; + final BuildContext context; List? items; List? images; String? version; ContainerErr? error; - String? hostId; String? runLog; - BuildContext? context; ContainerType type; ContainerProvider({ - this.client, - this.userName, - this.hostId, - this.context, - }) : type = Stores.docker.getType(hostId) { + required this.client, + required this.userName, + required this.hostId, + required this.context, + }) : type = Stores.container.getType(hostId) { refresh(); } Future setType(ContainerType type) async { this.type = type; - Stores.docker.setType(hostId, type); + Stores.container.setType(type, hostId); error = runLog = items = images = version = null; notifyListeners(); await refresh(); } - Future _checkDockerInstalled(SSHClient client) async { - final session = await client.execute("docker"); - await session.done; - // debugPrint('docker code: ${session.exitCode}'); - return session.exitCode == 0; - } + // Future _checkDockerInstalled(SSHClient client) async { + // final session = await client.execute("docker"); + // await session.done; + // // debugPrint('docker code: ${session.exitCode}'); + // return session.exitCode == 0; + // } - String _removeSudoPrompts(String value) { - final regex = RegExp(r"\[sudo\] password for \w+:"); - if (value.startsWith(regex)) { - return value.replaceFirstMapped(regex, (match) => ""); - } - return value; - } + // String _removeSudoPrompts(String value) { + // final regex = RegExp(r"\[sudo\] password for \w+:"); + // if (value.startsWith(regex)) { + // return value.replaceFirstMapped(regex, (match) => ""); + // } + // return value; + // } Future _requiresSudo() async { final psResult = await client?.run(_wrap(ContainerCmdType.ps.exec(type))); @@ -69,31 +69,22 @@ class ContainerProvider extends ChangeNotifier { return false; } + /// Docker Logic: + /// - Check if docker is installed, if not, return error, if yes, continue + /// - Check permission, if permission denied and no DOCKER_HOST, return error Future refresh() async { var raw = ''; - var rawErr = ''; - debugPrint('exec: ${_wrap(ContainerCmdType.execAll(type))}'); - final sudo = await _requiresSudo(); + final sudo = + await _requiresSudo() && Stores.setting.containerTrySudo.fetch(); await client?.execWithPwd( _wrap(ContainerCmdType.execAll(type, sudo: sudo)), context: context, onStdout: (data, _) => raw = '$raw$data', - onStderr: (data, _) => raw = '$rawErr$data', ); - raw = _removeSudoPrompts(raw); - rawErr = _removeSudoPrompts(rawErr); - - debugPrint('result raw [$raw, $rawErr]'); - - final dockerInstalled = await _checkDockerInstalled(client!); - // debugPrint("docker installed = $dockerInstalled"); - - if (!dockerInstalled || - raw.contains(_dockerNotFound) || - rawErr.contains(_dockerNotFound)) { + if (raw.contains(_dockerNotFound)) { error = ContainerErr(type: ContainerErrType.notInstalled); notifyListeners(); return; @@ -188,7 +179,7 @@ class ContainerProvider extends ChangeNotifier { Future restart(String id) async => await run('restart $id'); - Future run(String cmd) async { + Future run(String cmd, {bool autoRefresh = true}) async { cmd = switch (type) { ContainerType.docker => 'docker $cmd', ContainerType.podman => 'podman $cmd', @@ -214,13 +205,13 @@ class ContainerProvider extends ChangeNotifier { message: errs.join('\n').trim(), ); } - await refresh(); + if (autoRefresh) await refresh(); return null; } /// wrap cmd with `docker host` String _wrap(String cmd) { - final dockerHost = Stores.docker.fetch(hostId); + final dockerHost = Stores.container.fetch(hostId); cmd = 'export LANG=en_US.UTF-8 && $cmd'; final noDockerHost = dockerHost?.isEmpty ?? true; if (!noDockerHost) { diff --git a/lib/data/res/build_data.dart b/lib/data/res/build_data.dart index e385738c..dd6ff40b 100644 --- a/lib/data/res/build_data.dart +++ b/lib/data/res/build_data.dart @@ -2,9 +2,9 @@ class BuildData { static const String name = "ServerBox"; - static const int build = 761; + static const int build = 762; static const String engine = "3.19.0"; - static const String buildAt = "2024-02-18 12:48:41"; - static const int modifications = 10; + static const String buildAt = "2024-02-18 15:57:42"; + static const int modifications = 12; static const int script = 38; } diff --git a/lib/data/res/store.dart b/lib/data/res/store.dart index f3db72c4..ef4fe067 100644 --- a/lib/data/res/store.dart +++ b/lib/data/res/store.dart @@ -10,7 +10,7 @@ import 'package:toolbox/locator.dart'; abstract final class Stores { static final setting = locator(); static final server = locator(); - static final docker = locator(); + static final container = locator(); static final history = locator(); static final key = locator(); static final snippet = locator(); @@ -18,7 +18,7 @@ abstract final class Stores { static final List all = [ setting, server, - docker, + container, history, key, snippet, diff --git a/lib/data/store/container.dart b/lib/data/store/container.dart index ea229b72..8cac168b 100644 --- a/lib/data/store/container.dart +++ b/lib/data/store/container.dart @@ -1,11 +1,13 @@ +import 'package:toolbox/core/extension/listx.dart'; import 'package:toolbox/data/model/container/type.dart'; +import 'package:toolbox/data/res/store.dart'; import '../../core/persistant_store.dart'; const _keyConfig = 'providerConfig'; -class DockerStore extends PersistentStore { - DockerStore() : super('docker'); +class ContainerStore extends PersistentStore { + ContainerStore() : super('docker'); String? fetch(String? id) { return box.get(id); @@ -16,17 +18,28 @@ class DockerStore extends PersistentStore { box.updateLastModified(); } - ContainerType getType([String? id]) { - final cfg = box.get(_keyConfig + (id ?? '')); - if (cfg == null) { - return ContainerType.docker; - } else { - return ContainerType.values.firstWhere((e) => e.toString() == cfg); + ContainerType getType([String id = '']) { + final cfg = box.get(_keyConfig + id); + if (cfg != null) { + final type = + ContainerType.values.firstWhereOrNull((e) => e.toString() == cfg); + if (type != null) return type; } + + return defaultType; } - void setType(String? id, ContainerType type) { - box.put(_keyConfig + (id ?? ''), type.toString()); + ContainerType get defaultType { + if (Stores.setting.usePodman.fetch()) return ContainerType.podman; + return ContainerType.docker; + } + + void setType(ContainerType type, [String id = '']) { + if (type == defaultType) { + box.delete(_keyConfig + id); + } else { + box.put(_keyConfig + id, type.toString()); + } box.updateLastModified(); } } diff --git a/lib/data/store/setting.dart b/lib/data/store/setting.dart index 8b80e998..7309bba1 100644 --- a/lib/data/store/setting.dart +++ b/lib/data/store/setting.dart @@ -224,6 +224,12 @@ class SettingStore extends PersistentStore { ].map((e) => e.index).toList(), ); + /// Docker is more popular than podman, set to `false` to use docker + late final usePodman = property('usePodman', false); + + /// Try to use `sudo` to run docker command + late final containerTrySudo = property('containerTrySudo', true); + // Never show these settings for users // // ------BEGIN------ diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index fc918770..71993303 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -42,6 +42,7 @@ "container": "Container", "containerName": "Container Name", "containerStatus": "Container Status", + "containerTrySudoTip": "Zum Beispiel: In der App ist der Benutzer auf aaa eingestellt, aber Docker ist unter dem Root-Benutzer installiert. In diesem Fall müssen Sie diese Option aktivieren", "convert": "Konvertieren", "copy": "Kopieren", "copyPath": "Pfad kopieren", @@ -241,6 +242,7 @@ "times": "x", "total": "Total", "traffic": "Durchflussmenge", + "trySudo": "Versuche es mit sudo", "ttl": "ttl", "unknown": "Unbekannt", "unknownError": "Unbekannter Fehler", @@ -256,6 +258,7 @@ "uptime": "Betriebszeit", "urlOrJson": "URL oder JSON", "useNoPwd": "Es wird kein Passwort verwendet", + "usePodmanByDefault": "Standardmäßige Verwendung von Podman", "used": "Gebraucht", "user": "Benutzer", "versionHaveUpdate": "Gefunden: v1.0.{build}, klicke zum Aktualisieren", diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 0d9876d5..bd461a31 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -42,6 +42,7 @@ "container": "Container", "containerName": "Container name", "containerStatus": "Container status", + "containerTrySudoTip": "For example: In the app, the user is set to aaa, but Docker is installed under the root user. In this case, you need to enable this option.", "convert": "Convert", "copy": "Copy", "copyPath": "Copy path", @@ -209,7 +210,7 @@ "sftpDlPrepare": "Preparing to connect...", "sftpRmrDirSummary": "Use `rm -r` to delete a folder in SFTP.", "sftpSSHConnected": "SFTP Connected", - "sftpShowFoldersFirst": "Disply folders first", + "sftpShowFoldersFirst": "Display folders first", "showDistLogo": "Show distribution logo", "shutdown": "Shutdown", "size": "Size", @@ -241,6 +242,7 @@ "times": "Times", "total": "Total", "traffic": "Traffic", + "trySudo": "Try using sudo", "ttl": "ttl", "unknown": "Unknown", "unknownError": "Unknown error", @@ -256,6 +258,7 @@ "uptime": "Uptime", "urlOrJson": "URL or JSON", "useNoPwd": "No password will be used", + "usePodmanByDefault": "Defaulting to Podman", "used": "Used", "user": "User", "versionHaveUpdate": "Found: v1.0.{build}, click to update", diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index a39010f2..ea5d2212 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -42,6 +42,7 @@ "container": "Conteneurs", "containerName": "Nom du conteneur", "containerStatus": "Statut du conteneur", + "containerTrySudoTip": "Par exemple : dans l'application, l'utilisateur est défini comme aaa, mais Docker est installé en tant qu'utilisateur root. Dans ce cas, vous devez activer cette option.", "convert": "Convertir", "copy": "Copier", "copyPath": "Copier le chemin", @@ -241,6 +242,7 @@ "times": "Fois", "total": "Total", "traffic": "Trafic", + "trySudo": "Essayez d'utiliser sudo", "ttl": "ttl", "unknown": "Inconnu", "unknownError": "Erreur inconnue", @@ -256,6 +258,7 @@ "uptime": "Temps de disponibilité", "urlOrJson": "URL ou JSON", "useNoPwd": "Aucun mot de passe ne sera utilisé", + "usePodmanByDefault": "Utiliser Podman par défaut", "used": "Utilisé", "user": "Utilisateur", "versionHaveUpdate": "Trouvé : v1.0.{build}, cliquez pour mettre à jour", diff --git a/lib/l10n/app_id.arb b/lib/l10n/app_id.arb index 41f0c9c4..8fcadda5 100644 --- a/lib/l10n/app_id.arb +++ b/lib/l10n/app_id.arb @@ -42,6 +42,7 @@ "container": "Wadah", "containerName": "Nama kontainer", "containerStatus": "Status wadah", + "containerTrySudoTip": "Contohnya: Di dalam aplikasi, pengguna diatur sebagai aaa, tetapi Docker diinstal di bawah pengguna root. Dalam kasus ini, Anda perlu mengaktifkan opsi ini.", "convert": "Mengubah", "copy": "Menyalin", "copyPath": "Path Copy", @@ -241,6 +242,7 @@ "times": "Waktu", "total": "Total", "traffic": "Lalu lintas", + "trySudo": "Cobalah menggunakan sudo", "ttl": "ttl", "unknown": "Tidak dikenal", "unknownError": "Kesalahan yang tidak diketahui", @@ -256,6 +258,7 @@ "uptime": "Uptime", "urlOrJson": "URL atau JSON", "useNoPwd": "Tidak ada kata sandi yang akan digunakan", + "usePodmanByDefault": "Menggunakan Podman sebagai bawaan", "used": "Digunakan", "user": "Username", "versionHaveUpdate": "Ditemukan: v1.0.{build}, klik untuk memperbarui", diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index d1d5031a..bc925bc2 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -42,6 +42,7 @@ "container": "容器", "containerName": "容器名", "containerStatus": "容器状态", + "containerTrySudoTip": "例如:在应用内将用户设置为aaa,但是Docker安装在root用户下,这时就需要启用此选项", "convert": "转换", "copy": "复制", "copyPath": "复制路径", @@ -209,7 +210,7 @@ "sftpDlPrepare": "准备连接至服务器...", "sftpRmrDirSummary": "在 SFTP 中使用 `rm -r` 来删除文件夹", "sftpSSHConnected": "SFTP 已连接...", - "sftpShowFoldersFirst": "排序时文件夹显示在前", + "sftpShowFoldersFirst": "文件夹显示在前", "showDistLogo": "显示发行版 Logo", "shutdown": "关机", "size": "大小", @@ -241,6 +242,7 @@ "times": "次", "total": "总共", "traffic": "流量", + "trySudo": "尝试使用sudo", "ttl": "缓存时间", "unknown": "未知", "unknownError": "未知错误", @@ -256,6 +258,7 @@ "uptime": "启动时长", "urlOrJson": "链接或JSON", "useNoPwd": "将会使用无密码", + "usePodmanByDefault": "默认使用 Podman", "used": "已用", "user": "用户", "versionHaveUpdate": "找到新版本:v1.0.{build}, 点击更新", diff --git a/lib/l10n/app_zh_tw.arb b/lib/l10n/app_zh_tw.arb index a0802a35..fb16e201 100644 --- a/lib/l10n/app_zh_tw.arb +++ b/lib/l10n/app_zh_tw.arb @@ -42,6 +42,7 @@ "container": "容器", "containerName": "容器名稱", "containerStatus": "容器狀態", + "containerTrySudoTip": "例如:App内设置用户为aaa,但是Docker安装在root用户,这时就需要开启此选项", "convert": "轉換", "copy": "複製", "copyPath": "複製路徑", @@ -209,7 +210,7 @@ "sftpDlPrepare": "準備連接至服務器...", "sftpRmrDirSummary": "在 SFTP 中使用 `rm -r` 來刪除文件夾", "sftpSSHConnected": "SFTP 已連接...", - "sftpShowFoldersFirst": "排序時文件夾顯示在前", + "sftpShowFoldersFirst": "文件夾顯示在前", "showDistLogo": "顯示發行版 Logo", "shutdown": "关机", "size": "大小", @@ -241,6 +242,7 @@ "times": "次", "total": "總共", "traffic": "流量", + "trySudo": "嘗試使用sudo", "ttl": "緩存時間", "unknown": "未知", "unknownError": "未知錯誤", @@ -256,6 +258,7 @@ "uptime": "啟動時長", "urlOrJson": "鏈接或JSON", "useNoPwd": "将使用無密碼", + "usePodmanByDefault": "默認使用 Podman", "used": "已用", "user": "用戶", "versionHaveUpdate": "找到新版本:v1.0.{build}, 點擊更新", diff --git a/lib/locator.dart b/lib/locator.dart index 78372373..68b93b22 100644 --- a/lib/locator.dart +++ b/lib/locator.dart @@ -48,7 +48,7 @@ Future _setupLocatorForStores() async { await snippet.init(); locator.registerSingleton(snippet); - final docker = DockerStore(); + final docker = ContainerStore(); await docker.init(); locator.registerSingleton(docker); diff --git a/lib/view/page/container.dart b/lib/view/page/container.dart index 8f8d6917..1dc085b0 100644 --- a/lib/view/page/container.dart +++ b/lib/view/page/container.dart @@ -59,7 +59,7 @@ class _ContainerPageState extends State { return Scaffold( appBar: CustomAppBar( centerTitle: true, - title: TwoLineText(up: 'Container', down: widget.spi.name), + title: TwoLineText(up: l10n.container, down: widget.spi.name), actions: [ IconButton( onPressed: () async { @@ -358,7 +358,7 @@ class _ContainerPageState extends State { Future _showEditHostDialog() async { final id = widget.spi.id; - final host = Stores.docker.fetch(id); + final host = Stores.container.fetch(id); final ctrl = TextEditingController(text: host); await context.showRoundDialog( title: Text(l10n.dockerEditHost), @@ -379,7 +379,7 @@ class _ContainerPageState extends State { void _onSaveDockerHost(String val) { context.pop(); - Stores.docker.put(widget.spi.id, val.trim()); + Stores.container.put(widget.spi.id, val.trim()); _container.refresh(); } diff --git a/lib/view/page/setting/entry.dart b/lib/view/page/setting/entry.dart index fa426c45..941b5123 100644 --- a/lib/view/page/setting/entry.dart +++ b/lib/view/page/setting/entry.dart @@ -120,12 +120,7 @@ class _SettingPageState extends State { TextButton( onPressed: () { if (!BuildMode.isDebug) return; - Stores.docker.box.deleteFromDisk(); - Stores.server.box.deleteFromDisk(); - Stores.setting.box.deleteFromDisk(); - Stores.history.box.deleteFromDisk(); - Stores.snippet.box.deleteFromDisk(); - Stores.key.box.deleteFromDisk(); + Stores.all.map((e) => e.box.deleteFromDisk()); exit(0); }, child: Text(l10n.ok, @@ -144,6 +139,8 @@ class _SettingPageState extends State { _buildApp(), _buildTitle(l10n.server), _buildServer(), + _buildTitle(l10n.container), + _buildContainer(), _buildTitle('SSH'), _buildSSH(), _buildTitle('SFTP'), @@ -180,6 +177,7 @@ class _SettingPageState extends State { _buildAppColor(), //_buildLaunchPage(), _buildCheckUpdate(), + _buildCollapseUI(), ]; /// Platform specific settings @@ -204,7 +202,6 @@ class _SettingPageState extends State { Widget _buildServer() { return Column( children: [ - _buildCollapseUI(), _buildServerFuncBtns(), _buildServerSeq(), _buildServerDetailCardSeq(), @@ -219,6 +216,15 @@ class _SettingPageState extends State { ); } + Widget _buildContainer() { + return Column( + children: [ + _buildUsePodman(), + _buildContainerTrySudo(), + ].map((e) => CardX(child: e)).toList(), + ); + } + Widget _buildSSH() { return Column( children: [ @@ -1136,4 +1142,19 @@ class _SettingPageState extends State { trailing: StoreSwitch(prop: _setting.collapseUIDefault), ); } + + Widget _buildUsePodman() { + return ListTile( + title: Text(l10n.usePodmanByDefault), + trailing: StoreSwitch(prop: _setting.usePodman), + ); + } + + Widget _buildContainerTrySudo() { + return ListTile( + title: Text(l10n.trySudo), + subtitle: Text(l10n.containerTrySudoTip, style: UIs.textGrey), + trailing: StoreSwitch(prop: _setting.containerTrySudo), + ); + } } diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj index c8a93f2b..d96eba7b 100644 --- a/macos/Runner.xcodeproj/project.pbxproj +++ b/macos/Runner.xcodeproj/project.pbxproj @@ -439,7 +439,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 761; + CURRENT_PROJECT_VERSION = 762; DEVELOPMENT_TEAM = BA88US33G6; INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = "Server Box"; @@ -449,7 +449,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 10.15; - MARKETING_VERSION = 1.0.761; + MARKETING_VERSION = 1.0.762; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "Server Box"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -574,7 +574,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 761; + CURRENT_PROJECT_VERSION = 762; DEVELOPMENT_TEAM = BA88US33G6; INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = "Server Box"; @@ -584,7 +584,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 10.15; - MARKETING_VERSION = 1.0.761; + MARKETING_VERSION = 1.0.762; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "Server Box"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -604,7 +604,7 @@ "CODE_SIGN_IDENTITY[sdk=macosx*]" = "3rd Party Mac Developer Application"; CODE_SIGN_STYLE = Manual; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 761; + CURRENT_PROJECT_VERSION = 762; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=macosx*]" = BA88US33G6; INFOPLIST_FILE = Runner/Info.plist; @@ -615,7 +615,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 10.15; - MARKETING_VERSION = 1.0.761; + MARKETING_VERSION = 1.0.762; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "Server Box"; PROVISIONING_PROFILE_SPECIFIER = "";