From c512a6a27479028bd4de6fec74b9c765dd81a466 Mon Sep 17 00:00:00 2001 From: lollipopkit Date: Wed, 9 Aug 2023 23:58:38 +0800 Subject: [PATCH] opt. --- .dart_tool/flutter_gen/gen_l10n/l10n.dart | 6 + .dart_tool/flutter_gen/gen_l10n/l10n_de.dart | 3 + .dart_tool/flutter_gen/gen_l10n/l10n_en.dart | 3 + .dart_tool/flutter_gen/gen_l10n/l10n_id.dart | 3 + .dart_tool/flutter_gen/gen_l10n/l10n_zh.dart | 6 + ios/Runner.xcodeproj/project.pbxproj | 24 ++-- lib/core/provider_base.dart | 31 ----- lib/data/model/server/server.dart | 19 ++- lib/data/model/server/try_limiter.dart | 7 +- lib/data/provider/app.dart | 4 +- lib/data/provider/pkg.dart | 4 +- lib/data/provider/private_key.dart | 4 +- lib/data/provider/server.dart | 134 +++++++++++-------- lib/data/provider/sftp.dart | 4 +- lib/data/provider/snippet.dart | 4 +- lib/data/res/build_data.dart | 6 +- lib/l10n/app_de.arb | 1 + lib/l10n/app_en.arb | 1 + lib/l10n/app_id.arb | 1 + lib/l10n/app_zh.arb | 1 + lib/l10n/app_zh_tw.arb | 1 + lib/main.dart | 15 ++- lib/view/page/convert.dart | 7 + lib/view/page/docker.dart | 3 +- lib/view/page/full_screen.dart | 1 + lib/view/page/home.dart | 1 + lib/view/page/ping.dart | 7 + lib/view/page/pkg.dart | 9 +- lib/view/page/private_key/edit.dart | 11 ++ lib/view/page/process.dart | 4 - lib/view/page/server/edit.dart | 16 +++ lib/view/page/server/tab.dart | 18 +-- lib/view/page/snippet/edit.dart | 8 ++ lib/view/page/ssh/term.dart | 18 ++- lib/view/page/storage/sftp.dart | 6 +- macos/Runner.xcodeproj/project.pbxproj | 12 +- 36 files changed, 243 insertions(+), 160 deletions(-) delete mode 100644 lib/core/provider_base.dart diff --git a/.dart_tool/flutter_gen/gen_l10n/l10n.dart b/.dart_tool/flutter_gen/gen_l10n/l10n.dart index 646bc292..af58ffce 100644 --- a/.dart_tool/flutter_gen/gen_l10n/l10n.dart +++ b/.dart_tool/flutter_gen/gen_l10n/l10n.dart @@ -266,6 +266,12 @@ abstract class S { /// **'Connection'** String get conn; + /// No description provided for @connected. + /// + /// In en, this message translates to: + /// **'Connected'** + String get connected; + /// No description provided for @containerName. /// /// In en, this message translates to: diff --git a/.dart_tool/flutter_gen/gen_l10n/l10n_de.dart b/.dart_tool/flutter_gen/gen_l10n/l10n_de.dart index 3242f80e..1918124c 100644 --- a/.dart_tool/flutter_gen/gen_l10n/l10n_de.dart +++ b/.dart_tool/flutter_gen/gen_l10n/l10n_de.dart @@ -88,6 +88,9 @@ class SDe extends S { @override String get conn => 'Verbindung'; + @override + String get connected => 'in Verbindung gebracht'; + @override String get containerName => 'Container Name'; diff --git a/.dart_tool/flutter_gen/gen_l10n/l10n_en.dart b/.dart_tool/flutter_gen/gen_l10n/l10n_en.dart index 13738a03..9084f24d 100644 --- a/.dart_tool/flutter_gen/gen_l10n/l10n_en.dart +++ b/.dart_tool/flutter_gen/gen_l10n/l10n_en.dart @@ -88,6 +88,9 @@ class SEn extends S { @override String get conn => 'Connection'; + @override + String get connected => 'Connected'; + @override String get containerName => 'Container name'; diff --git a/.dart_tool/flutter_gen/gen_l10n/l10n_id.dart b/.dart_tool/flutter_gen/gen_l10n/l10n_id.dart index 8ec65e24..5465d7d6 100644 --- a/.dart_tool/flutter_gen/gen_l10n/l10n_id.dart +++ b/.dart_tool/flutter_gen/gen_l10n/l10n_id.dart @@ -88,6 +88,9 @@ class SId extends S { @override String get conn => 'Koneksi'; + @override + String get connected => 'Terhubung'; + @override String get containerName => 'Nama kontainer'; diff --git a/.dart_tool/flutter_gen/gen_l10n/l10n_zh.dart b/.dart_tool/flutter_gen/gen_l10n/l10n_zh.dart index d1d8846d..6cf5e9eb 100644 --- a/.dart_tool/flutter_gen/gen_l10n/l10n_zh.dart +++ b/.dart_tool/flutter_gen/gen_l10n/l10n_zh.dart @@ -88,6 +88,9 @@ class SZh extends S { @override String get conn => '连接'; + @override + String get connected => '已连接'; + @override String get containerName => '容器名'; @@ -784,6 +787,9 @@ class SZhTw extends SZh { @override String get conn => '連接'; + @override + String get connected => '已連接'; + @override String get containerName => '容器名稱'; diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 9b24a83a..532676f3 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -470,7 +470,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 454; + CURRENT_PROJECT_VERSION = 457; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_BITCODE = NO; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; @@ -478,7 +478,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.454; + MARKETING_VERSION = 1.0.457; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -602,7 +602,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 454; + CURRENT_PROJECT_VERSION = 457; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_BITCODE = NO; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; @@ -610,7 +610,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.454; + MARKETING_VERSION = 1.0.457; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -628,7 +628,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 454; + CURRENT_PROJECT_VERSION = 457; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_BITCODE = NO; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; @@ -636,7 +636,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.454; + MARKETING_VERSION = 1.0.457; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -657,7 +657,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 454; + CURRENT_PROJECT_VERSION = 457; DEVELOPMENT_TEAM = BA88US33G6; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; @@ -670,7 +670,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.0.454; + MARKETING_VERSION = 1.0.457; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget; @@ -696,7 +696,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 454; + CURRENT_PROJECT_VERSION = 457; DEVELOPMENT_TEAM = BA88US33G6; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; @@ -709,7 +709,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.0.454; + MARKETING_VERSION = 1.0.457; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -732,7 +732,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 454; + CURRENT_PROJECT_VERSION = 457; DEVELOPMENT_TEAM = BA88US33G6; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; @@ -745,7 +745,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.0.454; + MARKETING_VERSION = 1.0.457; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget; PRODUCT_NAME = "$(TARGET_NAME)"; diff --git a/lib/core/provider_base.dart b/lib/core/provider_base.dart deleted file mode 100644 index 974dbabe..00000000 --- a/lib/core/provider_base.dart +++ /dev/null @@ -1,31 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/widgets.dart'; - -class ProviderBase with ChangeNotifier { - void setState(void Function() callback) { - callback(); - notifyListeners(); - } -} - -class BusyProvider extends ProviderBase { - bool _isBusy = false; - bool get isBusy => _isBusy; - - setBusyState([bool isBusy = true]) { - _isBusy = isBusy; - notifyListeners(); - } - - FutureOr busyRun(FutureOr Function() func) async { - setBusyState(true); - try { - return await Future.sync(func); - } catch (e) { - rethrow; - } finally { - setBusyState(false); - } - } -} diff --git a/lib/data/model/server/server.dart b/lib/data/model/server/server.dart index cb7df5dc..e6f5740a 100644 --- a/lib/data/model/server/server.dart +++ b/lib/data/model/server/server.dart @@ -12,11 +12,22 @@ class Server { } enum ServerState { + failed, disconnected, connecting, - connected, - failed; - bool get shouldConnect => - this == ServerState.disconnected || this == ServerState.failed; + /// Connected to server + connected, + + /// Status parsing + loading, + + /// Status parsing finished + finished; + + bool get shouldConnect => this < ServerState.connecting; + + bool get canViewDetails => this == ServerState.finished; + + operator <(ServerState other) => index < other.index; } diff --git a/lib/data/model/server/try_limiter.dart b/lib/data/model/server/try_limiter.dart index 32b39c18..6b477879 100644 --- a/lib/data/model/server/try_limiter.dart +++ b/lib/data/model/server/try_limiter.dart @@ -4,7 +4,7 @@ import '../../store/setting.dart'; class TryLimiter { final Map _triedTimes = {}; - bool shouldTry(String id) { + bool canTry(String id) { final maxCount = locator().maxRetryCount.fetch()!; if (maxCount <= 0) { return true; @@ -13,10 +13,13 @@ class TryLimiter { if (times >= maxCount) { return false; } - _triedTimes[id] = times + 1; return true; } + void inc(String sid) { + _triedTimes[sid] = (_triedTimes[sid] ?? 0) + 1; + } + void reset(String id) { _triedTimes[id] = 0; } diff --git a/lib/data/provider/app.dart b/lib/data/provider/app.dart index 7874fda2..95a3d763 100644 --- a/lib/data/provider/app.dart +++ b/lib/data/provider/app.dart @@ -1,6 +1,6 @@ -import 'package:toolbox/core/provider_base.dart'; +import 'package:flutter/material.dart'; -class AppProvider extends BusyProvider { +class AppProvider extends ChangeNotifier { int? _newestBuild; int? get newestBuild => _newestBuild; diff --git a/lib/data/provider/pkg.dart b/lib/data/provider/pkg.dart index c48d08c8..a19e816b 100644 --- a/lib/data/provider/pkg.dart +++ b/lib/data/provider/pkg.dart @@ -2,16 +2,16 @@ import 'dart:async'; import 'dart:typed_data'; import 'package:dartssh2/dartssh2.dart'; +import 'package:flutter/material.dart'; import 'package:logging/logging.dart'; import 'package:toolbox/core/extension/ssh_client.dart'; import 'package:toolbox/core/extension/stringx.dart'; import 'package:toolbox/core/extension/uint8list.dart'; -import 'package:toolbox/core/provider_base.dart'; import 'package:toolbox/data/model/pkg/manager.dart'; import 'package:toolbox/data/model/pkg/upgrade_info.dart'; import 'package:toolbox/data/model/server/dist.dart'; -class PkgProvider extends BusyProvider { +class PkgProvider extends ChangeNotifier { final logger = Logger('PKG'); SSHClient? client; diff --git a/lib/data/provider/private_key.dart b/lib/data/provider/private_key.dart index 17c62e60..a12011f6 100644 --- a/lib/data/provider/private_key.dart +++ b/lib/data/provider/private_key.dart @@ -1,9 +1,9 @@ -import 'package:toolbox/core/provider_base.dart'; +import 'package:flutter/material.dart'; import 'package:toolbox/data/model/server/private_key_info.dart'; import 'package:toolbox/data/store/private_key.dart'; import 'package:toolbox/locator.dart'; -class PrivateKeyProvider extends BusyProvider { +class PrivateKeyProvider extends ChangeNotifier { List get pkis => _pkis; final _store = locator(); late List _pkis; diff --git a/lib/data/provider/server.dart b/lib/data/provider/server.dart index 4a612f72..d767786e 100644 --- a/lib/data/provider/server.dart +++ b/lib/data/provider/server.dart @@ -6,7 +6,6 @@ import 'package:toolbox/data/model/app/shell_func.dart'; import '../../core/extension/order.dart'; import '../../core/extension/uint8list.dart'; -import '../../core/provider_base.dart'; import '../../core/utils/server.dart'; import '../../locator.dart'; import '../model/server/server.dart'; @@ -21,7 +20,7 @@ import '../store/setting.dart'; typedef ServersMap = Map; -class ServerProvider extends BusyProvider { +class ServerProvider extends ChangeNotifier { final ServersMap _servers = {}; ServersMap get servers => _servers; final Order _serverOrder = []; @@ -39,7 +38,6 @@ class ServerProvider extends BusyProvider { final _settingStore = locator(); Future loadLocalData() async { - setBusyState(true); final spis = _serverStore.fetch(); for (final spi in spis) { _servers[spi.id] = genServer(spi); @@ -56,7 +54,6 @@ class ServerProvider extends BusyProvider { } _settingStore.serverOrder.put(_serverOrder); _updateTags(); - setBusyState(false); notifyListeners(); } @@ -204,77 +201,96 @@ class ServerProvider extends BusyProvider { } } + void _setServerState(Server s, ServerState ss) { + s.state = ss; + notifyListeners(); + } + Future _getData(ServerPrivateInfo spi) async { final sid = spi.id; final s = _servers[sid]; + if (s == null) return; - var raw = ''; - var segments = []; - - try { - final state = s.state; - if (state.shouldConnect) { - if (!_limiter.shouldTry(sid)) { - s.state = ServerState.failed; - notifyListeners(); - return; - } - s.state = ServerState.connecting; - notifyListeners(); - - // try to connect - final time1 = DateTime.now(); - s.client = await genClient(spi); - final time2 = DateTime.now(); - final spentTime = time2.difference(time1).inMilliseconds; - _logger.info('Connected to $sid in $spentTime ms.'); - - // after connected - s.state = ServerState.connected; - notifyListeners(); - // write script to server - final writeResult = await s.client!.run(installShellCmd).string; - - // if write failed - if (writeResult.isNotEmpty) { - throw Exception(writeResult); - } - // reset try times if connected successfully - _limiter.reset(sid); + if (!_limiter.canTry(sid)) { + if (s.state != ServerState.failed) { + _setServerState(s, ServerState.failed); } + return; + } - if (s.client == null) return; - // run script to get server status - raw = await s.client!.run(AppShellFuncType.status.exec).string; - segments = raw.split(seperator).map((e) => e.trim()).toList(); - if (raw.isEmpty || segments.length != StatusCmdType.values.length) { - s.state = ServerState.failed; - if (s.status.failedInfo?.isEmpty ?? true) { - s.status.failedInfo = 'Seperate segments failed, raw:\n$raw'; - } + if (s.state.shouldConnect) { + _setServerState(s, ServerState.connecting); + + final time1 = DateTime.now(); + + try { + s.client = await genClient(spi); + } catch (e) { + _limiter.inc(sid); + s.status.failedInfo = e.toString(); + _setServerState(s, ServerState.failed); + _logger.warning('Connect to $sid failed', e); return; } - } catch (e) { - s.state = ServerState.failed; - s.status.failedInfo = e.toString(); - rethrow; - } finally { - notifyListeners(); + + final time2 = DateTime.now(); + final spentTime = time2.difference(time1).inMilliseconds; + _logger.info('Connected to $sid in $spentTime ms.'); + + _setServerState(s, ServerState.connected); + + try { + final writeResult = await s.client?.run(installShellCmd).string; + if (writeResult == null || writeResult.isNotEmpty) { + _limiter.inc(sid); + s.status.failedInfo = writeResult; + _setServerState(s, ServerState.failed); + return; + } + } catch (e) { + _limiter.inc(sid); + s.status.failedInfo = e.toString(); + _setServerState(s, ServerState.failed); + _logger.warning('Write script to $sid failed', e); + return; + } + } + + if (s.client == null) return; + + if (s.state != ServerState.finished) { + _setServerState(s, ServerState.loading); + } + + final raw = await s.client?.run(AppShellFuncType.status.exec).string; + final segments = raw?.split(seperator).map((e) => e.trim()).toList(); + if (raw == null || + raw.isEmpty || + segments == null || + segments.length != StatusCmdType.values.length) { + _limiter.inc(sid); + s.status.failedInfo = 'Seperate segments failed, raw:\n$raw'; + _setServerState(s, ServerState.failed); + return; } try { final req = ServerStatusUpdateReq(s.status, segments); s.status = await compute(getStatus, req); - // Comment for debug - // s.status = await getStatus(req); - } catch (e) { - s.state = ServerState.failed; + } catch (e, trace) { + _limiter.inc(sid); s.status.failedInfo = 'Parse failed: $e\n\n$raw'; - rethrow; - } finally { - notifyListeners(); + _setServerState(s, ServerState.failed); + _logger.warning('Parse failed', e, trace); + return; } + + if (s.state != ServerState.finished) { + _setServerState(s, ServerState.finished); + } + // reset try times only after prepared successfully + _limiter.reset(sid); } Future runSnippets(String id, List snippets) async { diff --git a/lib/data/provider/sftp.dart b/lib/data/provider/sftp.dart index 3c603681..e3fed7a6 100644 --- a/lib/data/provider/sftp.dart +++ b/lib/data/provider/sftp.dart @@ -1,10 +1,10 @@ import 'dart:async'; -import 'package:toolbox/core/provider_base.dart'; +import 'package:flutter/material.dart'; import '../model/sftp/req.dart'; -class SftpProvider extends ProviderBase { +class SftpProvider extends ChangeNotifier { final List _status = []; List get status => _status; diff --git a/lib/data/provider/snippet.dart b/lib/data/provider/snippet.dart index 8240713d..921c407f 100644 --- a/lib/data/provider/snippet.dart +++ b/lib/data/provider/snippet.dart @@ -1,6 +1,6 @@ import 'dart:convert'; -import 'package:toolbox/core/provider_base.dart'; +import 'package:flutter/material.dart'; import 'package:toolbox/data/model/server/snippet.dart'; import 'package:toolbox/data/store/snippet.dart'; import 'package:toolbox/locator.dart'; @@ -8,7 +8,7 @@ import 'package:toolbox/locator.dart'; import '../../core/extension/order.dart'; import '../store/setting.dart'; -class SnippetProvider extends BusyProvider { +class SnippetProvider extends ChangeNotifier { late Order _snippets; Order get snippets => _snippets; diff --git a/lib/data/res/build_data.dart b/lib/data/res/build_data.dart index 5e86b79c..06e722e1 100644 --- a/lib/data/res/build_data.dart +++ b/lib/data/res/build_data.dart @@ -2,8 +2,8 @@ class BuildData { static const String name = "ServerBox"; - static const int build = 454; + static const int build = 457; static const String engine = "3.10.6"; - static const String buildAt = "2023-08-08 17:50:11.695696"; - static const int modifications = 3; + static const String buildAt = "2023-08-09 23:52:33.375014"; + static const int modifications = 30; } diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 9c0adb21..48920664 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -28,6 +28,7 @@ "close": "Schließen", "cmd": "Command", "conn": "Verbindung", + "connected": "in Verbindung gebracht", "containerName": "Container Name", "containerStatus": "Container Status", "convert": "Konvertieren", diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index b68df9a1..9ab9683f 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -28,6 +28,7 @@ "close": "Close", "cmd": "Command", "conn": "Connection", + "connected": "Connected", "containerName": "Container name", "containerStatus": "Container status", "convert": "Convert", diff --git a/lib/l10n/app_id.arb b/lib/l10n/app_id.arb index 13087746..3b4cd0cd 100644 --- a/lib/l10n/app_id.arb +++ b/lib/l10n/app_id.arb @@ -28,6 +28,7 @@ "close": "Menutup", "cmd": "Memerintah", "conn": "Koneksi", + "connected": "Terhubung", "containerName": "Nama kontainer", "containerStatus": "Status wadah", "convert": "Mengubah", diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index 9737c4df..8f03b7a1 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -28,6 +28,7 @@ "close": "关闭", "cmd": "命令", "conn": "连接", + "connected": "已连接", "containerName": "容器名", "containerStatus": "容器状态", "convert": "转换", diff --git a/lib/l10n/app_zh_tw.arb b/lib/l10n/app_zh_tw.arb index 827f64df..e0d23a5c 100644 --- a/lib/l10n/app_zh_tw.arb +++ b/lib/l10n/app_zh_tw.arb @@ -28,6 +28,7 @@ "close": "關閉", "cmd": "命令", "conn": "連接", + "connected": "已連接", "containerName": "容器名稱", "containerStatus": "容器狀態", "convert": "轉換", diff --git a/lib/main.dart b/lib/main.dart index 99f93e92..a1987c56 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -44,8 +44,17 @@ Future initApp() async { Logger.root.level = Level.ALL; Logger.root.onRecord.listen((record) { + var str = '[${record.loggerName}][${record.level.name}]: ${record.message}'; + if (record.error != null) { + str += '\n${record.error}'; + _debug.addMultiline(record.error.toString(), Colors.red); + } + if (record.stackTrace != null) { + str += '\n${record.stackTrace}'; + _debug.addMultiline(record.stackTrace.toString(), Colors.white); + } // ignore: avoid_print - print('[${record.loggerName}][${record.level.name}]: ${record.message}'); + print(str); }); } @@ -59,7 +68,7 @@ Future initHive() async { Hive.registerAdapter(NetViewTypeAdapter()); } -void runInZone(dynamic Function() body) { +void runInZone(void Function() body) { final zoneSpec = ZoneSpecification( print: (Zone self, ZoneDelegate parent, Zone zone, String line) { parent.print(zone, line); @@ -80,7 +89,7 @@ void runInZone(dynamic Function() body) { } void onError(Object obj, StackTrace stack) { - Analysis.recordException(obj); + Analysis.recordException(stack); _debug.addMultiline(obj, Colors.red); _debug.addMultiline(stack, Colors.white); } diff --git a/lib/view/page/convert.dart b/lib/view/page/convert.dart index ec6b3335..ca246ea1 100644 --- a/lib/view/page/convert.dart +++ b/lib/view/page/convert.dart @@ -41,6 +41,13 @@ class _ConvertPageState extends State _s = S.of(context)!; } + @override + void dispose() { + super.dispose(); + _textEditingController.dispose(); + _textEditingControllerResult.dispose(); + } + @override Widget build(BuildContext context) { super.build(context); diff --git a/lib/view/page/docker.dart b/lib/view/page/docker.dart index 3a9bed91..378dec54 100644 --- a/lib/view/page/docker.dart +++ b/lib/view/page/docker.dart @@ -41,6 +41,7 @@ class _DockerManagePageState extends State { void dispose() { super.dispose(); _docker.clear(); + _textController.dispose(); } @override @@ -54,8 +55,6 @@ class _DockerManagePageState extends State { super.initState(); final client = locator().servers[widget.spi.id]?.client; if (client == null) { - showSnackBar(context, Text(_s.noClient)); - context.pop(); return; } _docker.init(client, widget.spi.user, onPwdRequest, widget.spi.id); diff --git a/lib/view/page/full_screen.dart b/lib/view/page/full_screen.dart index 508f1da9..0eecbd2b 100644 --- a/lib/view/page/full_screen.dart +++ b/lib/view/page/full_screen.dart @@ -63,6 +63,7 @@ class _FullScreenPageState extends State with AfterLayoutMixin { void dispose() { super.dispose(); _timer.cancel(); + _pageController.dispose(); } @override diff --git a/lib/view/page/home.dart b/lib/view/page/home.dart index bf06a46a..ae9024c4 100644 --- a/lib/view/page/home.dart +++ b/lib/view/page/home.dart @@ -75,6 +75,7 @@ class _HomePageState extends State super.dispose(); WidgetsBinding.instance.removeObserver(this); _serverProvider.closeServer(); + _pageController.dispose(); } @override diff --git a/lib/view/page/ping.dart b/lib/view/page/ping.dart index 562ee28e..78694abf 100644 --- a/lib/view/page/ping.dart +++ b/lib/view/page/ping.dart @@ -48,6 +48,13 @@ class _PingPageState extends State _s = S.of(context)!; } + @override + void dispose() { + super.dispose(); + _textEditingController.dispose(); + _results.dispose(); + } + @override Widget build(BuildContext context) { super.build(context); diff --git a/lib/view/page/pkg.dart b/lib/view/page/pkg.dart index 0e1b294d..e3f000d6 100644 --- a/lib/view/page/pkg.dart +++ b/lib/view/page/pkg.dart @@ -45,18 +45,17 @@ class _PkgManagePageState extends State void dispose() { super.dispose(); _pkgProvider.clear(); + _textController.dispose(); + _scrollController.dispose(); + _scrollControllerUpdate.dispose(); } @override void initState() { super.initState(); final si = locator().servers[widget.spi.id]; - if (si == null || si.client == null) { - showSnackBar(context, Text(_s.waitConnection)); - context.pop(); - return; - } + if (si == null) return; _pkgProvider.init( si.client!, si.status.sysVer.dist, diff --git a/lib/view/page/private_key/edit.dart b/lib/view/page/private_key/edit.dart index 07ee547b..f8d41f2c 100644 --- a/lib/view/page/private_key/edit.dart +++ b/lib/view/page/private_key/edit.dart @@ -51,6 +51,17 @@ class _PrivateKeyEditPageState extends State _provider = locator(); } + @override + void dispose() { + super.dispose(); + _nameController.dispose(); + _keyController.dispose(); + _pwdController.dispose(); + _nameNode.dispose(); + _keyNode.dispose(); + _pwdNode.dispose(); + } + @override void didChangeDependencies() { super.didChangeDependencies(); diff --git a/lib/view/page/process.dart b/lib/view/page/process.dart index 8985e5d3..009249b7 100644 --- a/lib/view/page/process.dart +++ b/lib/view/page/process.dart @@ -41,10 +41,6 @@ class _ProcessPageState extends State { void initState() { super.initState(); _client = _serverProvider.servers[widget.spi.id]?.client; - if (_client == null) { - showSnackBar(context, Text(_s.noClient)); - return; - } _timer = Timer.periodic(const Duration(seconds: 3), (_) => _refresh()); } diff --git a/lib/view/page/server/edit.dart b/lib/view/page/server/edit.dart index 2b4ccc5f..b76f7456 100644 --- a/lib/view/page/server/edit.dart +++ b/lib/view/page/server/edit.dart @@ -55,6 +55,22 @@ class _ServerEditPageState extends State with AfterLayoutMixin { _serverProvider = locator(); } + @override + void dispose() { + super.dispose(); + _nameController.dispose(); + _ipController.dispose(); + _alterUrlController.dispose(); + _portController.dispose(); + _usernameController.dispose(); + _passwordController.dispose(); + _nameFocus.dispose(); + _ipFocus.dispose(); + _alterUrlFocus.dispose(); + _portFocus.dispose(); + _usernameFocus.dispose(); + } + @override void didChangeDependencies() { super.didChangeDependencies(); diff --git a/lib/view/page/server/tab.dart b/lib/view/page/server/tab.dart index b080d446..48d179ea 100644 --- a/lib/view/page/server/tab.dart +++ b/lib/view/page/server/tab.dart @@ -150,12 +150,12 @@ class _ServerPageState extends State return GestureDetector( key: Key(si.spi.id + (_tag ?? '')), onTap: () { - if (si.state == ServerState.connected) { + if (si.state.canViewDetails) { AppRoute( ServerDetailPage(si.spi.id), 'server detail page', ).go(context); - } else { + } else if (si.status.failedInfo != null) { _showFailReason(si.status); } }, @@ -176,7 +176,7 @@ class _ServerPageState extends State final rootDisk = findRootDisk(ss.disk); late final List children; var height = 23.0; - if (cs != ServerState.connected) { + if (cs != ServerState.finished) { children = [ _buildServerCardTitle(ss, cs, spi), ]; @@ -286,7 +286,7 @@ class _ServerPageState extends State context: context, title: Text(_s.error), child: SingleChildScrollView( - child: Text(ss.failedInfo!), + child: Text(ss.failedInfo ?? _s.unknownError), ), actions: [ TextButton( @@ -393,12 +393,16 @@ class _ServerPageState extends State switch (cs) { case ServerState.disconnected: return _s.disconnected; - case ServerState.connected: + case ServerState.finished: final tempStr = temp == null ? '' : '${temp.toStringAsFixed(1)}°C'; final items = [tempStr, upTime]; final str = items.where((element) => element.isNotEmpty).join(' | '); - if (str.isEmpty) return _s.serverTabLoading; + if (str.isEmpty) return _s.noResult; return str; + case ServerState.loading: + return _s.serverTabLoading; + case ServerState.connected: + return _s.connected; case ServerState.connecting: return _s.serverTabConnecting; case ServerState.failed: @@ -409,8 +413,6 @@ class _ServerPageState extends State return _s.serverTabPlzSave; } return failedInfo; - default: - return _s.serverTabUnkown; } } diff --git a/lib/view/page/snippet/edit.dart b/lib/view/page/snippet/edit.dart index 945375c4..c318cae9 100644 --- a/lib/view/page/snippet/edit.dart +++ b/lib/view/page/snippet/edit.dart @@ -37,6 +37,14 @@ class _SnippetEditPageState extends State _provider = locator(); } + @override + void dispose() { + super.dispose(); + _nameController.dispose(); + _scriptController.dispose(); + _scriptNode.dispose(); + } + @override void didChangeDependencies() { super.didChangeDependencies(); diff --git a/lib/view/page/ssh/term.dart b/lib/view/page/ssh/term.dart index 88d13393..4a1b1d52 100644 --- a/lib/view/page/ssh/term.dart +++ b/lib/view/page/ssh/term.dart @@ -68,6 +68,18 @@ class _SSHPageState extends State { _initVirtKeys(); } + @override + void dispose() { + super.dispose(); + _virtKeyLongPressTimer?.cancel(); + _terminalController.dispose(); + _client?.close(); + // ignore: unnecessary_null_comparison + if (_session != null) { + _session.close(); + } + } + @override void didChangeDependencies() { super.didChangeDependencies(); @@ -80,12 +92,6 @@ class _SSHPageState extends State { _virtKeysHeight = _media.size.height * 0.043 * _virtKeysList.length; } - @override - void dispose() { - _client?.close(); - super.dispose(); - } - @override Widget build(BuildContext context) { Widget child = Scaffold( diff --git a/lib/view/page/storage/sftp.dart b/lib/view/page/storage/sftp.dart index a6c0061a..cd39681a 100644 --- a/lib/view/page/storage/sftp.dart +++ b/lib/view/page/storage/sftp.dart @@ -49,7 +49,6 @@ class SftpPage extends StatefulWidget { class _SftpPageState extends State { final SftpBrowserStatus _status = SftpBrowserStatus(); - final ScrollController _scrollController = ScrollController(); final _sftp = locator(); @@ -297,7 +296,6 @@ class _SftpPageState extends State { key: Key(widget.spi.name + _status.path!.path), child: ListView.builder( itemCount: _status.files!.length, - controller: _scrollController, padding: const EdgeInsets.symmetric(horizontal: 7, vertical: 3), itemBuilder: (_, index) => _buildItem(_status.files![index]), ), @@ -458,9 +456,7 @@ class _SftpPageState extends State { TextButton( onPressed: () async { context.pop(); - showLoadingDialog( - context - ); + showLoadingDialog(context); final remotePath = _getRemotePath(file); try { if (file.attr.isDirectory) { diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj index e9b3c4e8..6db32eb8 100644 --- a/macos/Runner.xcodeproj/project.pbxproj +++ b/macos/Runner.xcodeproj/project.pbxproj @@ -475,9 +475,9 @@ baseConfigurationReference = C1C758C41C4E208965A68933 /* Pods-RunnerTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; - CURRENT_PROJECT_VERSION = 454; + CURRENT_PROJECT_VERSION = 457; GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0.454; + MARKETING_VERSION = 1.0.457; PRODUCT_BUNDLE_IDENTIFIER = tech.lolli.serverBox.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; @@ -490,9 +490,9 @@ baseConfigurationReference = 15AF97DF993E8968098D6EBE /* Pods-RunnerTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; - CURRENT_PROJECT_VERSION = 454; + CURRENT_PROJECT_VERSION = 457; GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0.454; + MARKETING_VERSION = 1.0.457; PRODUCT_BUNDLE_IDENTIFIER = tech.lolli.serverBox.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; @@ -505,9 +505,9 @@ baseConfigurationReference = 7CFA7DE7FABA75685DFB6948 /* Pods-RunnerTests.profile.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; - CURRENT_PROJECT_VERSION = 454; + CURRENT_PROJECT_VERSION = 457; GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0.454; + MARKETING_VERSION = 1.0.457; PRODUCT_BUNDLE_IDENTIFIER = tech.lolli.serverBox.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0;