opt.: loading dialog

This commit is contained in:
lollipopkit
2024-02-29 18:12:44 +08:00
parent 2137bfbcd0
commit 183fc7f160
13 changed files with 256 additions and 224 deletions

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 = 775; CURRENT_PROJECT_VERSION = 778;
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.775; MARKETING_VERSION = 1.0.778;
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 = 775; CURRENT_PROJECT_VERSION = 778;
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.775; MARKETING_VERSION = 1.0.778;
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 = 775; CURRENT_PROJECT_VERSION = 778;
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.775; MARKETING_VERSION = 1.0.778;
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 = 775; CURRENT_PROJECT_VERSION = 778;
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.775; MARKETING_VERSION = 1.0.778;
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 = 775; CURRENT_PROJECT_VERSION = 778;
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.775; MARKETING_VERSION = 1.0.778;
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 = 775; CURRENT_PROJECT_VERSION = 778;
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.775; MARKETING_VERSION = 1.0.778;
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 = 775; CURRENT_PROJECT_VERSION = 778;
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.775; MARKETING_VERSION = 1.0.778;
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 = 775; CURRENT_PROJECT_VERSION = 778;
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.775; MARKETING_VERSION = 1.0.778;
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 = 775; CURRENT_PROJECT_VERSION = 778;
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.775; MARKETING_VERSION = 1.0.778;
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

