From 3feef3936cf6b421c5dd976e0b2c79b0c9b0bec6 Mon Sep 17 00:00:00 2001 From: lollipopkit Date: Fri, 3 Feb 2023 13:12:39 +0800 Subject: [PATCH] new & opt new: support set maxRetryCount of server reconnection opt: server detail UI opt: server provider opt: `ssh` page on Android --- ios/Runner.xcodeproj/project.pbxproj | 12 +- lib/app.dart | 24 +-- lib/data/model/server/server.dart | 12 +- .../model/server/server_private_info.dart | 20 ++- lib/data/provider/server.dart | 148 ++++++++++-------- lib/data/res/build_data.dart | 8 +- lib/data/res/misc.dart | 2 - lib/data/store/server.dart | 5 +- lib/data/store/setting.dart | 3 + lib/generated/intl/messages_en.dart | 5 + lib/generated/intl/messages_zh.dart | 3 + lib/generated/l10n.dart | 30 ++++ lib/l10n/intl_en.arb | 3 + lib/l10n/intl_zh.arb | 3 + lib/view/page/server/detail.dart | 4 +- lib/view/page/server/edit.dart | 2 +- lib/view/page/server/tab.dart | 17 +- lib/view/page/setting.dart | 47 ++++++ lib/view/page/sftp/view.dart | 2 +- lib/view/page/ssh.dart | 18 ++- 20 files changed, 245 insertions(+), 123 deletions(-) diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index f98dc303..08fb11db 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -356,7 +356,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = 213; + CURRENT_PROJECT_VERSION = 214; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -364,7 +364,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.213; + MARKETING_VERSION = 1.0.214; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -486,7 +486,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = 213; + CURRENT_PROJECT_VERSION = 214; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -494,7 +494,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.213; + MARKETING_VERSION = 1.0.214; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -510,7 +510,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = 213; + CURRENT_PROJECT_VERSION = 214; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -518,7 +518,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.213; + MARKETING_VERSION = 1.0.214; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; diff --git a/lib/app.dart b/lib/app.dart index f6c1a786..7500f379 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -64,17 +64,19 @@ class MyApp extends StatelessWidget { radioTheme: radioTheme, ), darkTheme: ThemeData.dark().copyWith( - useMaterial3: false, - floatingActionButtonTheme: fabTheme, - iconTheme: iconTheme, - primaryIconTheme: iconTheme, - switchTheme: switchTheme, - inputDecorationTheme: inputDecorationTheme, - radioTheme: radioTheme, - colorScheme: ColorScheme.fromSwatch( - primarySwatch: primaryColor.materialColor, - brightness: Brightness.dark, - accentColor: primaryColor)), + useMaterial3: false, + floatingActionButtonTheme: fabTheme, + iconTheme: iconTheme, + primaryIconTheme: iconTheme, + switchTheme: switchTheme, + inputDecorationTheme: inputDecorationTheme, + radioTheme: radioTheme, + colorScheme: ColorScheme.fromSwatch( + primarySwatch: primaryColor.materialColor, + brightness: Brightness.dark, + accentColor: primaryColor, + ), + ), home: const MyHomePage(), ); }, diff --git a/lib/data/model/server/server.dart b/lib/data/model/server/server.dart index 70199ac7..068f2b13 100644 --- a/lib/data/model/server/server.dart +++ b/lib/data/model/server/server.dart @@ -6,9 +6,17 @@ class Server { ServerPrivateInfo spi; ServerStatus status; SSHClient? client; - ServerConnectionState cs; + ServerState cs; Server(this.spi, this.status, this.client, this.cs); } -enum ServerConnectionState { disconnected, connecting, connected, failed } +enum ServerState { + disconnected, + connecting, + connected, + failed; + + bool get shouldConnect => + this == ServerState.disconnected || this == ServerState.failed; +} diff --git a/lib/data/model/server/server_private_info.dart b/lib/data/model/server/server_private_info.dart index f574dbc6..b2d9ad96 100644 --- a/lib/data/model/server/server_private_info.dart +++ b/lib/data/model/server/server_private_info.dart @@ -31,15 +31,17 @@ class ServerPrivateInfo { @HiveField(5) String? pubKeyId; - String get id => '$user@$ip:$port'; + late String id; + + ServerPrivateInfo({ + required this.name, + required this.ip, + required this.port, + required this.user, + required this.pwd, + this.pubKeyId, + }) : id = '$user@$ip:$port'; - ServerPrivateInfo( - {required this.name, - required this.ip, - required this.port, - required this.user, - required this.pwd, - this.pubKeyId}); ServerPrivateInfo.fromJson(Map json) { name = json["name"].toString(); ip = json["ip"].toString(); @@ -47,7 +49,9 @@ class ServerPrivateInfo { user = json["user"].toString(); pwd = json["authorization"].toString(); pubKeyId = json["pubKeyId"]?.toString(); + id = '$user@$ip:$port'; } + Map toJson() { final Map data = {}; data["name"] = name; diff --git a/lib/data/provider/server.dart b/lib/data/provider/server.dart index 40e70be4..b5832458 100644 --- a/lib/data/provider/server.dart +++ b/lib/data/provider/server.dart @@ -2,7 +2,6 @@ import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:logging/logging.dart'; -import 'package:toolbox/data/res/misc.dart'; import '../../core/extension/uint8list.dart'; import '../../core/provider_base.dart'; @@ -28,7 +27,7 @@ class ServerProvider extends BusyProvider { Timer? _timer; - final logger = Logger('SERVER'); + final _logger = Logger('SERVER'); Future loadLocalData() async { setBusyState(true); @@ -39,7 +38,7 @@ class ServerProvider extends BusyProvider { } Server genServer(ServerPrivateInfo spi) { - return Server(spi, initStatus, null, ServerConnectionState.disconnected); + return Server(spi, initStatus, null, ServerState.disconnected); } Future refreshData({ServerPrivateInfo? spi}) async { @@ -71,8 +70,9 @@ class ServerProvider extends BusyProvider { void setDisconnected() { for (var i = 0; i < _servers.length; i++) { - _servers[i].cs = ServerConnectionState.disconnected; + _servers[i].cs = ServerState.disconnected; } + notifyListeners(); } void closeServer({ServerPrivateInfo? spi}) { @@ -81,163 +81,171 @@ class ServerProvider extends BusyProvider { _servers[i].client?.close(); _servers[i].client = null; } + notifyListeners(); return; } - final idx = _servers.indexWhere((e) => e.spi == spi); - if (idx < 0) { - throw RangeError.index(idx, _servers); - } + final idx = getServerIdx(spi.id); _servers[idx].client?.close(); + _servers[idx].client = null; + notifyListeners(); } void addServer(ServerPrivateInfo spi) { _servers.add(genServer(spi)); - locator().put(spi); notifyListeners(); + locator().put(spi); refreshData(spi: spi); } - void delServer(ServerPrivateInfo info) { - final idx = _servers.indexWhere((s) => s.spi == info); - if (idx == -1) return; + void delServer(String id) { + final idx = getServerIdx(id); _servers[idx].client?.close(); _servers.removeAt(idx); notifyListeners(); - locator().delete(info); + locator().delete(id); } Future updateServer( ServerPrivateInfo old, ServerPrivateInfo newSpi) async { - final idx = _servers.indexWhere((e) => e.spi == old); + final idx = _servers.indexWhere((e) => e.spi.id == old.id); if (idx < 0) { throw RangeError.index(idx, _servers); } _servers[idx].spi = newSpi; - locator().update(old, newSpi); _servers[idx].client = await genClient(newSpi); notifyListeners(); + locator().update(old, newSpi); refreshData(spi: newSpi); } + int getServerIdx(String id) { + final idx = _servers.indexWhere((s) => s.spi.id == id); + if (idx < 0) { + throw Exception('Server not found: $id'); + } + return idx; + } + + Server getServer(String id) => _servers[getServerIdx(id)]; + Future _getData(ServerPrivateInfo spi) async { - final s = _servers.firstWhere((element) => element.spi == spi); + final sid = spi.id; + final s = getServer(sid); final state = s.cs; - if (state == ServerConnectionState.failed || - state == ServerConnectionState.disconnected) { - if (!_limiter.shouldTry(spi.id)) { - s.cs = ServerConnectionState.failed; + if (state.shouldConnect) { + if (!_limiter.shouldTry(sid)) { + s.cs = ServerState.failed; notifyListeners(); return; } - s.cs = ServerConnectionState.connecting; + s.cs = ServerState.connecting; notifyListeners(); - final time1 = DateTime.now(); + try { + // try to connect + final time1 = DateTime.now(); s.client = await genClient(spi); final time2 = DateTime.now(); - logger.info( - 'Connected to [${spi.name}] in [${time2.difference(time1).toString()}].'); - s.cs = ServerConnectionState.connected; + final spentTime = time2.difference(time1).inMilliseconds; + _logger.info('Connected to [$sid] in $spentTime ms.'); + + // after connected + s.cs = ServerState.connected; final writeResult = await s.client! .run("echo '$shellCmd' > $shellPath && chmod +x $shellPath") .string; + + // if write failed if (writeResult.isNotEmpty) { throw Exception(writeResult); } - _limiter.resetTryTimes(spi.id); + _limiter.resetTryTimes(sid); } catch (e) { - s.cs = ServerConnectionState.failed; - s.status.failedInfo = '$e ## '; - logger.warning(e); + s.cs = ServerState.failed; + s.status.failedInfo = '$e'; + _logger.warning(e); } finally { notifyListeners(); } } - // if client is null, return if (s.client == null) return; + // run script to get server status final raw = await s.client!.run("sh $shellPath").string; final segments = raw.split(seperator).map((e) => e.trim()).toList(); if (raw.isEmpty || segments.length == 1) { - s.cs = ServerConnectionState.failed; + s.cs = ServerState.failed; if (s.status.failedInfo == null || s.status.failedInfo!.isEmpty) { s.status.failedInfo = 'No data received'; } notifyListeners(); return; } + // remove first empty segment segments.removeAt(0); try { - _getCPU(spi, segments[2], segments[7], segments[8]); - _getMem(spi, segments[6]); - _getSysVer(spi, segments[1]); - _getUpTime(spi, segments[3]); - _getDisk(spi, segments[5]); - _getTcp(spi, segments[4]); - _getNetSpeed(spi, segments[0]); + _getCPU(sid, segments[2], segments[7], segments[8]); + _getMem(sid, segments[6]); + _getSysVer(sid, segments[1]); + _getUpTime(sid, segments[3]); + _getDisk(sid, segments[5]); + _getTcp(sid, segments[4]); + _getNetSpeed(sid, segments[0]); } catch (e) { - s.cs = ServerConnectionState.failed; + s.cs = ServerState.failed; s.status.failedInfo = e.toString(); - logger.warning(e); + _logger.warning(e); rethrow; } finally { notifyListeners(); } } - Future _getNetSpeed(ServerPrivateInfo spi, String raw) async { - final info = _servers.firstWhere((e) => e.spi == spi); - info.status.netSpeed.update(await compute(parseNetSpeed, raw)); + Future _getNetSpeed(String id, String raw) async { + final net = await compute(parseNetSpeed, raw); + getServer(id).status.netSpeed.update(net); } - void _getSysVer(ServerPrivateInfo spi, String raw) { - final info = _servers.firstWhere((e) => e.spi == spi); + void _getSysVer(String id, String raw) { final s = raw.split('='); if (s.length == 2) { - info.status.sysVer = s[1].replaceAll('"', '').replaceFirst('\n', ''); + final ver = s[1].replaceAll('"', '').replaceFirst('\n', ''); + getServer(id).status.sysVer = ver; } } - Future _getCPU(ServerPrivateInfo spi, String raw, String tempType, - String tempValue) async { - final info = _servers.firstWhere((e) => e.spi == spi); + Future _getCPU( + String id, String raw, String tempType, String tempValue) async { final cpus = await compute(parseCPU, raw); + final temp = await compute(parseCPUTemp, [tempType, tempValue]); if (cpus.isNotEmpty) { - info.status.cpu.update( - cpus, - await compute(parseCPUTemp, [tempType, tempValue]), - ); + getServer(id).status.cpu.update(cpus, temp); } } - void _getUpTime(ServerPrivateInfo spi, String raw) { - _servers.firstWhere((e) => e.spi == spi).status.uptime = - raw.split('up ')[1].split(', ')[0]; + void _getUpTime(String id, String raw) { + getServer(id).status.uptime = raw.split('up ')[1].split(', ')[0]; } - Future _getTcp(ServerPrivateInfo spi, String raw) async { - final info = _servers.firstWhere((e) => e.spi == spi); + Future _getTcp(String id, String raw) async { final status = await compute(parseTcp, raw); if (status != null) { - info.status.tcp = status; + getServer(id).status.tcp = status; } } - Future _getDisk(ServerPrivateInfo spi, String raw) async { - final info = _servers.firstWhere((e) => e.spi == spi); - info.status.disk = await compute(parseDisk, raw); + Future _getDisk(String id, String raw) async { + getServer(id).status.disk = await compute(parseDisk, raw); } - Future _getMem(ServerPrivateInfo spi, String raw) async { - final info = _servers.firstWhere((e) => e.spi == spi); - info.status.mem = await compute(parseMem, raw); + Future _getMem(String id, String raw) async { + getServer(id).status.mem = await compute(parseMem, raw); } Future runSnippet(String id, Snippet snippet) async { - final client = - _servers.firstWhere((element) => element.spi.id == id).client; + final client = getServer(id).client; if (client == null) { return null; } @@ -249,8 +257,12 @@ class _TryLimiter { final Map _triedTimes = {}; bool shouldTry(String id) { + final maxCount = locator().maxRetryCount.fetch()!; + if (maxCount <= 0) { + return true; + } final times = _triedTimes[id] ?? 0; - if (times >= serverMaxTryTimes) { + if (times >= maxCount) { return false; } _triedTimes[id] = times + 1; diff --git a/lib/data/res/build_data.dart b/lib/data/res/build_data.dart index 3b0097cc..32fd9b9a 100644 --- a/lib/data/res/build_data.dart +++ b/lib/data/res/build_data.dart @@ -2,9 +2,9 @@ class BuildData { static const String name = "ServerBox"; - static const int build = 213; + static const int build = 214; static const String engine = - "Flutter 3.7.0 • channel stable • https://github.com/flutter/flutter.git\nFramework • revision b06b8b2710 (9 days ago) • 2023-01-23 16:55:55 -0800\nEngine • revision b24591ed32\nTools • Dart 2.19.0 • DevTools 2.20.1\n"; - static const String buildAt = "2023-02-02 16:57:16.480921"; - static const int modifications = 5; + "Flutter 3.7.0 • channel stable • https://github.com/flutter/flutter.git\nFramework • revision b06b8b2710 (10 days ago) • 2023-01-23 16:55:55 -0800\nEngine • revision b24591ed32\nTools • Dart 2.19.0 • DevTools 2.20.1\n"; + static const String buildAt = "2023-02-03 12:48:35.264858"; + static const int modifications = 12; } diff --git a/lib/data/res/misc.dart b/lib/data/res/misc.dart index 76dc418b..34c14749 100644 --- a/lib/data/res/misc.dart +++ b/lib/data/res/misc.dart @@ -1,3 +1 @@ -const serverMaxTryTimes = 7; - final numReg = RegExp(r'\s{1,}'); diff --git a/lib/data/store/server.dart b/lib/data/store/server.dart index 5e39bc3f..bb6725e8 100644 --- a/lib/data/store/server.dart +++ b/lib/data/store/server.dart @@ -18,14 +18,15 @@ class ServerStore extends PersistentStore { return ss; } - void delete(ServerPrivateInfo s) { - box.delete(s.id); + void delete(String id) { + box.delete(id); } void update(ServerPrivateInfo old, ServerPrivateInfo newInfo) { if (!have(old)) { throw Exception('Old ServerPrivateInfo not found'); } + delete(old.id); put(newInfo); } diff --git a/lib/data/store/setting.dart b/lib/data/store/setting.dart index defc2543..e62ea42f 100644 --- a/lib/data/store/setting.dart +++ b/lib/data/store/setting.dart @@ -25,4 +25,7 @@ class SettingStore extends PersistentStore { StoreProperty get termColorIdx => property('termColorIdx', defaultValue: 0); + + /// Max retry count when connect to server + StoreProperty get maxRetryCount => property('maxRetryCount', defaultValue: 7); } diff --git a/lib/generated/intl/messages_en.dart b/lib/generated/intl/messages_en.dart index 64f6ff89..605d5871 100644 --- a/lib/generated/intl/messages_en.dart +++ b/lib/generated/intl/messages_en.dart @@ -166,6 +166,10 @@ class MessageLookup extends MessageLookupByLibrary { "loss": MessageLookupByLibrary.simpleMessage("loss"), "madeWithLove": m8, "max": MessageLookupByLibrary.simpleMessage("max"), + "maxRetryCount": MessageLookupByLibrary.simpleMessage( + "Number of server reconnection"), + "maxRetryCountEqual0": + MessageLookupByLibrary.simpleMessage("Will retry again and again."), "min": MessageLookupByLibrary.simpleMessage("min"), "ms": MessageLookupByLibrary.simpleMessage("ms"), "name": MessageLookupByLibrary.simpleMessage("Name"), @@ -243,6 +247,7 @@ class MessageLookup extends MessageLookupByLibrary { "Are you sure to use no password?"), "sureToDeleteServer": m14, "termTheme": MessageLookupByLibrary.simpleMessage("Terminal theme"), + "times": MessageLookupByLibrary.simpleMessage("Times"), "ttl": MessageLookupByLibrary.simpleMessage("ttl"), "unknown": MessageLookupByLibrary.simpleMessage("unknown"), "unknownError": MessageLookupByLibrary.simpleMessage("Unknown error"), diff --git a/lib/generated/intl/messages_zh.dart b/lib/generated/intl/messages_zh.dart index 87243a1f..8e21b88e 100644 --- a/lib/generated/intl/messages_zh.dart +++ b/lib/generated/intl/messages_zh.dart @@ -148,6 +148,8 @@ class MessageLookup extends MessageLookupByLibrary { "loss": MessageLookupByLibrary.simpleMessage("丢包率"), "madeWithLove": m8, "max": MessageLookupByLibrary.simpleMessage("最大"), + "maxRetryCount": MessageLookupByLibrary.simpleMessage("连接服务器重试次数"), + "maxRetryCountEqual0": MessageLookupByLibrary.simpleMessage("会无限重试"), "min": MessageLookupByLibrary.simpleMessage("最小"), "ms": MessageLookupByLibrary.simpleMessage("毫秒"), "name": MessageLookupByLibrary.simpleMessage("名称"), @@ -210,6 +212,7 @@ class MessageLookup extends MessageLookupByLibrary { "sureNoPwd": MessageLookupByLibrary.simpleMessage("确认使用无密码?"), "sureToDeleteServer": m14, "termTheme": MessageLookupByLibrary.simpleMessage("终端主题"), + "times": MessageLookupByLibrary.simpleMessage("次"), "ttl": MessageLookupByLibrary.simpleMessage("缓存时间"), "unknown": MessageLookupByLibrary.simpleMessage("未知"), "unknownError": MessageLookupByLibrary.simpleMessage("未知错误"), diff --git a/lib/generated/l10n.dart b/lib/generated/l10n.dart index 3f227bf0..98d5b1d0 100644 --- a/lib/generated/l10n.dart +++ b/lib/generated/l10n.dart @@ -821,6 +821,26 @@ class S { ); } + /// `Number of server reconnection` + String get maxRetryCount { + return Intl.message( + 'Number of server reconnection', + name: 'maxRetryCount', + desc: '', + args: [], + ); + } + + /// `Will retry again and again.` + String get maxRetryCountEqual0 { + return Intl.message( + 'Will retry again and again.', + name: 'maxRetryCountEqual0', + desc: '', + args: [], + ); + } + /// `min` String get min { return Intl.message( @@ -1391,6 +1411,16 @@ class S { ); } + /// `Times` + String get times { + return Intl.message( + 'Times', + name: 'times', + desc: '', + args: [], + ); + } + /// `ttl` String get ttl { return Intl.message( diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index 9ed88d09..8eae8b5f 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -76,6 +76,8 @@ "loss": "loss", "madeWithLove": "\nMade with ❤️ by {myGithub}", "max": "max", + "maxRetryCount": "Number of server reconnection", + "maxRetryCountEqual0": "Will retry again and again.", "min": "min", "ms": "ms", "name": "Name", @@ -133,6 +135,7 @@ "sureNoPwd": "Are you sure to use no password?", "sureToDeleteServer": "Are you sure to delete server [{server}]?", "termTheme": "Terminal theme", + "times": "Times", "ttl": "ttl", "unknown": "unknown", "unknownError": "Unknown error", diff --git a/lib/l10n/intl_zh.arb b/lib/l10n/intl_zh.arb index 061c0af0..84879234 100644 --- a/lib/l10n/intl_zh.arb +++ b/lib/l10n/intl_zh.arb @@ -76,6 +76,8 @@ "loss": "丢包率", "madeWithLove": "\n用❤️制作 by {myGithub}", "max": "最大", + "maxRetryCount": "连接服务器重试次数", + "maxRetryCountEqual0": "会无限重试", "min": "最小", "ms": "毫秒", "name": "名称", @@ -133,6 +135,7 @@ "sureNoPwd": "确认使用无密码?", "sureToDeleteServer": "你确定要删除服务器 [{server}] 吗?", "termTheme": "终端主题", + "times": "次", "ttl": "缓存时间", "unknown": "未知", "unknownError": "未知错误", diff --git a/lib/view/page/server/detail.dart b/lib/view/page/server/detail.dart index cc2deab6..5803717c 100644 --- a/lib/view/page/server/detail.dart +++ b/lib/view/page/server/detail.dart @@ -345,7 +345,7 @@ class _ServerDetailPageState extends State '${ns.speedIn(device: device)} | ${ns.totalIn(device: device)}', style: textSize11, textAlign: TextAlign.center, - textScaleFactor: 0.87, + textScaleFactor: 0.9, ), ), SizedBox( @@ -354,7 +354,7 @@ class _ServerDetailPageState extends State '${ns.speedOut(device: device)} | ${ns.totalOut(device: device)}', style: textSize11, textAlign: TextAlign.right, - textScaleFactor: 0.87, + textScaleFactor: 0.9, ), ) ], diff --git a/lib/view/page/server/edit.dart b/lib/view/page/server/edit.dart index f8f7e783..78eabec0 100644 --- a/lib/view/page/server/edit.dart +++ b/lib/view/page/server/edit.dart @@ -73,7 +73,7 @@ class _ServerEditPageState extends State with AfterLayoutMixin { [ TextButton( onPressed: () { - _serverProvider.delServer(widget.spi!); + _serverProvider.delServer(widget.spi!.id); Navigator.of(context).pop(); Navigator.of(context).pop(); }, diff --git a/lib/view/page/server/tab.dart b/lib/view/page/server/tab.dart index 31a8b68d..1a875761 100644 --- a/lib/view/page/server/tab.dart +++ b/lib/view/page/server/tab.dart @@ -123,13 +123,12 @@ class _ServerPageState extends State } Widget _buildRealServerCard(ServerStatus ss, String serverName, - ServerConnectionState cs, ServerPrivateInfo spi) { + ServerState cs, ServerPrivateInfo spi) { final rootDisk = ss.disk.firstWhere((element) => element.loc == '/'); final topRightStr = getTopRightStr(cs, ss.cpu.temp, ss.uptime, ss.failedInfo); - final hasError = - cs == ServerConnectionState.failed && ss.failedInfo != null; + final hasError = cs == ServerState.failed && ss.failedInfo != null; final style = TextStyle( color: _theme.textTheme.bodyLarge!.color!.withAlpha(100), fontSize: 11); @@ -288,12 +287,12 @@ class _ServerPageState extends State ); } - String getTopRightStr(ServerConnectionState cs, String temp, String upTime, - String? failedInfo) { + String getTopRightStr( + ServerState cs, String temp, String upTime, String? failedInfo) { switch (cs) { - case ServerConnectionState.disconnected: + case ServerState.disconnected: return _s.disconnected; - case ServerConnectionState.connected: + case ServerState.connected: if (temp == '') { if (upTime == '') { return _s.serverTabLoading; @@ -307,9 +306,9 @@ class _ServerPageState extends State return '$temp | $upTime'; } } - case ServerConnectionState.connecting: + case ServerState.connecting: return _s.serverTabConnecting; - case ServerConnectionState.failed: + case ServerState.failed: if (failedInfo == null) { return _s.serverTabFailed; } diff --git a/lib/view/page/setting.dart b/lib/view/page/setting.dart index 6e83f54b..4fe5cfc2 100644 --- a/lib/view/page/setting.dart +++ b/lib/view/page/setting.dart @@ -32,6 +32,7 @@ class _SettingPageState extends State { late int _selectedColorValue; late int _launchPageIdx; late int _termThemeIdx; + late double _maxRetryCount; late double _updateInterval; @override @@ -49,6 +50,7 @@ class _SettingPageState extends State { _launchPageIdx = _setting.launchPage.fetch()!; _termThemeIdx = _setting.termColorIdx.fetch()!; _updateInterval = _setting.serverStatusUpdateInterval.fetch()!.toDouble(); + _maxRetryCount = _setting.maxRetryCount.fetch()!.toDouble(); } @override @@ -66,6 +68,7 @@ class _SettingPageState extends State { _buildLaunchPage(), _buildDistLogoSwitch(), _buildTermTheme(), + _buildMaxRetry(), ].map((e) => RoundRectCard(e)).toList(), ), ); @@ -286,4 +289,48 @@ class _SettingPageState extends State { }, ); } + + Widget _buildMaxRetry() { + return ExpansionTile( + textColor: primaryColor, + title: Text( + _s.maxRetryCount, + style: textSize13, + textAlign: TextAlign.start, + ), + trailing: Text('${_maxRetryCount.toInt()} ${_s.times}'), + children: [ + Slider( + thumbColor: primaryColor, + activeColor: primaryColor.withOpacity(0.7), + min: 0, + max: 10, + value: _maxRetryCount, + onChanged: (newValue) { + setState(() { + _maxRetryCount = newValue; + }); + }, + onChangeEnd: (val) { + _setting.maxRetryCount.put(val.toInt()); + }, + label: '${_maxRetryCount.toInt()} ${_s.times}', + divisions: 10, + ), + const SizedBox( + height: 3, + ), + _maxRetryCount == 0.0 + ? Text( + _s.maxRetryCountEqual0, + style: const TextStyle(color: Colors.grey, fontSize: 12), + textAlign: TextAlign.center, + ) + : const SizedBox(), + const SizedBox( + height: 13, + ) + ], + ); + } } diff --git a/lib/view/page/sftp/view.dart b/lib/view/page/sftp/view.dart index 2087f57c..ecf2e675 100644 --- a/lib/view/page/sftp/view.dart +++ b/lib/view/page/sftp/view.dart @@ -177,7 +177,7 @@ class _SFTPPageState extends State { ); Widget _buildFileView() { - if (_client == null || _si?.cs != ServerConnectionState.connected) { + if (_client == null || _si?.cs != ServerState.connected) { return centerCircleLoading; } diff --git a/lib/view/page/ssh.dart b/lib/view/page/ssh.dart index 4d04f321..0a938bc3 100644 --- a/lib/view/page/ssh.dart +++ b/lib/view/page/ssh.dart @@ -105,14 +105,18 @@ class _SSHPageState extends State { @override Widget build(BuildContext context) { final termTheme = _isDark ? termDarkTheme : termLightTheme; - return AnnotatedRegion( - value: _isDark ? SystemUiOverlayStyle.light : SystemUiOverlayStyle.dark, - child: Scaffold( - backgroundColor: termTheme.background, - body: _buildBody(termTheme.toTerminalTheme(_termColors)), - bottomNavigationBar: _buildBottom(termTheme.background), - ), + Widget child = Scaffold( + backgroundColor: termTheme.background, + body: _buildBody(termTheme.toTerminalTheme(_termColors)), + bottomNavigationBar: _buildBottom(termTheme.background), ); + if (Platform.isIOS) { + child = AnnotatedRegion( + value: _isDark ? SystemUiOverlayStyle.light : SystemUiOverlayStyle.dark, + child: child, + ); + } + return child; } Widget _buildBody(TerminalTheme termTheme) {