new: iperf

This commit is contained in:
lollipopkit
2024-01-21 18:53:17 +08:00
parent 50d6ed919b
commit 1434556e0b
34 changed files with 432 additions and 117 deletions

View File

@@ -214,12 +214,6 @@ abstract class S {
/// **'Backup'** /// **'Backup'**
String get backup; String get backup;
/// No description provided for @backupAndRestore.
///
/// In en, this message translates to:
/// **'Backup and Restore'**
String get backupAndRestore;
/// No description provided for @backupTip. /// No description provided for @backupTip.
/// ///
/// In en, this message translates to: /// In en, this message translates to:
@@ -1510,6 +1504,12 @@ abstract class S {
/// **'Times'** /// **'Times'**
String get times; String get times;
/// No description provided for @total.
///
/// In en, this message translates to:
/// **'Total'**
String get total;
/// No description provided for @traffic. /// No description provided for @traffic.
/// ///
/// In en, this message translates to: /// In en, this message translates to:
@@ -1606,6 +1606,12 @@ abstract class S {
/// **'No password will be used.'** /// **'No password will be used.'**
String get useNoPwd; String get useNoPwd;
/// No description provided for @used.
///
/// In en, this message translates to:
/// **'Used'**
String get used;
/// No description provided for @user. /// No description provided for @user.
/// ///
/// In en, this message translates to: /// In en, this message translates to:

View File

@@ -63,9 +63,6 @@ class SDe extends S {
@override @override
String get backup => 'Backup'; String get backup => 'Backup';
@override
String get backupAndRestore => 'Backup und Wiederherstellung';
@override @override
String get backupTip => 'Das Backup wird nur einfach verschlüsselt.\nBitte bewahre die Datei sicher auf.'; String get backupTip => 'Das Backup wird nur einfach verschlüsselt.\nBitte bewahre die Datei sicher auf.';
@@ -741,6 +738,9 @@ class SDe extends S {
@override @override
String get times => 'x'; String get times => 'x';
@override
String get total => 'Total';
@override @override
String get traffic => 'Durchflussmenge'; String get traffic => 'Durchflussmenge';
@@ -793,6 +793,9 @@ class SDe extends S {
@override @override
String get useNoPwd => 'Es wird kein Passwort verwendet.'; String get useNoPwd => 'Es wird kein Passwort verwendet.';
@override
String get used => 'Gebraucht';
@override @override
String get user => 'Benutzer'; String get user => 'Benutzer';

View File

@@ -63,9 +63,6 @@ class SEn extends S {
@override @override
String get backup => 'Backup'; String get backup => 'Backup';
@override
String get backupAndRestore => 'Backup and Restore';
@override @override
String get backupTip => 'The exported data is simply encrypted. \nPlease keep it safe.'; String get backupTip => 'The exported data is simply encrypted. \nPlease keep it safe.';
@@ -741,6 +738,9 @@ class SEn extends S {
@override @override
String get times => 'Times'; String get times => 'Times';
@override
String get total => 'Total';
@override @override
String get traffic => 'Traffic'; String get traffic => 'Traffic';
@@ -793,6 +793,9 @@ class SEn extends S {
@override @override
String get useNoPwd => 'No password will be used.'; String get useNoPwd => 'No password will be used.';
@override
String get used => 'Used';
@override @override
String get user => 'User'; String get user => 'User';

View File

@@ -63,9 +63,6 @@ class SFr extends S {
@override @override
String get backup => 'Sauvegarder'; String get backup => 'Sauvegarder';
@override
String get backupAndRestore => 'Sauvegarde et restauration';
@override @override
String get backupTip => 'Les données exportées sont simplement chiffrées. \nVeuillez les conserver en lieu sûr.'; String get backupTip => 'Les données exportées sont simplement chiffrées. \nVeuillez les conserver en lieu sûr.';
@@ -741,6 +738,9 @@ class SFr extends S {
@override @override
String get times => 'Fois'; String get times => 'Fois';
@override
String get total => 'Total';
@override @override
String get traffic => 'Trafic'; String get traffic => 'Trafic';
@@ -793,6 +793,9 @@ class SFr extends S {
@override @override
String get useNoPwd => 'Aucun mot de passe ne sera utilisé.'; String get useNoPwd => 'Aucun mot de passe ne sera utilisé.';
@override
String get used => 'Utilisé';
@override @override
String get user => 'Utilisateur'; String get user => 'Utilisateur';

View File

@@ -63,9 +63,6 @@ class SId extends S {
@override @override
String get backup => 'Cadangan'; String get backup => 'Cadangan';
@override
String get backupAndRestore => 'Cadangan dan Pulihkan';
@override @override
String get backupTip => 'Data yang diekspor hanya dienkripsi.\nTolong jaga keamanannya.'; String get backupTip => 'Data yang diekspor hanya dienkripsi.\nTolong jaga keamanannya.';
@@ -741,6 +738,9 @@ class SId extends S {
@override @override
String get times => 'Waktu'; String get times => 'Waktu';
@override
String get total => 'Total';
@override @override
String get traffic => 'Lalu lintas'; String get traffic => 'Lalu lintas';
@@ -793,6 +793,9 @@ class SId extends S {
@override @override
String get useNoPwd => 'Tidak ada kata sandi yang akan digunakan.'; String get useNoPwd => 'Tidak ada kata sandi yang akan digunakan.';
@override
String get used => 'Digunakan';
@override @override
String get user => 'Username'; String get user => 'Username';

View File

@@ -63,9 +63,6 @@ class SZh extends S {
@override @override
String get backup => '备份'; String get backup => '备份';
@override
String get backupAndRestore => '备份和恢复';
@override @override
String get backupTip => '导出的数据仅进行了简单加密,请妥善保管。'; String get backupTip => '导出的数据仅进行了简单加密,请妥善保管。';
@@ -741,6 +738,9 @@ class SZh extends S {
@override @override
String get times => ''; String get times => '';
@override
String get total => '总共';
@override @override
String get traffic => '流量'; String get traffic => '流量';
@@ -793,6 +793,9 @@ class SZh extends S {
@override @override
String get useNoPwd => '将会使用无密码。'; String get useNoPwd => '将会使用无密码。';
@override
String get used => '已用';
@override @override
String get user => '用户'; String get user => '用户';
@@ -902,9 +905,6 @@ class SZhTw extends SZh {
@override @override
String get backup => '備份'; String get backup => '備份';
@override
String get backupAndRestore => '備份和還原';
@override @override
String get backupTip => '導出的數據僅進行了簡單加密,請妥善保管。'; String get backupTip => '導出的數據僅進行了簡單加密,請妥善保管。';
@@ -1580,6 +1580,9 @@ class SZhTw extends SZh {
@override @override
String get times => ''; String get times => '';
@override
String get total => '總共';
@override @override
String get traffic => '流量'; String get traffic => '流量';
@@ -1632,6 +1635,9 @@ class SZhTw extends SZh {
@override @override
String get useNoPwd => '将使用無密碼。'; String get useNoPwd => '将使用無密碼。';
@override
String get used => '已用';
@override @override
String get user => '用戶'; String get user => '用戶';

View File

@@ -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 = 712; CURRENT_PROJECT_VERSION = 715;
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.712; MARKETING_VERSION = 1.0.715;
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 = 712; CURRENT_PROJECT_VERSION = 715;
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.712; MARKETING_VERSION = 1.0.715;
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 = 712; CURRENT_PROJECT_VERSION = 715;
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.712; MARKETING_VERSION = 1.0.715;
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 = 712; CURRENT_PROJECT_VERSION = 715;
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.712; MARKETING_VERSION = 1.0.715;
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 = 712; CURRENT_PROJECT_VERSION = 715;
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.712; MARKETING_VERSION = 1.0.715;
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 = 712; CURRENT_PROJECT_VERSION = 715;
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.712; MARKETING_VERSION = 1.0.715;
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 = 712; CURRENT_PROJECT_VERSION = 715;
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.712; MARKETING_VERSION = 1.0.715;
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 = 712; CURRENT_PROJECT_VERSION = 715;
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.712; MARKETING_VERSION = 1.0.715;
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 = 712; CURRENT_PROJECT_VERSION = 715;
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.712; MARKETING_VERSION = 1.0.715;
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;

View File

@@ -5,15 +5,17 @@ import 'package:toolbox/data/model/server/server_private_info.dart';
import 'package:toolbox/view/page/backup.dart'; import 'package:toolbox/view/page/backup.dart';
import 'package:toolbox/view/page/container.dart'; import 'package:toolbox/view/page/container.dart';
import 'package:toolbox/view/page/home.dart'; import 'package:toolbox/view/page/home.dart';
import 'package:toolbox/view/page/iperf.dart';
import 'package:toolbox/view/page/ping.dart'; import 'package:toolbox/view/page/ping.dart';
import 'package:toolbox/view/page/private_key/edit.dart'; import 'package:toolbox/view/page/private_key/edit.dart';
import 'package:toolbox/view/page/private_key/list.dart'; import 'package:toolbox/view/page/private_key/list.dart';
import 'package:toolbox/view/page/server/detail.dart'; import 'package:toolbox/view/page/server/detail.dart';
import 'package:toolbox/view/page/setting/android.dart'; import 'package:toolbox/view/page/setting/platform/android.dart';
import 'package:toolbox/view/page/setting/ios.dart'; import 'package:toolbox/view/page/setting/platform/ios.dart';
import 'package:toolbox/view/page/setting/seq/srv_func_seq.dart';
import 'package:toolbox/view/page/snippet/result.dart'; import 'package:toolbox/view/page/snippet/result.dart';
import 'package:toolbox/view/page/ssh/page.dart'; import 'package:toolbox/view/page/ssh/page.dart';
import 'package:toolbox/view/page/setting/virt_key.dart'; import 'package:toolbox/view/page/setting/seq/virt_key.dart';
import 'package:toolbox/view/page/storage/local.dart'; import 'package:toolbox/view/page/storage/local.dart';
import '../data/model/server/snippet.dart'; import '../data/model/server/snippet.dart';
@@ -24,8 +26,8 @@ import '../view/page/process.dart';
import '../view/page/server/edit.dart'; import '../view/page/server/edit.dart';
import '../view/page/server/tab.dart'; import '../view/page/server/tab.dart';
import '../view/page/setting/entry.dart'; import '../view/page/setting/entry.dart';
import '../view/page/setting/srv_detail_seq.dart'; import '../view/page/setting/seq/srv_detail_seq.dart';
import '../view/page/setting/srv_seq.dart'; import '../view/page/setting/seq/srv_seq.dart';
import '../view/page/snippet/edit.dart'; import '../view/page/snippet/edit.dart';
import '../view/page/snippet/list.dart'; import '../view/page/snippet/list.dart';
import '../view/page/storage/sftp.dart'; import '../view/page/storage/sftp.dart';
@@ -218,4 +220,12 @@ class AppRoute {
), ),
'snippet_result'); 'snippet_result');
} }
static AppRoute iperf({Key? key, required ServerPrivateInfo spi}) {
return AppRoute(IPerfPage(key: key, spi: spi), 'iperf');
}
static AppRoute serverFuncBtnsOrder({Key? key}) {
return AppRoute(ServerFuncBtnsOrderPage(key: key), 'server_func_btns_seq');
}
} }

View File

@@ -1,30 +1,44 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:toolbox/core/extension/context/locale.dart'; import 'package:toolbox/core/extension/context/locale.dart';
enum ServerTabMenu { part 'server_func.g.dart';
@HiveType(typeId: 6)
enum ServerFuncBtn {
@HiveField(0)
terminal, terminal,
@HiveField(1)
sftp, sftp,
@HiveField(2)
container, container,
@HiveField(3)
process, process,
@HiveField(4)
pkg, pkg,
@HiveField(5)
snippet, snippet,
@HiveField(6)
iperf,
; ;
IconData get icon => switch (this) { IconData get icon => switch (this) {
ServerTabMenu.sftp => Icons.insert_drive_file, sftp => Icons.insert_drive_file,
ServerTabMenu.snippet => Icons.code, snippet => Icons.code,
ServerTabMenu.pkg => Icons.system_security_update, pkg => Icons.system_security_update,
ServerTabMenu.container => Icons.view_agenda, container => Icons.view_agenda,
ServerTabMenu.process => Icons.list_alt_outlined, process => Icons.list_alt_outlined,
ServerTabMenu.terminal => Icons.terminal, terminal => Icons.terminal,
iperf => Icons.speed,
}; };
String get toStr => switch (this) { String get toStr => switch (this) {
ServerTabMenu.sftp => 'SFTP', sftp => 'SFTP',
ServerTabMenu.snippet => l10n.snippet, snippet => l10n.snippet,
ServerTabMenu.pkg => l10n.pkg, pkg => l10n.pkg,
ServerTabMenu.container => l10n.container, container => l10n.container,
ServerTabMenu.process => l10n.process, process => l10n.process,
ServerTabMenu.terminal => l10n.terminal, terminal => l10n.terminal,
iperf => 'iperf',
}; };
} }

View File

@@ -0,0 +1,71 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'server_func.dart';
// **************************************************************************
// TypeAdapterGenerator
// **************************************************************************
class ServerFuncBtnAdapter extends TypeAdapter<ServerFuncBtn> {
@override
final int typeId = 6;
@override
ServerFuncBtn read(BinaryReader reader) {
switch (reader.readByte()) {
case 0:
return ServerFuncBtn.terminal;
case 1:
return ServerFuncBtn.sftp;
case 2:
return ServerFuncBtn.container;
case 3:
return ServerFuncBtn.process;
case 4:
return ServerFuncBtn.pkg;
case 5:
return ServerFuncBtn.snippet;
case 6:
return ServerFuncBtn.iperf;
default:
return ServerFuncBtn.terminal;
}
}
@override
void write(BinaryWriter writer, ServerFuncBtn obj) {
switch (obj) {
case ServerFuncBtn.terminal:
writer.writeByte(0);
break;
case ServerFuncBtn.sftp:
writer.writeByte(1);
break;
case ServerFuncBtn.container:
writer.writeByte(2);
break;
case ServerFuncBtn.process:
writer.writeByte(3);
break;
case ServerFuncBtn.pkg:
writer.writeByte(4);
break;
case ServerFuncBtn.snippet:
writer.writeByte(5);
break;
case ServerFuncBtn.iperf:
writer.writeByte(6);
break;
}
}
@override
int get hashCode => typeId.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is ServerFuncBtnAdapter &&
runtimeType == other.runtimeType &&
typeId == other.typeId;
}

View File

@@ -140,9 +140,13 @@ class ServerProvider extends ChangeNotifier {
static final refreshKey = GlobalKey<RefreshIndicatorState>(); static final refreshKey = GlobalKey<RefreshIndicatorState>();
Future<void> startAutoRefresh() async { Future<void> startAutoRefresh() async {
final duration = Stores.setting.serverStatusUpdateInterval.fetch(); var duration = Stores.setting.serverStatusUpdateInterval.fetch();
stopAutoRefresh(); stopAutoRefresh();
if (duration == 0) return; if (duration == 0) return;
if (duration < 0 || duration > 10 || duration == 1) {
duration = 3;
Loggers.app.warning('Invalid duration: $duration, use default 3');
}
refreshKey.currentState?.show(); refreshKey.currentState?.show();
_timer = Timer.periodic(Duration(seconds: duration), (_) async { _timer = Timer.periodic(Duration(seconds: duration), (_) async {
await refreshData(); await refreshData();

View File

@@ -2,9 +2,9 @@
class BuildData { class BuildData {
static const String name = "ServerBox"; static const String name = "ServerBox";
static const int build = 712; static const int build = 715;
static const String engine = "3.16.7"; static const String engine = "3.16.8";
static const String buildAt = "2024-01-21 15:41:48"; static const String buildAt = "2024-01-21 18:14:00";
static const int modifications = 5; static const int modifications = 20;
static const int script = 35; static const int script = 36;
} }

View File

@@ -1,6 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:toolbox/core/persistant_store.dart'; import 'package:toolbox/core/persistant_store.dart';
import 'package:toolbox/core/utils/platform/base.dart'; import 'package:toolbox/core/utils/platform/base.dart';
import 'package:toolbox/data/model/app/menu/server_func.dart';
import '../model/app/net_view.dart'; import '../model/app/net_view.dart';
import '../res/default.dart'; import '../res/default.dart';
@@ -208,6 +209,15 @@ class SettingStore extends PersistentStore {
/// Whether collapse UI items by default /// Whether collapse UI items by default
late final collapseUIDefault = property('collapseUIDefault', true); late final collapseUIDefault = property('collapseUIDefault', true);
late final serverFuncBtns = listProperty<ServerFuncBtn>('serverBtns', [
ServerFuncBtn.terminal,
ServerFuncBtn.sftp,
ServerFuncBtn.container,
ServerFuncBtn.process,
ServerFuncBtn.pkg,
ServerFuncBtn.snippet,
]);
// Never show these settings for users // Never show these settings for users
// //
// ------BEGIN------ // ------BEGIN------

View File

@@ -19,7 +19,6 @@
"autoConnect": "Automatisch verbinden", "autoConnect": "Automatisch verbinden",
"autoUpdateHomeWidget": "Home-Widget automatisch aktualisieren", "autoUpdateHomeWidget": "Home-Widget automatisch aktualisieren",
"backup": "Backup", "backup": "Backup",
"backupAndRestore": "Backup und Wiederherstellung",
"backupTip": "Das Backup wird nur einfach verschlüsselt.\nBitte bewahre die Datei sicher auf.", "backupTip": "Das Backup wird nur einfach verschlüsselt.\nBitte bewahre die Datei sicher auf.",
"backupVersionNotMatch": "Die Backup-Version stimmt nicht überein.", "backupVersionNotMatch": "Die Backup-Version stimmt nicht überein.",
"battery": "Batterie", "battery": "Batterie",
@@ -235,6 +234,7 @@
"themeMode": "Themen-Modus", "themeMode": "Themen-Modus",
"time": "Zeit", "time": "Zeit",
"times": "x", "times": "x",
"total": "Total",
"traffic": "Durchflussmenge", "traffic": "Durchflussmenge",
"ttl": "ttl", "ttl": "ttl",
"unknown": "Unbekannt", "unknown": "Unbekannt",
@@ -250,6 +250,7 @@
"upsideDown": "Upside Down", "upsideDown": "Upside Down",
"urlOrJson": "URL oder JSON", "urlOrJson": "URL oder JSON",
"useNoPwd": "Es wird kein Passwort verwendet.", "useNoPwd": "Es wird kein Passwort verwendet.",
"used": "Gebraucht",
"user": "Benutzer", "user": "Benutzer",
"versionHaveUpdate": "Gefunden: v1.0.{build}, klicke zum Aktualisieren", "versionHaveUpdate": "Gefunden: v1.0.{build}, klicke zum Aktualisieren",
"versionUnknownUpdate": "Aktuell: v1.0.{build}. Klicken Sie hier, um nach Updates zu suchen", "versionUnknownUpdate": "Aktuell: v1.0.{build}. Klicken Sie hier, um nach Updates zu suchen",

View File

@@ -19,7 +19,6 @@
"autoConnect": "Auto connect", "autoConnect": "Auto connect",
"autoUpdateHomeWidget": "Auto update home widget", "autoUpdateHomeWidget": "Auto update home widget",
"backup": "Backup", "backup": "Backup",
"backupAndRestore": "Backup and Restore",
"backupTip": "The exported data is simply encrypted. \nPlease keep it safe.", "backupTip": "The exported data is simply encrypted. \nPlease keep it safe.",
"backupVersionNotMatch": "Backup version is not match.", "backupVersionNotMatch": "Backup version is not match.",
"battery": "Battery", "battery": "Battery",
@@ -235,6 +234,7 @@
"themeMode": "Theme mode", "themeMode": "Theme mode",
"time": "Time", "time": "Time",
"times": "Times", "times": "Times",
"total": "Total",
"traffic": "Traffic", "traffic": "Traffic",
"ttl": "ttl", "ttl": "ttl",
"unknown": "Unknown", "unknown": "Unknown",
@@ -251,6 +251,7 @@
"uptime": "Uptime", "uptime": "Uptime",
"urlOrJson": "URL or JSON", "urlOrJson": "URL or JSON",
"useNoPwd": "No password will be used.", "useNoPwd": "No password will be used.",
"used": "Used",
"user": "User", "user": "User",
"versionHaveUpdate": "Found: v1.0.{build}, click to update", "versionHaveUpdate": "Found: v1.0.{build}, click to update",
"versionUnknownUpdate": "Current: v1.0.{build}, click to check updates", "versionUnknownUpdate": "Current: v1.0.{build}, click to check updates",

View File

@@ -19,7 +19,6 @@
"autoConnect": "Connexion automatique", "autoConnect": "Connexion automatique",
"autoUpdateHomeWidget": "Mise à jour automatique du widget d'accueil", "autoUpdateHomeWidget": "Mise à jour automatique du widget d'accueil",
"backup": "Sauvegarder", "backup": "Sauvegarder",
"backupAndRestore": "Sauvegarde et restauration",
"backupTip": "Les données exportées sont simplement chiffrées. \nVeuillez les conserver en lieu sûr.", "backupTip": "Les données exportées sont simplement chiffrées. \nVeuillez les conserver en lieu sûr.",
"backupVersionNotMatch": "La version de sauvegarde ne correspond pas.", "backupVersionNotMatch": "La version de sauvegarde ne correspond pas.",
"battery": "Batterie", "battery": "Batterie",
@@ -235,6 +234,7 @@
"themeMode": "Mode du thème", "themeMode": "Mode du thème",
"time": "L'heure", "time": "L'heure",
"times": "Fois", "times": "Fois",
"total": "Total",
"traffic": "Trafic", "traffic": "Trafic",
"ttl": "ttl", "ttl": "ttl",
"unknown": "Inconnu", "unknown": "Inconnu",
@@ -251,6 +251,7 @@
"uptime": "Temps de disponibilité", "uptime": "Temps de disponibilité",
"urlOrJson": "URL ou JSON", "urlOrJson": "URL ou JSON",
"useNoPwd": "Aucun mot de passe ne sera utilisé.", "useNoPwd": "Aucun mot de passe ne sera utilisé.",
"used": "Utilisé",
"user": "Utilisateur", "user": "Utilisateur",
"versionHaveUpdate": "Trouvé : v1.0.{build}, cliquez pour mettre à jour", "versionHaveUpdate": "Trouvé : v1.0.{build}, cliquez pour mettre à jour",
"versionUnknownUpdate": "Actuel : v1.0.{build}, cliquez pour vérifier les mises à jour", "versionUnknownUpdate": "Actuel : v1.0.{build}, cliquez pour vérifier les mises à jour",

View File

@@ -19,7 +19,6 @@
"autoConnect": "Hubungkan otomatis", "autoConnect": "Hubungkan otomatis",
"autoUpdateHomeWidget": "Widget Rumah Pembaruan Otomatis", "autoUpdateHomeWidget": "Widget Rumah Pembaruan Otomatis",
"backup": "Cadangan", "backup": "Cadangan",
"backupAndRestore": "Cadangan dan Pulihkan",
"backupTip": "Data yang diekspor hanya dienkripsi.\nTolong jaga keamanannya.", "backupTip": "Data yang diekspor hanya dienkripsi.\nTolong jaga keamanannya.",
"backupVersionNotMatch": "Versi cadangan tidak cocok.", "backupVersionNotMatch": "Versi cadangan tidak cocok.",
"battery": "Baterai", "battery": "Baterai",
@@ -235,6 +234,7 @@
"themeMode": "Mode tema", "themeMode": "Mode tema",
"time": "Waktu", "time": "Waktu",
"times": "Waktu", "times": "Waktu",
"total": "Total",
"traffic": "Lalu lintas", "traffic": "Lalu lintas",
"ttl": "ttl", "ttl": "ttl",
"unknown": "Tidak dikenal", "unknown": "Tidak dikenal",
@@ -250,6 +250,7 @@
"upsideDown": "Terbalik", "upsideDown": "Terbalik",
"urlOrJson": "URL atau JSON", "urlOrJson": "URL atau JSON",
"useNoPwd": "Tidak ada kata sandi yang akan digunakan.", "useNoPwd": "Tidak ada kata sandi yang akan digunakan.",
"used": "Digunakan",
"user": "Username", "user": "Username",
"versionHaveUpdate": "Ditemukan: v1.0.{build}, klik untuk memperbarui", "versionHaveUpdate": "Ditemukan: v1.0.{build}, klik untuk memperbarui",
"versionUnknownUpdate": "Saat ini: v1.0.{build}. Klik untuk memeriksa pembaruan.", "versionUnknownUpdate": "Saat ini: v1.0.{build}. Klik untuk memeriksa pembaruan.",

View File

@@ -19,7 +19,6 @@
"autoConnect": "自动连接", "autoConnect": "自动连接",
"autoUpdateHomeWidget": "自动更新桌面小部件", "autoUpdateHomeWidget": "自动更新桌面小部件",
"backup": "备份", "backup": "备份",
"backupAndRestore": "备份和恢复",
"backupTip": "导出的数据仅进行了简单加密,请妥善保管。", "backupTip": "导出的数据仅进行了简单加密,请妥善保管。",
"backupVersionNotMatch": "备份版本不匹配,无法恢复", "backupVersionNotMatch": "备份版本不匹配,无法恢复",
"battery": "电池", "battery": "电池",
@@ -235,6 +234,7 @@
"themeMode": "主题模式", "themeMode": "主题模式",
"time": "时间", "time": "时间",
"times": "次", "times": "次",
"total": "总共",
"traffic": "流量", "traffic": "流量",
"ttl": "缓存时间", "ttl": "缓存时间",
"unknown": "未知", "unknown": "未知",
@@ -251,6 +251,7 @@
"uptime": "启动时长", "uptime": "启动时长",
"urlOrJson": "链接或JSON", "urlOrJson": "链接或JSON",
"useNoPwd": "将会使用无密码。", "useNoPwd": "将会使用无密码。",
"used": "已用",
"user": "用户", "user": "用户",
"versionHaveUpdate": "找到新版本v1.0.{build}, 点击更新", "versionHaveUpdate": "找到新版本v1.0.{build}, 点击更新",
"versionUnknownUpdate": "当前v1.0.{build},点击检查更新", "versionUnknownUpdate": "当前v1.0.{build},点击检查更新",

View File

@@ -19,7 +19,6 @@
"autoConnect": "自動連接", "autoConnect": "自動連接",
"autoUpdateHomeWidget": "自動更新桌面小部件", "autoUpdateHomeWidget": "自動更新桌面小部件",
"backup": "備份", "backup": "備份",
"backupAndRestore": "備份和還原",
"backupTip": "導出的數據僅進行了簡單加密,請妥善保管。", "backupTip": "導出的數據僅進行了簡單加密,請妥善保管。",
"backupVersionNotMatch": "備份版本不匹配,無法還原", "backupVersionNotMatch": "備份版本不匹配,無法還原",
"battery": "電池", "battery": "電池",
@@ -235,6 +234,7 @@
"themeMode": "主題模式", "themeMode": "主題模式",
"time": "時間", "time": "時間",
"times": "次", "times": "次",
"total": "總共",
"traffic": "流量", "traffic": "流量",
"ttl": "緩存時間", "ttl": "緩存時間",
"unknown": "未知", "unknown": "未知",
@@ -251,6 +251,7 @@
"uptime": "啟動時長", "uptime": "啟動時長",
"urlOrJson": "鏈接或JSON", "urlOrJson": "鏈接或JSON",
"useNoPwd": "将使用無密碼。", "useNoPwd": "将使用無密碼。",
"used": "已用",
"user": "用戶", "user": "用戶",
"versionHaveUpdate": "找到新版本v1.0.{build}, 點擊更新", "versionHaveUpdate": "找到新版本v1.0.{build}, 點擊更新",
"versionUnknownUpdate": "當前v1.0.{build},點擊檢查更新", "versionUnknownUpdate": "當前v1.0.{build},點擊檢查更新",

View File

@@ -15,6 +15,7 @@ import 'package:toolbox/core/utils/sync/icloud.dart';
import 'package:toolbox/core/utils/platform/base.dart'; import 'package:toolbox/core/utils/platform/base.dart';
import 'package:toolbox/core/utils/sync/webdav.dart'; import 'package:toolbox/core/utils/sync/webdav.dart';
import 'package:toolbox/core/utils/ui.dart'; import 'package:toolbox/core/utils/ui.dart';
import 'package:toolbox/data/model/app/menu/server_func.dart';
import 'package:toolbox/data/res/logger.dart'; import 'package:toolbox/data/res/logger.dart';
import 'package:toolbox/data/res/provider.dart'; import 'package:toolbox/data/res/provider.dart';
import 'package:toolbox/data/res/store.dart'; import 'package:toolbox/data/res/store.dart';
@@ -118,6 +119,7 @@ Future<void> _initDb() async {
Hive.registerAdapter(ServerPrivateInfoAdapter()); // 3 Hive.registerAdapter(ServerPrivateInfoAdapter()); // 3
Hive.registerAdapter(VirtKeyAdapter()); // 4 Hive.registerAdapter(VirtKeyAdapter()); // 4
Hive.registerAdapter(NetViewTypeAdapter()); // 5 Hive.registerAdapter(NetViewTypeAdapter()); // 5
Hive.registerAdapter(ServerFuncBtnAdapter()); // 6
} }
void _setupLogger() { void _setupLogger() {

View File

@@ -33,7 +33,7 @@ class BackupPage extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: CustomAppBar( appBar: CustomAppBar(
title: Text(l10n.backupAndRestore, style: UIs.text18), title: Text(l10n.backup, style: UIs.text18),
), ),
body: _buildBody(context), body: _buildBody(context),
); );

View File

@@ -232,7 +232,7 @@ class _HomePageState extends State<HomePage>
), ),
ListTile( ListTile(
leading: const Icon(Icons.import_export), leading: const Icon(Icons.import_export),
title: Text(l10n.backupAndRestore), title: Text(l10n.backup),
onTap: () => AppRoute.backup().go(context), onTap: () => AppRoute.backup().go(context),
), ),
ListTile( ListTile(
@@ -286,7 +286,7 @@ ${GithubIds.contributors.map((e) => '[$e](${e.url})').join(' ')}
#### Participants #### Participants
${GithubIds.participants.map((e) => '[$e](${e.url})').join(' ')} ${GithubIds.participants.map((e) => '[$e](${e.url})').join(' ')}
#### My apps #### My other apps
- [GPT Box](https://github.com/lollipopkit/flutter_gpt_box) - [GPT Box](https://github.com/lollipopkit/flutter_gpt_box)
''', ''',
), ),

67
lib/view/page/iperf.dart Normal file
View File

@@ -0,0 +1,67 @@
import 'package:flutter/material.dart';
import 'package:toolbox/core/extension/context/locale.dart';
import 'package:toolbox/core/extension/context/snackbar.dart';
import 'package:toolbox/core/route.dart';
import 'package:toolbox/data/model/server/server_private_info.dart';
import 'package:toolbox/view/widget/appbar.dart';
import 'package:toolbox/view/widget/input_field.dart';
class IPerfPage extends StatefulWidget {
final ServerPrivateInfo spi;
const IPerfPage({super.key, required this.spi});
@override
State<IPerfPage> createState() => _IPerfPageState();
}
class _IPerfPageState extends State<IPerfPage> {
final _hostCtrl = TextEditingController();
final _portCtrl = TextEditingController();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: const CustomAppBar(
title: Text('iperf'),
),
body: _buildBody(),
floatingActionButton: _buildFAB(),
);
}
Widget _buildFAB() {
return FloatingActionButton(
heroTag: 'iperf',
child: const Icon(Icons.send),
onPressed: () {
if (_hostCtrl.text.isEmpty || _portCtrl.text.isEmpty) {
context.showSnackBar(l10n.fieldMustNotEmpty);
return;
}
AppRoute.ssh(
spi: widget.spi,
initCmd: 'iperf -c ${_hostCtrl.text} -p ${_portCtrl.text}',
).go(context);
},
);
}
Widget _buildBody() {
return ListView(
padding: const EdgeInsets.symmetric(horizontal: 17),
children: [
Input(
controller: _hostCtrl,
label: l10n.host,
icon: Icons.computer,
),
Input(
controller: _portCtrl,
label: l10n.port,
type: TextInputType.number,
icon: Icons.numbers,
),
],
);
}
}

View File

@@ -452,7 +452,7 @@ class _ServerDetailPageState extends State<ServerDetailPage>
Widget _buildDiskItem(Disk disk, ServerStatus ss) { Widget _buildDiskItem(Disk disk, ServerStatus ss) {
final (read, write) = ss.diskIO.getSpeed(disk.dev); final (read, write) = ss.diskIO.getSpeed(disk.dev);
final text = () { final text = () {
final use = '${disk.used.kb2Str} / ${disk.size.kb2Str}'; final use = '${l10n.used} ${disk.avail.kb2Str} / ${disk.size.kb2Str}';
if (read == null || write == null) return use; if (read == null || write == null) return use;
return '$use\n${l10n.read} $read | ${l10n.write} $write'; return '$use\n${l10n.read} $read | ${l10n.write} $write';
}(); }();

View File

@@ -206,7 +206,8 @@ class _SettingPageState extends State<SettingPage> {
children: [ children: [
_buildCollapseUI(), _buildCollapseUI(),
_buildServerFuncBtns(), _buildServerFuncBtns(),
_buildSequence(), _buildServerSeq(),
_buildServerDetailCardSeq(),
_buildNetViewType(), _buildNetViewType(),
_buildUpdateInterval(), _buildUpdateInterval(),
_buildMaxRetry(), _buildMaxRetry(),
@@ -985,6 +986,16 @@ class _SettingPageState extends State<SettingPage> {
} }
Widget _buildServerFuncBtns() { Widget _buildServerFuncBtns() {
return ExpandTile(
title: Text(l10n.serverFuncBtns),
children: [
_buildServerFuncBtnsSwitch(),
_buildServerFuncBtnsOrder(),
],
);
}
Widget _buildServerFuncBtnsSwitch() {
return ListTile( return ListTile(
title: Text(l10n.location), title: Text(l10n.location),
subtitle: Text(l10n.moveOutServerFuncBtnsHelp, style: UIs.text13Grey), subtitle: Text(l10n.moveOutServerFuncBtnsHelp, style: UIs.text13Grey),
@@ -992,25 +1003,27 @@ class _SettingPageState extends State<SettingPage> {
); );
} }
Widget _buildSequence() { Widget _buildServerFuncBtnsOrder() {
return ExpandTile( return ListTile(
title: Text(l10n.sequence), title: Text(l10n.sequence),
subtitle: Text( trailing: const Icon(Icons.keyboard_arrow_right),
'${l10n.serverOrder} / ${l10n.serverDetailOrder} ...', onTap: () => AppRoute.serverFuncBtnsOrder().go(context),
style: UIs.textGrey, );
), }
children: [
ListTile( Widget _buildServerSeq() {
return ListTile(
title: Text(l10n.serverOrder), title: Text(l10n.serverOrder),
trailing: const Icon(Icons.keyboard_arrow_right), trailing: const Icon(Icons.keyboard_arrow_right),
onTap: () => AppRoute.serverOrder().go(context), onTap: () => AppRoute.serverOrder().go(context),
), );
ListTile( }
Widget _buildServerDetailCardSeq() {
return ListTile(
title: Text(l10n.serverDetailOrder), title: Text(l10n.serverDetailOrder),
trailing: const Icon(Icons.keyboard_arrow_right), trailing: const Icon(Icons.keyboard_arrow_right),
onTap: () => AppRoute.serverDetailOrder().go(context), onTap: () => AppRoute.serverDetailOrder().go(context),
),
],
); );
} }

View File

@@ -9,7 +9,7 @@ import 'package:toolbox/core/extension/context/snackbar.dart';
import 'package:toolbox/core/utils/platform/auth.dart'; import 'package:toolbox/core/utils/platform/auth.dart';
import 'package:toolbox/data/res/store.dart'; import 'package:toolbox/data/res/store.dart';
import 'package:toolbox/data/res/ui.dart'; import 'package:toolbox/data/res/ui.dart';
import 'package:toolbox/view/page/setting/platform_pub.dart'; import 'package:toolbox/view/page/setting/platform/platform_pub.dart';
import 'package:toolbox/view/widget/appbar.dart'; import 'package:toolbox/view/widget/appbar.dart';
import 'package:toolbox/view/widget/input_field.dart'; import 'package:toolbox/view/widget/input_field.dart';
import 'package:toolbox/view/widget/cardx.dart'; import 'package:toolbox/view/widget/cardx.dart';

View File

@@ -12,7 +12,7 @@ import 'package:toolbox/data/res/logger.dart';
import 'package:toolbox/data/res/misc.dart'; import 'package:toolbox/data/res/misc.dart';
import 'package:toolbox/data/res/store.dart'; import 'package:toolbox/data/res/store.dart';
import 'package:toolbox/data/res/ui.dart'; import 'package:toolbox/data/res/ui.dart';
import 'package:toolbox/view/page/setting/platform_pub.dart'; import 'package:toolbox/view/page/setting/platform/platform_pub.dart';
import 'package:toolbox/view/widget/appbar.dart'; import 'package:toolbox/view/widget/appbar.dart';
import 'package:toolbox/view/widget/future_widget.dart'; import 'package:toolbox/view/widget/future_widget.dart';
import 'package:toolbox/view/widget/cardx.dart'; import 'package:toolbox/view/widget/cardx.dart';

View File

@@ -5,9 +5,9 @@ import 'package:toolbox/core/utils/platform/base.dart';
import 'package:toolbox/data/res/default.dart'; import 'package:toolbox/data/res/default.dart';
import 'package:toolbox/data/res/store.dart'; import 'package:toolbox/data/res/store.dart';
import '../../../core/extension/order.dart'; import '../../../../core/extension/order.dart';
import '../../widget/appbar.dart'; import '../../../widget/appbar.dart';
import '../../widget/cardx.dart'; import '../../../widget/cardx.dart';
class ServerDetailOrderPage extends StatefulWidget { class ServerDetailOrderPage extends StatefulWidget {
const ServerDetailOrderPage({super.key}); const ServerDetailOrderPage({super.key});

View File

@@ -0,0 +1,88 @@
import 'package:flutter/material.dart';
import 'package:toolbox/core/extension/context/locale.dart';
import 'package:toolbox/core/extension/context/snackbar.dart';
import 'package:toolbox/core/utils/platform/base.dart';
import 'package:toolbox/data/model/app/menu/server_func.dart';
import 'package:toolbox/data/res/store.dart';
import '../../../../core/extension/order.dart';
import '../../../widget/appbar.dart';
import '../../../widget/cardx.dart';
class ServerFuncBtnsOrderPage extends StatefulWidget {
const ServerFuncBtnsOrderPage({super.key});
@override
State<ServerFuncBtnsOrderPage> createState() => _ServerDetailOrderPageState();
}
class _ServerDetailOrderPageState extends State<ServerFuncBtnsOrderPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(
title: Text(l10n.serverDetailOrder),
),
body: _buildBody(),
);
}
Widget _buildBody() {
final keys_ = Stores.setting.serverFuncBtns.fetch();
final keys = <ServerFuncBtn>[];
for (final key in keys_) {
keys.add(key);
}
final disabled =
ServerFuncBtn.values.where((e) => !keys.contains(e)).toList();
final allKeys = [...keys, ...disabled];
return ReorderableListView.builder(
padding: const EdgeInsets.all(7),
itemBuilder: (_, idx) {
final key = allKeys[idx];
return CardX(
key: ValueKey(idx),
child: ListTile(
title: Text(key.toStr),
leading: _buildCheckBox(keys, key, idx, idx < keys.length),
trailing: isDesktop ? null : const Icon(Icons.drag_handle),
),
);
},
itemCount: allKeys.length,
onReorder: (o, n) {
if (o >= keys.length || n >= keys.length) {
context.showSnackBar(l10n.disabled);
return;
}
keys.moveByItem(keys, o, n, property: Stores.setting.serverFuncBtns);
setState(() {});
},
);
}
Widget _buildCheckBox(
List<ServerFuncBtn> keys,
ServerFuncBtn key,
int idx,
bool value,
) {
return Checkbox(
value: value,
onChanged: (val) {
if (val == null) return;
if (val) {
if (idx >= keys.length) {
keys.add(key);
} else {
keys.insert(idx - 1, key);
}
} else {
keys.remove(key);
}
Stores.setting.serverFuncBtns.put(keys);
setState(() {});
},
);
}
}

View File

@@ -6,7 +6,7 @@ import 'package:toolbox/data/res/store.dart';
import 'package:toolbox/data/res/ui.dart'; import 'package:toolbox/data/res/ui.dart';
import 'package:toolbox/view/widget/cardx.dart'; import 'package:toolbox/view/widget/cardx.dart';
import '../../widget/appbar.dart'; import '../../../widget/appbar.dart';
class ServerOrderPage extends StatefulWidget { class ServerOrderPage extends StatefulWidget {
const ServerOrderPage({super.key}); const ServerOrderPage({super.key});

View File

@@ -8,7 +8,7 @@ import 'package:toolbox/data/res/store.dart';
import 'package:toolbox/data/res/ui.dart'; import 'package:toolbox/data/res/ui.dart';
import 'package:toolbox/view/widget/cardx.dart'; import 'package:toolbox/view/widget/cardx.dart';
import '../../widget/appbar.dart'; import '../../../widget/appbar.dart';
class SSHVirtKeySettingPage extends StatefulWidget { class SSHVirtKeySettingPage extends StatefulWidget {
const SSHVirtKeySettingPage({super.key}); const SSHVirtKeySettingPage({super.key});

View File

@@ -180,9 +180,8 @@ class _LocalStoragePageState extends State<LocalStoragePage> {
? const Icon(Icons.folder_open) ? const Icon(Icons.folder_open)
: const Icon(Icons.insert_drive_file), : const Icon(Icons.insert_drive_file),
title: Text(fileName), title: Text(fileName),
subtitle: isDir subtitle:
? null isDir ? null : Text(stat.size.bytes2Str, style: UIs.textGrey),
: Text(stat.size.bytes2Str, style: UIs.textGrey),
trailing: Text( trailing: Text(
stat.modified stat.modified
.toString() .toString()

View File

@@ -16,6 +16,7 @@ import 'package:toolbox/data/model/server/dist.dart';
import 'package:toolbox/data/model/server/snippet.dart'; import 'package:toolbox/data/model/server/snippet.dart';
import 'package:toolbox/data/res/path.dart'; import 'package:toolbox/data/res/path.dart';
import 'package:toolbox/data/res/provider.dart'; import 'package:toolbox/data/res/provider.dart';
import 'package:toolbox/data/res/store.dart';
import '../../core/route.dart'; import '../../core/route.dart';
import '../../core/utils/server.dart'; import '../../core/utils/server.dart';
@@ -33,9 +34,9 @@ class ServerFuncBtnsTopRight extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return PopupMenu<ServerTabMenu>( return PopupMenu<ServerFuncBtn>(
items: ServerTabMenu.values items: ServerFuncBtn.values
.map((e) => PopupMenuItem<ServerTabMenu>( .map((e) => PopupMenuItem<ServerFuncBtn>(
value: e, value: e,
child: Row( child: Row(
children: [ children: [
@@ -94,7 +95,7 @@ class ServerFuncBtns extends StatelessWidget {
// ); // );
return Row( return Row(
mainAxisAlignment: MainAxisAlignment.spaceAround, mainAxisAlignment: MainAxisAlignment.spaceAround,
children: ServerTabMenu.values children: Stores.setting.serverFuncBtns.fetch()
.map( .map(
(e) => IconButton( (e) => IconButton(
onPressed: () => _onTapMoreBtns(e, spi, context), onPressed: () => _onTapMoreBtns(e, spi, context),
@@ -109,21 +110,21 @@ class ServerFuncBtns extends StatelessWidget {
} }
void _onTapMoreBtns( void _onTapMoreBtns(
ServerTabMenu value, ServerFuncBtn value,
ServerPrivateInfo spi, ServerPrivateInfo spi,
BuildContext context, BuildContext context,
) async { ) async {
switch (value) { switch (value) {
case ServerTabMenu.pkg: case ServerFuncBtn.pkg:
_onPkg(context, spi); _onPkg(context, spi);
break; break;
case ServerTabMenu.sftp: case ServerFuncBtn.sftp:
AppRoute.sftp(spi: spi).checkGo( AppRoute.sftp(spi: spi).checkGo(
context: context, context: context,
check: () => _checkClient(context, spi.id), check: () => _checkClient(context, spi.id),
); );
break; break;
case ServerTabMenu.snippet: case ServerFuncBtn.snippet:
final snippet = await context.showPickSingleDialog<Snippet>( final snippet = await context.showPickSingleDialog<Snippet>(
items: Pros.snippet.snippets, items: Pros.snippet.snippets,
name: (e) => e.name, name: (e) => e.name,
@@ -135,21 +136,27 @@ void _onTapMoreBtns(
check: () => _checkClient(context, spi.id), check: () => _checkClient(context, spi.id),
); );
break; break;
case ServerTabMenu.container: case ServerFuncBtn.container:
AppRoute.docker(spi: spi).checkGo( AppRoute.docker(spi: spi).checkGo(
context: context, context: context,
check: () => _checkClient(context, spi.id), check: () => _checkClient(context, spi.id),
); );
break; break;
case ServerTabMenu.process: case ServerFuncBtn.process:
AppRoute.process(spi: spi).checkGo( AppRoute.process(spi: spi).checkGo(
context: context, context: context,
check: () => _checkClient(context, spi.id), check: () => _checkClient(context, spi.id),
); );
break; break;
case ServerTabMenu.terminal: case ServerFuncBtn.terminal:
_gotoSSH(spi, context); _gotoSSH(spi, context);
break; break;
case ServerFuncBtn.iperf:
AppRoute.iperf(spi: spi).checkGo(
context: context,
check: () => _checkClient(context, spi.id),
);
break;
} }
} }