@@ -1,3 +1,5 @@
import 'dart:async';
import 'package:choice/choice.dart'; 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';
@@ -14,11 +16,13 @@ extension DialogX on BuildContext {
List<Widget>? actions, List<Widget>? actions,
Widget? title, Widget? title,
bool barrierDismiss = true, bool barrierDismiss = true,
void Function(BuildContext)? onContext,
}) async { }) async {
return await showDialog<T>( return await showDialog<T>(
context: this, context: this,
barrierDismissible: barrierDismiss, barrierDismissible: barrierDismiss,
builder: (_) { builder: (ctx) {
onContext?.call(ctx);
return AlertDialog( return AlertDialog(
title: title, title: title,
content: child, content: child,
@@ -29,11 +33,28 @@ extension DialogX on BuildContext {
); );
} }
void showLoadingDialog({bool barrierDismiss = false}) { Future<T> showLoadingDialog<T>({
required Future<T> Function() fn,
bool barrierDismiss = false,
}) async {
BuildContext? ctx;
showRoundDialog( showRoundDialog(
child: UIs.centerSizedLoading, child: UIs.centerSizedLoading,
barrierDismiss: barrierDismiss, barrierDismiss: barrierDismiss,
onContext: (c) => ctx = c,
); );
try {
return await fn();
} catch (e) {
rethrow;
} finally {
/// Wait for context to be unmounted
await Future.delayed(const Duration(milliseconds: 100));
if (ctx?.mounted == true) {
ctx?.pop();
}
}
} }
Future<String?> showPwdDialog( Future<String?> showPwdDialog(

View File

@@ -306,10 +306,13 @@ class ServerProvider extends ChangeNotifier {
// Write script to server // Write script to server
// by ssh // by ssh
try { try {
await s.client?.runForOutput(ShellFunc.installShellCmd, await s.client?.runForOutput(
ShellFunc.installShellCmd,
action: (session) async { action: (session) async {
session.stdin.add(ShellFunc.allScript.uint8List); session.stdin.add(ShellFunc.allScript.uint8List);
}).string; session.stdin.close();
},
);
} on SSHAuthAbortError catch (e) { } on SSHAuthAbortError catch (e) {
TryLimiter.inc(sid); TryLimiter.inc(sid);
s.status.err = e.toString(); s.status.err = e.toString();
@@ -387,7 +390,7 @@ class ServerProvider extends ChangeNotifier {
if (!systemType.isSegmentsLenMatch(segments.length)) { if (!systemType.isSegmentsLenMatch(segments.length)) {
TryLimiter.inc(sid); TryLimiter.inc(sid);
s.status.err = s.status.err =
'Segments not match: expect ${systemType.segmentsLen}, got ${segments.length}'; 'Segments not match: expect ${systemType.segmentsLen}, got ${segments.length}, raw:\n\n$raw';
_setServerState(s, ServerState.failed); _setServerState(s, ServerState.failed);
return; return;
} }

View File

@@ -2,9 +2,9 @@
class BuildData { class BuildData {
static const String name = "ServerBox"; static const String name = "ServerBox";
static const int build = 775; static const int build = 778;
static const String engine = "3.19.0"; static const String engine = "3.19.1";
static const String buildAt = "2024-02-23 09:28:28"; static const String buildAt = "2024-02-26 16:30:57";
static const int modifications = 2; static const int modifications = 6;
static const int script = 38; static const int script = 40;
} }

View File

@@ -231,9 +231,9 @@ class BackupPage extends StatelessWidget {
} }
try { try {
context.showLoadingDialog(); final backup = await context.showLoadingDialog(
final backup = fn: () => Computer.shared.start(Backup.fromJsonString, text.trim()),
await Computer.shared.start(Backup.fromJsonString, text.trim()); );
if (backupFormatVersion != backup.version) { if (backupFormatVersion != backup.version) {
context.showSnackBar(l10n.backupVersionNotMatch); context.showSnackBar(l10n.backupVersionNotMatch);
return; return;
@@ -261,8 +261,6 @@ class BackupPage extends StatelessWidget {
} catch (e, trace) { } catch (e, trace) {
Loggers.app.warning('Import backup failed', e, trace); Loggers.app.warning('Import backup failed', e, trace);
context.showSnackBar(e.toString()); context.showSnackBar(e.toString());
} finally {
context.pop();
} }
} }
@@ -388,9 +386,10 @@ class BackupPage extends StatelessWidget {
} }
try { try {
context.showLoadingDialog(); final backup = await context.showLoadingDialog(
final backup = fn: () => Computer.shared.start(Backup.fromJsonString, text.trim()),
await Computer.shared.start(Backup.fromJsonString, text.trim()); );
if (backupFormatVersion != backup.version) { if (backupFormatVersion != backup.version) {
context.showSnackBar(l10n.backupVersionNotMatch); context.showSnackBar(l10n.backupVersionNotMatch);
return; return;
@@ -418,8 +417,6 @@ class BackupPage extends StatelessWidget {
} catch (e, trace) { } catch (e, trace) {
Loggers.app.warning('Import backup failed', e, trace); Loggers.app.warning('Import backup failed', e, trace);
context.showSnackBar(e.toString()); context.showSnackBar(e.toString());
} finally {
context.pop();
} }
} }
} }

View File

@@ -72,11 +72,8 @@ class _ContainerPageState extends State<ContainerPage> {
title: TwoLineText(up: l10n.container, down: widget.spi.name), title: TwoLineText(up: l10n.container, down: widget.spi.name),
actions: [ actions: [
IconButton( IconButton(
onPressed: () async { onPressed: () =>
context.showLoadingDialog(); context.showLoadingDialog(fn: () => _container.refresh()),
await _container.refresh();
context.pop();
},
icon: const Icon(Icons.refresh), icon: const Icon(Icons.refresh),
) )
], ],
@@ -393,9 +390,10 @@ class _ContainerPageState extends State<ContainerPage> {
TextButton( TextButton(
onPressed: () async { onPressed: () async {
context.pop(); context.pop();
context.showLoadingDialog();
final result = await _container.run(cmd); final result = await context.showLoadingDialog(
context.pop(); fn: () => _container.run(cmd),
);
if (result != null) { if (result != null) {
context.showSnackBar(result.message ?? l10n.unknownError); context.showSnackBar(result.message ?? l10n.unknownError);
} }
@@ -506,9 +504,10 @@ class _ContainerPageState extends State<ContainerPage> {
TextButton( TextButton(
onPressed: () async { onPressed: () async {
context.pop(); context.pop();
context.showLoadingDialog();
final result = await _container.delete(id, force); final result = await context.showLoadingDialog(
context.pop(); fn: () => _container.delete(id, force),
);
if (result != null) { if (result != null) {
context.showRoundDialog( context.showRoundDialog(
title: Text(l10n.error), title: Text(l10n.error),
@@ -522,9 +521,9 @@ class _ContainerPageState extends State<ContainerPage> {
); );
break; break;
case ContainerMenu.start: case ContainerMenu.start:
context.showLoadingDialog(); final result = await context.showLoadingDialog(
final result = await _container.start(id); fn: () => _container.start(id),
context.pop(); );
if (result != null) { if (result != null) {
context.showRoundDialog( context.showRoundDialog(
title: Text(l10n.error), title: Text(l10n.error),
@@ -533,9 +532,9 @@ class _ContainerPageState extends State<ContainerPage> {
} }
break; break;
case ContainerMenu.stop: case ContainerMenu.stop:
context.showLoadingDialog(); final result = await context.showLoadingDialog(
final result = await _container.stop(id); fn: () => _container.stop(id),
context.pop(); );
if (result != null) { if (result != null) {
context.showRoundDialog( context.showRoundDialog(
title: Text(l10n.error), title: Text(l10n.error),
@@ -544,9 +543,9 @@ class _ContainerPageState extends State<ContainerPage> {
} }
break; break;
case ContainerMenu.restart: case ContainerMenu.restart:
context.showLoadingDialog(); final result = await context.showLoadingDialog(
final result = await _container.restart(id); fn: () => _container.restart(id),
context.pop(); );
if (result != null) { if (result != null) {
context.showRoundDialog( context.showRoundDialog(
title: Text(l10n.error), title: Text(l10n.error),

View File

@@ -148,9 +148,10 @@ class _EditorPageState extends State<EditorPage> {
// If path is not null, then it's a file editor // If path is not null, then it's a file editor
// save the text and return true to pop the page // save the text and return true to pop the page
if (widget.path != null) { if (widget.path != null) {
context.showLoadingDialog(); await context.showLoadingDialog(
await File(widget.path!).writeAsString(_controller.text); fn: () => File(widget.path!).writeAsString(_controller.text),
context.pop(); );
context.pop(true); context.pop(true);
return; return;
} }

View File

@@ -108,9 +108,12 @@ class _ServerEditPageState extends State<ServerEditPage> {
PreferredSizeWidget _buildAppBar() { PreferredSizeWidget _buildAppBar() {
return CustomAppBar( return CustomAppBar(
title: Text(l10n.edit, style: UIs.text18), title: Text(l10n.edit, style: UIs.text18),
actions: widget.spi != null actions: widget.spi != null ? [_buildDelBtn()] : null,
? [ );
IconButton( }
Widget _buildDelBtn() {
return IconButton(
onPressed: () { onPressed: () {
var delScripts = false; var delScripts = false;
context.showRoundDialog( context.showRoundDialog(
@@ -143,11 +146,12 @@ class _ServerEditPageState extends State<ServerEditPage> {
onPressed: () async { onPressed: () async {
context.pop(); context.pop();
if (delScripts) { if (delScripts) {
context.showLoadingDialog(); await context.showLoadingDialog(
const cmd = fn: () async {
'rm ${ShellFunc.srvBoxDir}/mobile_v*.sh'; const cmd = 'rm ${ShellFunc.srvBoxDir}/mobile_v*.sh';
await widget.spi?.server?.client?.run(cmd); return widget.spi?.server?.client?.run(cmd);
context.pop(); },
);
} }
Pros.server.delServer(widget.spi!.id); Pros.server.delServer(widget.spi!.id);
context.pop(true); context.pop(true);
@@ -158,9 +162,6 @@ class _ServerEditPageState extends State<ServerEditPage> {
); );
}, },
icon: const Icon(Icons.delete), icon: const Icon(Icons.delete),
),
]
: null,
); );
} }

View File

@@ -1161,6 +1161,7 @@ class _SettingPageState extends State<SettingPage> {
_setting.preferTemperatureDevs.put(list); _setting.preferTemperatureDevs.put(list);
context.pop(); context.pop();
} }
return ListTile( return ListTile(
title: Text(l10n.preferTemperatureDeviceList), title: Text(l10n.preferTemperatureDeviceList),
subtitle: Text(l10n.preferTemperatureDeviceListTip, style: UIs.textGrey), subtitle: Text(l10n.preferTemperatureDeviceListTip, style: UIs.textGrey),

View File

@@ -406,9 +406,7 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
SftpReqType.download, SftpReqType.download,
); );
Pros.sftp.add(req, completer: completer); Pros.sftp.add(req, completer: completer);
context.showLoadingDialog(); await context.showLoadingDialog(fn: () => completer.future);
await completer.future;
context.pop();
final result = await AppRoute.editor(path: localPath).go<bool>(context); final result = await AppRoute.editor(path: localPath).go<bool>(context);
if (result != null && result) { if (result != null && result) {
@@ -471,9 +469,9 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
TextButton( TextButton(
onPressed: () async { onPressed: () async {
context.pop(); context.pop();
context.showLoadingDialog();
final remotePath = _getRemotePath(file);
try { try {
await context.showLoadingDialog(fn: () async {
final remotePath = _getRemotePath(file);
if (useRmr) { if (useRmr) {
await _client!.run('rm -r "$remotePath"'); await _client!.run('rm -r "$remotePath"');
} else if (file.attr.isDirectory) { } else if (file.attr.isDirectory) {
@@ -481,9 +479,8 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
} else { } else {
await _status.client!.remove(remotePath); await _status.client!.remove(remotePath);
} }
context.pop(); });
} catch (e) { } catch (e) {
context.pop();
context.showRoundDialog( context.showRoundDialog(
title: Text(l10n.error), title: Text(l10n.error),
child: Text(e.toString()), child: Text(e.toString()),
@@ -574,9 +571,8 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
} }
context.pop(); context.pop();
final path = '${_status.path!.path}/${textController.text}'; final path = '${_status.path!.path}/${textController.text}';
context.showLoadingDialog(); await context.showLoadingDialog(
await _client!.run('touch "$path"'); fn: () => _client!.run('touch "$path"'));
context.pop();
_listDir(); _listDir();
}, },
child: Text(l10n.ok, style: UIs.textRed), child: Text(l10n.ok, style: UIs.textRed),
@@ -640,9 +636,7 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
); );
return; return;
} }
context.showLoadingDialog(); await context.showLoadingDialog(fn: () async => _client?.run(cmd));
await _client?.run(cmd);
context.pop();
_listDir(); _listDir();
} }
@@ -657,12 +651,9 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
/// Only return true if the path is changed /// Only return true if the path is changed
Future<bool> _listDir() async { Future<bool> _listDir() async {
// Allow dismiss, because may this op will take a long time return context.showLoadingDialog(
context.showLoadingDialog(barrierDismiss: true); fn: () async {
if (_status.client == null) { _status.client ??= await _client?.sftp();
final sftpc = await _client?.sftp();
_status.client = sftpc;
}
try { try {
final listPath = _status.path?.path ?? '/'; final listPath = _status.path?.path ?? '/';
final fs = await _status.client?.listdir(listPath); final fs = await _status.client?.listdir(listPath);
@@ -689,7 +680,6 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
setState(() { setState(() {
_status.files = fs; _status.files = fs;
}); });
context.pop();
// Only update history when success // Only update history when success
if (Stores.setting.sftpOpenLastPath.fetch()) { if (Stores.setting.sftpOpenLastPath.fetch()) {
@@ -700,7 +690,6 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
} }
return false; return false;
} catch (e, trace) { } catch (e, trace) {
context.pop();
Loggers.app.warning('List dir failed', e, trace); Loggers.app.warning('List dir failed', e, trace);
await _backward(); await _backward();
Future.delayed( Future.delayed(
@@ -718,6 +707,9 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
); );
return false; return false;
} }
},
barrierDismiss: true,
);
} }
Future<void> _backward() async { Future<void> _backward() async {

View File

@@ -223,7 +223,8 @@ bool _checkClient(BuildContext context, String id) {
Future<void> _onPkg(BuildContext context, ServerPrivateInfo spi) async { Future<void> _onPkg(BuildContext context, ServerPrivateInfo spi) async {
final server = spi.server; final server = spi.server;
if (server == null) { final client = server?.client;
if (server == null || client == null) {
context.showSnackBar(l10n.noClient); context.showSnackBar(l10n.noClient);
return; return;
} }
@@ -232,42 +233,43 @@ Future<void> _onPkg(BuildContext context, ServerPrivateInfo spi) async {
context.showSnackBar(l10n.noResult); context.showSnackBar(l10n.noResult);
return; return;
} }
final pkg = PkgManager.fromDist(sys.dist); final pkg = PkgManager.fromDist(sys.dist);
if (pkg == null) {
context.showSnackBar('Unsupported dist: $sys');
return;
}
// Update pkg list // Update pkg list
context.showLoadingDialog(); await context.showLoadingDialog(
final updateCmd = pkg?.update; fn: () async {
final updateCmd = pkg.update;
if (updateCmd != null) { if (updateCmd != null) {
await server.client!.execWithPwd( await client.execWithPwd(updateCmd, context: context);
updateCmd,
context: context,
);
} }
context.pop(); },
barrierDismiss: true,
);
final listCmd = pkg?.listUpdate; final listCmd = pkg.listUpdate;
if (listCmd == null) { if (listCmd == null) {
context.showSnackBar('Unsupported dist: $sys'); context.showSnackBar('Unsupported dist: $sys');
return; return;
} }
// Get upgrade list // Get upgrade list
context.showLoadingDialog(); final result = await context.showLoadingDialog(fn: () async {
final result = await server.client?.run(listCmd).string; return await client.run(listCmd).string;
context.pop(); });
if (result == null) { final list = pkg.updateListRemoveUnused(result.split('\n'));
context.showSnackBar(l10n.noResult); final upgradeable = list.map((e) => UpgradePkgInfo(e, pkg)).toList();
return; if (upgradeable.isEmpty) {
}
final list = pkg?.updateListRemoveUnused(result.split('\n'));
final upgradeable = list?.map((e) => UpgradePkgInfo(e, pkg)).toList();
if (upgradeable == null || upgradeable.isEmpty) {
context.showSnackBar(l10n.noUpdateAvailable); context.showSnackBar(l10n.noUpdateAvailable);
return; return;
} }
final args = upgradeable.map((e) => e.package).join(' '); final args = upgradeable.map((e) => e.package).join(' ');
final isSU = server.spi.user == 'root'; final isSU = server.spi.user == 'root';
final upgradeCmd = isSU ? pkg?.upgrade(args) : 'sudo ${pkg?.upgrade(args)}'; final upgradeCmd = isSU ? pkg.upgrade(args) : 'sudo ${pkg.upgrade(args)}';
// Confirm upgrade // Confirm upgrade
final gotoUpgrade = await context.showRoundDialog<bool>( final gotoUpgrade = await context.showRoundDialog<bool>(

View File

@@ -439,7 +439,7 @@
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 775; CURRENT_PROJECT_VERSION = 778;
DEVELOPMENT_TEAM = BA88US33G6; DEVELOPMENT_TEAM = BA88US33G6;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "Server Box"; INFOPLIST_KEY_CFBundleDisplayName = "Server Box";
@@ -449,7 +449,7 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 10.15; MACOSX_DEPLOYMENT_TARGET = 10.15;
MARKETING_VERSION = 1.0.775; MARKETING_VERSION = 1.0.778;
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
PRODUCT_NAME = "Server Box"; PRODUCT_NAME = "Server Box";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
@@ -574,7 +574,7 @@
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 775; CURRENT_PROJECT_VERSION = 778;
DEVELOPMENT_TEAM = BA88US33G6; DEVELOPMENT_TEAM = BA88US33G6;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "Server Box"; INFOPLIST_KEY_CFBundleDisplayName = "Server Box";
@@ -584,7 +584,7 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 10.15; MACOSX_DEPLOYMENT_TARGET = 10.15;
MARKETING_VERSION = 1.0.775; MARKETING_VERSION = 1.0.778;
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
PRODUCT_NAME = "Server Box"; PRODUCT_NAME = "Server Box";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
@@ -604,7 +604,7 @@
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "3rd Party Mac Developer Application"; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "3rd Party Mac Developer Application";
CODE_SIGN_STYLE = Manual; CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 775; CURRENT_PROJECT_VERSION = 778;
DEVELOPMENT_TEAM = ""; DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=macosx*]" = BA88US33G6; "DEVELOPMENT_TEAM[sdk=macosx*]" = BA88US33G6;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
@@ -615,7 +615,7 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 10.15; MACOSX_DEPLOYMENT_TARGET = 10.15;
MARKETING_VERSION = 1.0.775; MARKETING_VERSION = 1.0.778;
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
PRODUCT_NAME = "Server Box"; PRODUCT_NAME = "Server Box";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";

View File

@@ -1,4 +1,3 @@
import 'package:flutter/foundation.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:toolbox/data/model/server/nvdia.dart'; import 'package:toolbox/data/model/server/nvdia.dart';
@@ -841,8 +840,24 @@ const _raw = '''
void main() { void main() {
test('nvdia-smi', () { test('nvdia-smi', () {
if (kDebugMode) { final items = NvidiaSmi.fromXml(_raw);
print(NvidiaSmi.fromXml(_raw).firstOrNull?.memory.processes); expect(items.length, 1);
} final item = items[0];
expect(item.name, 'NVIDIA GeForce RTX 3080 Ti');
expect(item.temp, 34);
expect(item.power, '24.55 W / 350.00 W');
expect(item.memory.total, 12288);
expect(item.memory.used, 352);
expect(item.memory.unit, 'MiB');
final processes = item.memory.processes;
expect(processes.length, 3);
expect(processes[0].pid, 1575);
expect(processes[0].name, '/usr/lib/xorg/Xorg');
expect(processes[0].memory, 220);
expect(processes[1].pid, 1933);
expect(processes[1].name, '/usr/bin/gnome-shell');
expect(processes[1].memory, 34);
expect(processes[2].pid, 16484);
expect(processes[2].memory, 76);
}); });
} }