mirror of
https://github.com/lollipopkit/flutter_server_box.git
synced 2025-12-17 07:14:28 +01:00
new: picker & opt. rm -r
This commit is contained in:
@@ -1202,11 +1202,11 @@ abstract class S {
|
|||||||
/// **'Preparing to connect...'**
|
/// **'Preparing to connect...'**
|
||||||
String get sftpDlPrepare;
|
String get sftpDlPrepare;
|
||||||
|
|
||||||
/// No description provided for @sftpRmrfDirSummary.
|
/// No description provided for @sftpRmrDirSummary.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Use `rm -rf` to delete a folder in SFTP.'**
|
/// **'Use `rm -r` to delete a folder in SFTP.'**
|
||||||
String get sftpRmrfDirSummary;
|
String get sftpRmrDirSummary;
|
||||||
|
|
||||||
/// No description provided for @sftpSSHConnected.
|
/// No description provided for @sftpSSHConnected.
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -583,7 +583,7 @@ class SDe extends S {
|
|||||||
String get sftpDlPrepare => 'Verbindung vorbereiten...';
|
String get sftpDlPrepare => 'Verbindung vorbereiten...';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get sftpRmrfDirSummary => 'Verwenden Sie \"rm -rf\", um das Verzeichnis in SFTP zu löschen.';
|
String get sftpRmrDirSummary => 'Verwenden Sie \"rm -r\", um das Verzeichnis in SFTP zu löschen.';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get sftpSSHConnected => 'SFTP Verbunden';
|
String get sftpSSHConnected => 'SFTP Verbunden';
|
||||||
|
|||||||
@@ -583,7 +583,7 @@ class SEn extends S {
|
|||||||
String get sftpDlPrepare => 'Preparing to connect...';
|
String get sftpDlPrepare => 'Preparing to connect...';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get sftpRmrfDirSummary => 'Use `rm -rf` to delete a folder in SFTP.';
|
String get sftpRmrDirSummary => 'Use `rm -r` to delete a folder in SFTP.';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get sftpSSHConnected => 'SFTP Connected';
|
String get sftpSSHConnected => 'SFTP Connected';
|
||||||
|
|||||||
@@ -583,7 +583,7 @@ class SId extends S {
|
|||||||
String get sftpDlPrepare => 'Bersiap untuk terhubung ...';
|
String get sftpDlPrepare => 'Bersiap untuk terhubung ...';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get sftpRmrfDirSummary => 'Gunakan `rm -rf` untuk menghapus dir di SFTP';
|
String get sftpRmrDirSummary => 'Gunakan `rm -r` untuk menghapus dir di SFTP';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get sftpSSHConnected => 'Sftp terhubung';
|
String get sftpSSHConnected => 'Sftp terhubung';
|
||||||
|
|||||||
@@ -583,7 +583,7 @@ class SZh extends S {
|
|||||||
String get sftpDlPrepare => '准备连接至服务器...';
|
String get sftpDlPrepare => '准备连接至服务器...';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get sftpRmrfDirSummary => '在 SFTP 中使用 `rm -rf` 来删除文件夹';
|
String get sftpRmrDirSummary => '在 SFTP 中使用 `rm -r` 来删除文件夹';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get sftpSSHConnected => 'SFTP 已连接...';
|
String get sftpSSHConnected => 'SFTP 已连接...';
|
||||||
@@ -1318,7 +1318,7 @@ class SZhTw extends SZh {
|
|||||||
String get sftpDlPrepare => '準備連接至服務器...';
|
String get sftpDlPrepare => '準備連接至服務器...';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get sftpRmrfDirSummary => '在 SFTP 中使用 `rm -rf` 來刪除文件夾';
|
String get sftpRmrDirSummary => '在 SFTP 中使用 `rm -r` 來刪除文件夾';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get sftpSSHConnected => 'SFTP 已連接...';
|
String get sftpSSHConnected => 'SFTP 已連接...';
|
||||||
|
|||||||
@@ -586,7 +586,7 @@
|
|||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||||
CURRENT_PROJECT_VERSION = 577;
|
CURRENT_PROJECT_VERSION = 578;
|
||||||
DEVELOPMENT_TEAM = BA88US33G6;
|
DEVELOPMENT_TEAM = BA88US33G6;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
|
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
|
||||||
@@ -596,7 +596,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0.577;
|
MARKETING_VERSION = 1.0.578;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
|
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
@@ -720,7 +720,7 @@
|
|||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||||
CURRENT_PROJECT_VERSION = 577;
|
CURRENT_PROJECT_VERSION = 578;
|
||||||
DEVELOPMENT_TEAM = BA88US33G6;
|
DEVELOPMENT_TEAM = BA88US33G6;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
|
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
|
||||||
@@ -730,7 +730,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0.577;
|
MARKETING_VERSION = 1.0.578;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
|
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
@@ -748,7 +748,7 @@
|
|||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||||
CURRENT_PROJECT_VERSION = 577;
|
CURRENT_PROJECT_VERSION = 578;
|
||||||
DEVELOPMENT_TEAM = BA88US33G6;
|
DEVELOPMENT_TEAM = BA88US33G6;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
|
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
|
||||||
@@ -758,7 +758,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0.577;
|
MARKETING_VERSION = 1.0.578;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
|
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
@@ -779,7 +779,7 @@
|
|||||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 577;
|
CURRENT_PROJECT_VERSION = 578;
|
||||||
DEVELOPMENT_TEAM = BA88US33G6;
|
DEVELOPMENT_TEAM = BA88US33G6;
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
@@ -792,7 +792,7 @@
|
|||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
"@executable_path/../../Frameworks",
|
"@executable_path/../../Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0.577;
|
MARKETING_VERSION = 1.0.578;
|
||||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||||
MTL_FAST_MATH = YES;
|
MTL_FAST_MATH = YES;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget;
|
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget;
|
||||||
@@ -818,7 +818,7 @@
|
|||||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 577;
|
CURRENT_PROJECT_VERSION = 578;
|
||||||
DEVELOPMENT_TEAM = BA88US33G6;
|
DEVELOPMENT_TEAM = BA88US33G6;
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
@@ -831,7 +831,7 @@
|
|||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
"@executable_path/../../Frameworks",
|
"@executable_path/../../Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0.577;
|
MARKETING_VERSION = 1.0.578;
|
||||||
MTL_FAST_MATH = YES;
|
MTL_FAST_MATH = YES;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget;
|
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
@@ -854,7 +854,7 @@
|
|||||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 577;
|
CURRENT_PROJECT_VERSION = 578;
|
||||||
DEVELOPMENT_TEAM = BA88US33G6;
|
DEVELOPMENT_TEAM = BA88US33G6;
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
@@ -867,7 +867,7 @@
|
|||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
"@executable_path/../../Frameworks",
|
"@executable_path/../../Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0.577;
|
MARKETING_VERSION = 1.0.578;
|
||||||
MTL_FAST_MATH = YES;
|
MTL_FAST_MATH = YES;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget;
|
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
@@ -890,7 +890,7 @@
|
|||||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 577;
|
CURRENT_PROJECT_VERSION = 578;
|
||||||
DEVELOPMENT_ASSET_PATHS = "";
|
DEVELOPMENT_ASSET_PATHS = "";
|
||||||
DEVELOPMENT_TEAM = BA88US33G6;
|
DEVELOPMENT_TEAM = BA88US33G6;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
@@ -902,7 +902,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0.577;
|
MARKETING_VERSION = 1.0.578;
|
||||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||||
MTL_FAST_MATH = YES;
|
MTL_FAST_MATH = YES;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd;
|
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd;
|
||||||
@@ -931,7 +931,7 @@
|
|||||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 577;
|
CURRENT_PROJECT_VERSION = 578;
|
||||||
DEVELOPMENT_ASSET_PATHS = "";
|
DEVELOPMENT_ASSET_PATHS = "";
|
||||||
DEVELOPMENT_TEAM = BA88US33G6;
|
DEVELOPMENT_TEAM = BA88US33G6;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
@@ -943,7 +943,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0.577;
|
MARKETING_VERSION = 1.0.578;
|
||||||
MTL_FAST_MATH = YES;
|
MTL_FAST_MATH = YES;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd;
|
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd;
|
||||||
PRODUCT_NAME = ServerBox;
|
PRODUCT_NAME = ServerBox;
|
||||||
@@ -969,7 +969,7 @@
|
|||||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 577;
|
CURRENT_PROJECT_VERSION = 578;
|
||||||
DEVELOPMENT_ASSET_PATHS = "";
|
DEVELOPMENT_ASSET_PATHS = "";
|
||||||
DEVELOPMENT_TEAM = BA88US33G6;
|
DEVELOPMENT_TEAM = BA88US33G6;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
@@ -981,7 +981,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0.577;
|
MARKETING_VERSION = 1.0.578;
|
||||||
MTL_FAST_MATH = YES;
|
MTL_FAST_MATH = YES;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd;
|
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd;
|
||||||
PRODUCT_NAME = ServerBox;
|
PRODUCT_NAME = ServerBox;
|
||||||
|
|||||||
18
lib/app.dart
18
lib/app.dart
@@ -73,22 +73,14 @@ class MyApp extends StatelessWidget {
|
|||||||
|
|
||||||
Widget _wrapSystemColor(BuildContext context, Widget child) {
|
Widget _wrapSystemColor(BuildContext context, Widget child) {
|
||||||
return DynamicColorBuilder(builder: (light, dark) {
|
return DynamicColorBuilder(builder: (light, dark) {
|
||||||
_setupPrimaryColor(context, light, dark);
|
if (context.isDark && light != null) {
|
||||||
|
primaryColor = light.primary;
|
||||||
|
} else if (!context.isDark && dark != null) {
|
||||||
|
primaryColor = dark.primary;
|
||||||
|
}
|
||||||
return child;
|
return child;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void _setupPrimaryColor(
|
|
||||||
BuildContext context,
|
|
||||||
ColorScheme? light,
|
|
||||||
ColorScheme? dark,
|
|
||||||
) {
|
|
||||||
if (context.isDark && light != null) {
|
|
||||||
primaryColor = light.primary;
|
|
||||||
} else if (!context.isDark && dark != null) {
|
|
||||||
primaryColor = dark.primary;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ThemeData _getAmoledTheme(ThemeData darkTheme) => darkTheme.copyWith(
|
ThemeData _getAmoledTheme(ThemeData darkTheme) => darkTheme.copyWith(
|
||||||
|
|||||||
@@ -1,13 +1,11 @@
|
|||||||
|
import 'package:choice/choice.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:toolbox/core/extension/context/common.dart';
|
import 'package:toolbox/core/extension/context/common.dart';
|
||||||
import 'package:toolbox/core/extension/context/locale.dart';
|
import 'package:toolbox/core/extension/context/locale.dart';
|
||||||
import 'package:toolbox/data/res/provider.dart';
|
import 'package:toolbox/view/widget/choice_chip.dart';
|
||||||
|
|
||||||
import '../../../data/model/server/snippet.dart';
|
|
||||||
import '../../../data/res/ui.dart';
|
import '../../../data/res/ui.dart';
|
||||||
import '../../../view/widget/input_field.dart';
|
import '../../../view/widget/input_field.dart';
|
||||||
import '../../../view/widget/picker.dart';
|
|
||||||
import '../../route.dart';
|
|
||||||
|
|
||||||
extension DialogX on BuildContext {
|
extension DialogX on BuildContext {
|
||||||
Future<T?> showRoundDialog<T>({
|
Future<T?> showRoundDialog<T>({
|
||||||
@@ -53,45 +51,60 @@ extension DialogX on BuildContext {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void showSnippetDialog(
|
Future<List<T>?> showPickDialog<T>({
|
||||||
void Function(Snippet s) onSelected,
|
required List<T?> items,
|
||||||
) {
|
required String Function(T) name,
|
||||||
if (Pros.snippet.snippets.isEmpty) {
|
bool multi = true,
|
||||||
showRoundDialog(
|
}) async {
|
||||||
child: Text(l10n.noSavedSnippet),
|
var vals = <T>[];
|
||||||
actions: [
|
final sure = await showRoundDialog<bool>(
|
||||||
TextButton(
|
|
||||||
onPressed: () => pop(),
|
|
||||||
child: Text(l10n.ok),
|
|
||||||
),
|
|
||||||
TextButton(
|
|
||||||
onPressed: () {
|
|
||||||
pop();
|
|
||||||
AppRoute.snippetEdit().go(this);
|
|
||||||
},
|
|
||||||
child: Text(l10n.add),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var snippet = Pros.snippet.snippets.first;
|
|
||||||
showRoundDialog(
|
|
||||||
title: Text(l10n.choose),
|
title: Text(l10n.choose),
|
||||||
child: Picker(
|
child: Choice<T>(
|
||||||
items: Pros.snippet.snippets.map((e) => Text(e.name)).toList(),
|
onChanged: (value) => vals = value,
|
||||||
onSelected: (idx) => snippet = Pros.snippet.snippets[idx],
|
multiple: multi,
|
||||||
|
clearable: true,
|
||||||
|
builder: (state, _) {
|
||||||
|
return Wrap(
|
||||||
|
children: List<Widget>.generate(
|
||||||
|
items.length,
|
||||||
|
(index) {
|
||||||
|
final item = items[index];
|
||||||
|
if (item == null) return UIs.placeholder;
|
||||||
|
return ChoiceChipX<T>(
|
||||||
|
label: name(item),
|
||||||
|
state: state,
|
||||||
|
value: item,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () async {
|
onPressed: () => pop(true),
|
||||||
pop();
|
|
||||||
onSelected(snippet);
|
|
||||||
},
|
|
||||||
child: Text(l10n.ok),
|
child: Text(l10n.ok),
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
if (sure == true && vals.isNotEmpty) {
|
||||||
|
return vals;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<T?> showPickSingleDialog<T>({
|
||||||
|
required List<T?> items,
|
||||||
|
required String Function(T) name,
|
||||||
|
}) async {
|
||||||
|
final vals = await showPickDialog<T>(
|
||||||
|
items: items,
|
||||||
|
name: name,
|
||||||
|
multi: false,
|
||||||
|
);
|
||||||
|
if (vals != null && vals.isNotEmpty) {
|
||||||
|
return vals.first;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
class BuildData {
|
class BuildData {
|
||||||
static const String name = "ServerBox";
|
static const String name = "ServerBox";
|
||||||
static const int build = 577;
|
static const int build = 578;
|
||||||
static const String engine = "3.13.5";
|
static const String engine = "3.13.5";
|
||||||
static const String buildAt = "2023-09-25 18:52:38";
|
static const String buildAt = "2023-09-25 19:49:19";
|
||||||
static const int modifications = 3;
|
static const int modifications = 4;
|
||||||
static const int script = 19;
|
static const int script = 19;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -184,10 +184,10 @@ class SettingStore extends PersistentStore {
|
|||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Whether use `rm -rf` to delete directory on SFTP
|
/// Whether use `rm -r` to delete directory on SFTP
|
||||||
late final sftpRmrfDir = StoreProperty(
|
late final sftpRmrDir = StoreProperty(
|
||||||
box,
|
box,
|
||||||
'sftpRmrfDir',
|
'sftpRmrDir',
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -184,7 +184,7 @@
|
|||||||
"serverTabUnkown": "Unbekannter Status",
|
"serverTabUnkown": "Unbekannter Status",
|
||||||
"setting": "Einstellungen",
|
"setting": "Einstellungen",
|
||||||
"sftpDlPrepare": "Verbindung vorbereiten...",
|
"sftpDlPrepare": "Verbindung vorbereiten...",
|
||||||
"sftpRmrfDirSummary": "Verwenden Sie \"rm -rf\", um das Verzeichnis in SFTP zu löschen.",
|
"sftpRmrDirSummary": "Verwenden Sie \"rm -r\", um das Verzeichnis in SFTP zu löschen.",
|
||||||
"sftpSSHConnected": "SFTP Verbunden",
|
"sftpSSHConnected": "SFTP Verbunden",
|
||||||
"showDistLogo": "Distributionslogo anzeigen",
|
"showDistLogo": "Distributionslogo anzeigen",
|
||||||
"snippet": "Snippet",
|
"snippet": "Snippet",
|
||||||
|
|||||||
@@ -184,7 +184,7 @@
|
|||||||
"serverTabUnkown": "Unknown state",
|
"serverTabUnkown": "Unknown state",
|
||||||
"setting": "Settings",
|
"setting": "Settings",
|
||||||
"sftpDlPrepare": "Preparing to connect...",
|
"sftpDlPrepare": "Preparing to connect...",
|
||||||
"sftpRmrfDirSummary": "Use `rm -rf` to delete a folder in SFTP.",
|
"sftpRmrDirSummary": "Use `rm -r` to delete a folder in SFTP.",
|
||||||
"sftpSSHConnected": "SFTP Connected",
|
"sftpSSHConnected": "SFTP Connected",
|
||||||
"showDistLogo": "Show distribution logo",
|
"showDistLogo": "Show distribution logo",
|
||||||
"snippet": "Snippet",
|
"snippet": "Snippet",
|
||||||
|
|||||||
@@ -184,7 +184,7 @@
|
|||||||
"serverTabUnkown": "Negara yang tidak diketahui",
|
"serverTabUnkown": "Negara yang tidak diketahui",
|
||||||
"setting": "Pengaturan",
|
"setting": "Pengaturan",
|
||||||
"sftpDlPrepare": "Bersiap untuk terhubung ...",
|
"sftpDlPrepare": "Bersiap untuk terhubung ...",
|
||||||
"sftpRmrfDirSummary": "Gunakan `rm -rf` untuk menghapus dir di SFTP",
|
"sftpRmrDirSummary": "Gunakan `rm -r` untuk menghapus dir di SFTP",
|
||||||
"sftpSSHConnected": "Sftp terhubung",
|
"sftpSSHConnected": "Sftp terhubung",
|
||||||
"showDistLogo": "Tampilkan logo distribusi",
|
"showDistLogo": "Tampilkan logo distribusi",
|
||||||
"snippet": "Snippet",
|
"snippet": "Snippet",
|
||||||
|
|||||||
@@ -184,7 +184,7 @@
|
|||||||
"serverTabUnkown": "未知状态",
|
"serverTabUnkown": "未知状态",
|
||||||
"setting": "设置",
|
"setting": "设置",
|
||||||
"sftpDlPrepare": "准备连接至服务器...",
|
"sftpDlPrepare": "准备连接至服务器...",
|
||||||
"sftpRmrfDirSummary": "在 SFTP 中使用 `rm -rf` 来删除文件夹",
|
"sftpRmrDirSummary": "在 SFTP 中使用 `rm -r` 来删除文件夹",
|
||||||
"sftpSSHConnected": "SFTP 已连接...",
|
"sftpSSHConnected": "SFTP 已连接...",
|
||||||
"showDistLogo": "显示发行版 Logo",
|
"showDistLogo": "显示发行版 Logo",
|
||||||
"snippet": "代码片段",
|
"snippet": "代码片段",
|
||||||
|
|||||||
@@ -184,7 +184,7 @@
|
|||||||
"serverTabUnkown": "未知狀態",
|
"serverTabUnkown": "未知狀態",
|
||||||
"setting": "設置",
|
"setting": "設置",
|
||||||
"sftpDlPrepare": "準備連接至服務器...",
|
"sftpDlPrepare": "準備連接至服務器...",
|
||||||
"sftpRmrfDirSummary": "在 SFTP 中使用 `rm -rf` 來刪除文件夾",
|
"sftpRmrDirSummary": "在 SFTP 中使用 `rm -r` 來刪除文件夾",
|
||||||
"sftpSSHConnected": "SFTP 已連接...",
|
"sftpSSHConnected": "SFTP 已連接...",
|
||||||
"showDistLogo": "顯示發行版 Logo",
|
"showDistLogo": "顯示發行版 Logo",
|
||||||
"snippet": "程式片段",
|
"snippet": "程式片段",
|
||||||
|
|||||||
@@ -265,18 +265,24 @@ class _ServerPageState extends State<ServerPage>
|
|||||||
tooltip: 'Suspend',
|
tooltip: 'Suspend',
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () => _askFor(func: () => srv.client?.execWithPwd(
|
onPressed: () => _askFor(
|
||||||
ShellFunc.shutdown.exec,
|
func: () => srv.client?.execWithPwd(
|
||||||
context: context,
|
ShellFunc.shutdown.exec,
|
||||||
), msg: 'Shutdown ${srv.spi.name}',),
|
context: context,
|
||||||
|
),
|
||||||
|
msg: 'Shutdown ${srv.spi.name}',
|
||||||
|
),
|
||||||
icon: const Icon(Icons.power_off),
|
icon: const Icon(Icons.power_off),
|
||||||
tooltip: 'Shutdown',
|
tooltip: 'Shutdown',
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () => _askFor(func: () => srv.client?.execWithPwd(
|
onPressed: () => _askFor(
|
||||||
ShellFunc.reboot.exec,
|
func: () => srv.client?.execWithPwd(
|
||||||
context: context,
|
ShellFunc.reboot.exec,
|
||||||
), msg: 'Reboot ${srv.spi.name}',),
|
context: context,
|
||||||
|
),
|
||||||
|
msg: 'Reboot ${srv.spi.name}',
|
||||||
|
),
|
||||||
icon: const Icon(Icons.restart_alt),
|
icon: const Icon(Icons.restart_alt),
|
||||||
tooltip: 'Reboot',
|
tooltip: 'Reboot',
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -234,7 +234,7 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
// Use hardware keyboard on desktop, so there is no need to set it
|
// Use hardware keyboard on desktop, so there is no need to set it
|
||||||
if (isMobile) _buildKeyboardType(),
|
if (isMobile) _buildKeyboardType(),
|
||||||
_buildSSHVirtKeys(),
|
_buildSSHVirtKeys(),
|
||||||
_buildSftpRmrfDir(),
|
_buildSftpRmrDir(),
|
||||||
].map((e) => RoundRectCard(e)).toList(),
|
].map((e) => RoundRectCard(e)).toList(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -997,11 +997,11 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildSftpRmrfDir() {
|
Widget _buildSftpRmrDir() {
|
||||||
return ListTile(
|
return ListTile(
|
||||||
title: const Text('rm -rf'),
|
title: const Text('rm -r'),
|
||||||
subtitle: Text(l10n.sftpRmrfDirSummary, style: UIs.textGrey),
|
subtitle: Text(l10n.sftpRmrDirSummary, style: UIs.textGrey),
|
||||||
trailing: StoreSwitch(prop: _setting.sftpRmrfDir),
|
trailing: StoreSwitch(prop: _setting.sftpRmrDir),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -127,13 +127,10 @@ class _SnippetListPageState extends State<SnippetListPage> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _runSnippet(Snippet snippet) async {
|
Future<void> _runSnippet(Snippet snippet) async {
|
||||||
final servers = await showDialog<List<Server>>(
|
final servers = await context.showPickDialog<Server>(
|
||||||
context: context,
|
|
||||||
builder: (_) => TagPicker<Server>(
|
|
||||||
items: Pros.server.servers.toList(),
|
items: Pros.server.servers.toList(),
|
||||||
tags: Pros.server.tags.toSet(),
|
name: (e) => e.spi.name,
|
||||||
),
|
);
|
||||||
);
|
|
||||||
if (servers == null) {
|
if (servers == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,9 @@ import 'package:toolbox/core/extension/context/dialog.dart';
|
|||||||
import 'package:toolbox/core/extension/context/locale.dart';
|
import 'package:toolbox/core/extension/context/locale.dart';
|
||||||
import 'package:toolbox/core/extension/context/snackbar.dart';
|
import 'package:toolbox/core/extension/context/snackbar.dart';
|
||||||
import 'package:toolbox/core/utils/platform/base.dart';
|
import 'package:toolbox/core/utils/platform/base.dart';
|
||||||
|
import 'package:toolbox/data/model/server/snippet.dart';
|
||||||
import 'package:toolbox/data/provider/virtual_keyboard.dart';
|
import 'package:toolbox/data/provider/virtual_keyboard.dart';
|
||||||
|
import 'package:toolbox/data/res/provider.dart';
|
||||||
import 'package:toolbox/data/res/store.dart';
|
import 'package:toolbox/data/res/store.dart';
|
||||||
import 'package:xterm/core.dart';
|
import 'package:xterm/core.dart';
|
||||||
import 'package:xterm/ui.dart' hide TerminalThemes;
|
import 'package:xterm/ui.dart' hide TerminalThemes;
|
||||||
@@ -253,10 +255,13 @@ class _SSHPageState extends State<SSHPage> {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case VirtualKeyFunc.snippet:
|
case VirtualKeyFunc.snippet:
|
||||||
context.showSnippetDialog((s) {
|
final s = await context.showPickSingleDialog<Snippet>(
|
||||||
_terminal.textInput(s.script);
|
items: Pros.snippet.snippets,
|
||||||
_terminal.keyInput(TerminalKey.enter);
|
name: (p0) => p0.name,
|
||||||
});
|
);
|
||||||
|
if (s == null) return;
|
||||||
|
_terminal.textInput(s.script);
|
||||||
|
_terminal.keyInput(TerminalKey.enter);
|
||||||
break;
|
break;
|
||||||
case VirtualKeyFunc.file:
|
case VirtualKeyFunc.file:
|
||||||
// get $PWD from SSH session
|
// get $PWD from SSH session
|
||||||
|
|||||||
@@ -5,12 +5,12 @@ import 'package:toolbox/core/extension/context/common.dart';
|
|||||||
import 'package:toolbox/core/extension/context/dialog.dart';
|
import 'package:toolbox/core/extension/context/dialog.dart';
|
||||||
import 'package:toolbox/core/extension/context/locale.dart';
|
import 'package:toolbox/core/extension/context/locale.dart';
|
||||||
import 'package:toolbox/core/extension/context/snackbar.dart';
|
import 'package:toolbox/core/extension/context/snackbar.dart';
|
||||||
|
import 'package:toolbox/data/model/server/server_private_info.dart';
|
||||||
import 'package:toolbox/data/model/sftp/req.dart';
|
import 'package:toolbox/data/model/sftp/req.dart';
|
||||||
import 'package:toolbox/data/res/misc.dart';
|
import 'package:toolbox/data/res/misc.dart';
|
||||||
import 'package:toolbox/data/res/provider.dart';
|
import 'package:toolbox/data/res/provider.dart';
|
||||||
import 'package:toolbox/view/widget/input_field.dart';
|
import 'package:toolbox/view/widget/input_field.dart';
|
||||||
import 'package:toolbox/view/widget/omit_start_text.dart';
|
import 'package:toolbox/view/widget/omit_start_text.dart';
|
||||||
import 'package:toolbox/view/widget/picker.dart';
|
|
||||||
import 'package:toolbox/view/widget/round_rect_card.dart';
|
import 'package:toolbox/view/widget/round_rect_card.dart';
|
||||||
|
|
||||||
import '../../../core/extension/numx.dart';
|
import '../../../core/extension/numx.dart';
|
||||||
@@ -273,24 +273,15 @@ class _LocalStoragePageState extends State<LocalStoragePage> {
|
|||||||
title: Text(l10n.upload),
|
title: Text(l10n.upload),
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
context.pop();
|
context.pop();
|
||||||
final ids = Pros.server.serverOrder;
|
|
||||||
var idx = 0;
|
final spi = await context.showPickSingleDialog<ServerPrivateInfo>(
|
||||||
await context.showRoundDialog(
|
items: Pros.server.serverOrder
|
||||||
title: Text(l10n.server),
|
.map((e) => Pros.server.pick(id: e)?.spi)
|
||||||
child: Picker(
|
.toList(),
|
||||||
items: ids.map((e) => Text(e)).toList(),
|
name: (e) => e.name,
|
||||||
onSelected: (idx_) => idx = idx_,
|
|
||||||
),
|
|
||||||
actions: [
|
|
||||||
TextButton(
|
|
||||||
onPressed: () => context.pop(), child: Text(l10n.ok)),
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
final id = ids[idx];
|
if (spi == null) return;
|
||||||
final spi = Pros.server.pick(id: id)?.spi;
|
|
||||||
if (spi == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final remotePath = await AppRoute.sftp(
|
final remotePath = await AppRoute.sftp(
|
||||||
spi: spi,
|
spi: spi,
|
||||||
isSelect: true,
|
isSelect: true,
|
||||||
@@ -298,6 +289,7 @@ class _LocalStoragePageState extends State<LocalStoragePage> {
|
|||||||
if (remotePath == null) {
|
if (remotePath == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Pros.sftp.add(SftpReq(
|
Pros.sftp.add(SftpReq(
|
||||||
spi,
|
spi,
|
||||||
'$remotePath/$fileName',
|
'$remotePath/$fileName',
|
||||||
@@ -346,7 +338,7 @@ class _LocalStoragePageState extends State<LocalStoragePage> {
|
|||||||
final fileName = file.path.split('/').last;
|
final fileName = file.path.split('/').last;
|
||||||
context.showRoundDialog(
|
context.showRoundDialog(
|
||||||
title: Text(l10n.delete),
|
title: Text(l10n.delete),
|
||||||
child: Text(l10n.sureDelete(fileName)),
|
child: Text(l10n.askContinue('${l10n.delete}: $fileName')),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => context.pop(),
|
onPressed: () => context.pop(),
|
||||||
|
|||||||
@@ -409,13 +409,16 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
|
|||||||
void _delete(SftpName file) {
|
void _delete(SftpName file) {
|
||||||
context.pop();
|
context.pop();
|
||||||
final isDir = file.attr.isDirectory;
|
final isDir = file.attr.isDirectory;
|
||||||
final useRmrf = Stores.setting.sftpRmrfDir.fetch();
|
final useRmr = Stores.setting.sftpRmrDir.fetch();
|
||||||
final dirText = (isDir && !useRmrf) ? '\n${l10n.dirEmpty}' : '';
|
final text = () {
|
||||||
final text = l10n.askContinue(
|
if (isDir && !useRmr) {
|
||||||
'${l10n.delete} ${l10n.files}(${file.filename})\n$dirText');
|
return l10n.askContinue(
|
||||||
final child = Text(text);
|
'${l10n.dirEmpty}\n${l10n.delete} ${l10n.files}(${file.filename})');
|
||||||
|
}
|
||||||
|
return l10n.askContinue('${l10n.delete} ${l10n.files}(${file.filename})');
|
||||||
|
}();
|
||||||
context.showRoundDialog(
|
context.showRoundDialog(
|
||||||
child: child,
|
child: Text(text),
|
||||||
title: Text(l10n.attention),
|
title: Text(l10n.attention),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
@@ -428,8 +431,8 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
|
|||||||
context.showLoadingDialog();
|
context.showLoadingDialog();
|
||||||
final remotePath = _getRemotePath(file);
|
final remotePath = _getRemotePath(file);
|
||||||
try {
|
try {
|
||||||
if (useRmrf) {
|
if (useRmr) {
|
||||||
await _client!.run('rm -rf "$remotePath"');
|
await _client!.run('rm -r "$remotePath"');
|
||||||
} else if (file.attr.isDirectory) {
|
} else if (file.attr.isDirectory) {
|
||||||
await _status.client!.rmdir(remotePath);
|
await _status.client!.rmdir(remotePath);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
29
lib/view/widget/choice_chip.dart
Normal file
29
lib/view/widget/choice_chip.dart
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import 'package:choice/selection.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class ChoiceChipX<T> extends StatelessWidget {
|
||||||
|
const ChoiceChipX({
|
||||||
|
Key? key,
|
||||||
|
required this.label,
|
||||||
|
required this.state,
|
||||||
|
required this.value,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
final String label;
|
||||||
|
final ChoiceController<T> state;
|
||||||
|
final T value;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.all(3),
|
||||||
|
child: ChoiceChip(
|
||||||
|
label: Text(label),
|
||||||
|
side: BorderSide.none,
|
||||||
|
selected: state.selected(value),
|
||||||
|
selectedColor: Theme.of(context).colorScheme.primary,
|
||||||
|
onSelected: state.onSelected(value),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class Picker extends StatelessWidget {
|
|
||||||
final List<Widget> items;
|
|
||||||
final void Function(int idx) onSelected;
|
|
||||||
final double height;
|
|
||||||
|
|
||||||
const Picker({
|
|
||||||
super.key,
|
|
||||||
required this.items,
|
|
||||||
required this.onSelected,
|
|
||||||
this.height = 157,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final pad = (height - 37) / 2;
|
|
||||||
return SizedBox(
|
|
||||||
height: height,
|
|
||||||
child: Stack(
|
|
||||||
children: [
|
|
||||||
Positioned(
|
|
||||||
top: pad,
|
|
||||||
bottom: pad,
|
|
||||||
left: 0,
|
|
||||||
right: 0,
|
|
||||||
child: Container(
|
|
||||||
height: 37,
|
|
||||||
decoration: const BoxDecoration(
|
|
||||||
borderRadius: BorderRadius.all(Radius.circular(7)),
|
|
||||||
color: Colors.black12,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
ListWheelScrollView.useDelegate(
|
|
||||||
itemExtent: 37,
|
|
||||||
diameterRatio: 2.7,
|
|
||||||
controller: FixedExtentScrollController(initialItem: 0),
|
|
||||||
onSelectedItemChanged: (idx) => onSelected(idx),
|
|
||||||
physics: const FixedExtentScrollPhysics(),
|
|
||||||
childDelegate: ListWheelChildBuilderDelegate(
|
|
||||||
builder: (context, index) => Center(
|
|
||||||
child: items[index],
|
|
||||||
),
|
|
||||||
childCount: items.length,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -21,7 +21,6 @@ import '../../data/model/pkg/upgrade_info.dart';
|
|||||||
import '../../data/model/server/server_private_info.dart';
|
import '../../data/model/server/server_private_info.dart';
|
||||||
import '../../data/model/server/snippet.dart';
|
import '../../data/model/server/snippet.dart';
|
||||||
import 'popup_menu.dart';
|
import 'popup_menu.dart';
|
||||||
import 'tag.dart';
|
|
||||||
|
|
||||||
class ServerFuncBtnsTopRight extends StatelessWidget {
|
class ServerFuncBtnsTopRight extends StatelessWidget {
|
||||||
final ServerPrivateInfo spi;
|
final ServerPrivateInfo spi;
|
||||||
@@ -96,13 +95,10 @@ void _onTapMoreBtns(
|
|||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case ServerTabMenuType.snippet:
|
case ServerTabMenuType.snippet:
|
||||||
final snippets = await showDialog<List<Snippet>>(
|
final snippets = await context.showPickDialog<Snippet>(
|
||||||
context: context,
|
|
||||||
builder: (_) => TagPicker<Snippet>(
|
|
||||||
items: Pros.snippet.snippets,
|
items: Pros.snippet.snippets,
|
||||||
tags: Pros.server.tags.toSet(),
|
name: (e) => e.name,
|
||||||
),
|
);
|
||||||
);
|
|
||||||
if (snippets == null) {
|
if (snippets == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import 'package:toolbox/data/res/ui.dart';
|
|||||||
import 'package:toolbox/view/widget/input_field.dart';
|
import 'package:toolbox/view/widget/input_field.dart';
|
||||||
import 'package:toolbox/view/widget/round_rect_card.dart';
|
import 'package:toolbox/view/widget/round_rect_card.dart';
|
||||||
|
|
||||||
import '../../data/model/app/tag_pickable.dart';
|
|
||||||
import '../../data/res/color.dart';
|
import '../../data/res/color.dart';
|
||||||
|
|
||||||
const _kTagBtnHeight = 31.0;
|
const _kTagBtnHeight = 31.0;
|
||||||
@@ -179,119 +178,6 @@ class _TagEditorState extends State<TagEditor> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class TagPicker<T extends TagPickable> extends StatefulWidget {
|
|
||||||
final List<T> items;
|
|
||||||
final Set<String> tags;
|
|
||||||
|
|
||||||
const TagPicker({
|
|
||||||
Key? key,
|
|
||||||
required this.items,
|
|
||||||
required this.tags,
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
_TagPickerState<T> createState() => _TagPickerState<T>();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _TagPickerState<T extends TagPickable> extends State<TagPicker<T>> {
|
|
||||||
late MediaQueryData _media;
|
|
||||||
final List<T> _selected = [];
|
|
||||||
|
|
||||||
@override
|
|
||||||
void didChangeDependencies() {
|
|
||||||
super.didChangeDependencies();
|
|
||||||
_media = MediaQuery.of(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final children = <Widget>[];
|
|
||||||
if (widget.tags.isNotEmpty) {
|
|
||||||
children.add(Text(l10n.tag));
|
|
||||||
children.add(UIs.height13);
|
|
||||||
children.add(SizedBox(
|
|
||||||
height: _kTagBtnHeight,
|
|
||||||
width: _media.size.width * 0.7,
|
|
||||||
child: _buildTags(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
if (widget.items.isNotEmpty) {
|
|
||||||
children.add(Text(l10n.all));
|
|
||||||
children.add(UIs.height13);
|
|
||||||
children.add(SizedBox(
|
|
||||||
height: _kTagBtnHeight,
|
|
||||||
width: _media.size.width * 0.7,
|
|
||||||
child: _buildItems(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
final child = widget.tags.isEmpty && widget.items.isEmpty
|
|
||||||
? Text(l10n.noOptions)
|
|
||||||
: Column(mainAxisSize: MainAxisSize.min, children: children);
|
|
||||||
return AlertDialog(
|
|
||||||
title: Text(l10n.choose),
|
|
||||||
content: child,
|
|
||||||
actions: [
|
|
||||||
TextButton(
|
|
||||||
onPressed: () => context.pop(_selected),
|
|
||||||
child: Text(l10n.ok),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildTags() {
|
|
||||||
return ListView.builder(
|
|
||||||
scrollDirection: Axis.horizontal,
|
|
||||||
itemCount: widget.tags.length,
|
|
||||||
itemBuilder: (_, idx) {
|
|
||||||
final item = widget.tags.elementAt(idx);
|
|
||||||
final isEnable =
|
|
||||||
widget.items.where((ele) => ele.containsTag(item)).every(
|
|
||||||
(ele) => _selected.contains(ele),
|
|
||||||
);
|
|
||||||
return TagBtn(
|
|
||||||
isEnable: isEnable,
|
|
||||||
onTap: () {
|
|
||||||
if (isEnable) {
|
|
||||||
_selected.removeWhere(
|
|
||||||
(ele) => ele.containsTag(item),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
_selected.addAll(widget.items.where(
|
|
||||||
(ele) => ele.containsTag(item),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
setState(() {});
|
|
||||||
},
|
|
||||||
content: item,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildItems() {
|
|
||||||
return ListView.builder(
|
|
||||||
scrollDirection: Axis.horizontal,
|
|
||||||
itemCount: widget.items.length,
|
|
||||||
itemBuilder: (context, index) {
|
|
||||||
final e = widget.items[index];
|
|
||||||
return TagBtn(
|
|
||||||
isEnable: _selected.contains(e),
|
|
||||||
onTap: () {
|
|
||||||
if (_selected.contains(e)) {
|
|
||||||
_selected.remove(e);
|
|
||||||
} else {
|
|
||||||
_selected.add(e);
|
|
||||||
}
|
|
||||||
setState(() {});
|
|
||||||
},
|
|
||||||
content: e.tagName,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class TagSwitcher extends StatelessWidget {
|
class TagSwitcher extends StatelessWidget {
|
||||||
final List<String> tags;
|
final List<String> tags;
|
||||||
final double width;
|
final double width;
|
||||||
|
|||||||
@@ -476,9 +476,9 @@
|
|||||||
baseConfigurationReference = C1C758C41C4E208965A68933 /* Pods-RunnerTests.debug.xcconfig */;
|
baseConfigurationReference = C1C758C41C4E208965A68933 /* Pods-RunnerTests.debug.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
CURRENT_PROJECT_VERSION = 577;
|
CURRENT_PROJECT_VERSION = 578;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
MARKETING_VERSION = 1.0.577;
|
MARKETING_VERSION = 1.0.578;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = tech.lolli.serverBox.RunnerTests;
|
PRODUCT_BUNDLE_IDENTIFIER = tech.lolli.serverBox.RunnerTests;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
@@ -491,9 +491,9 @@
|
|||||||
baseConfigurationReference = 15AF97DF993E8968098D6EBE /* Pods-RunnerTests.release.xcconfig */;
|
baseConfigurationReference = 15AF97DF993E8968098D6EBE /* Pods-RunnerTests.release.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
CURRENT_PROJECT_VERSION = 577;
|
CURRENT_PROJECT_VERSION = 578;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
MARKETING_VERSION = 1.0.577;
|
MARKETING_VERSION = 1.0.578;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = tech.lolli.serverBox.RunnerTests;
|
PRODUCT_BUNDLE_IDENTIFIER = tech.lolli.serverBox.RunnerTests;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
@@ -506,9 +506,9 @@
|
|||||||
baseConfigurationReference = 7CFA7DE7FABA75685DFB6948 /* Pods-RunnerTests.profile.xcconfig */;
|
baseConfigurationReference = 7CFA7DE7FABA75685DFB6948 /* Pods-RunnerTests.profile.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
CURRENT_PROJECT_VERSION = 577;
|
CURRENT_PROJECT_VERSION = 578;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
MARKETING_VERSION = 1.0.577;
|
MARKETING_VERSION = 1.0.578;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = tech.lolli.serverBox.RunnerTests;
|
PRODUCT_BUNDLE_IDENTIFIER = tech.lolli.serverBox.RunnerTests;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
|
|||||||
@@ -145,6 +145,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.3"
|
version: "2.0.3"
|
||||||
|
choice:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: choice
|
||||||
|
sha256: "176e52882753cd6d3cdf537be3c392bc67f8114bc8bd2b1a625207015c6de856"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.0"
|
||||||
circle_chart:
|
circle_chart:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ dependencies:
|
|||||||
git:
|
git:
|
||||||
ref: master
|
ref: master
|
||||||
url: https://github.com/lollipopkit/watch_connectivity
|
url: https://github.com/lollipopkit/watch_connectivity
|
||||||
|
choice: ^2.0.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_native_splash: ^2.1.6
|
flutter_native_splash: ^2.1.6
|
||||||
|
|||||||
Reference in New Issue
Block a user