mirror of
https://github.com/lollipopkit/flutter_server_box.git
synced 2025-12-17 07:14:28 +01:00
new & opt
new: support set maxRetryCount of server reconnection opt: server detail UI opt: server provider opt: `ssh` page on Android
This commit is contained in:
@@ -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";
|
||||
|
||||
@@ -74,7 +74,9 @@ class MyApp extends StatelessWidget {
|
||||
colorScheme: ColorScheme.fromSwatch(
|
||||
primarySwatch: primaryColor.materialColor,
|
||||
brightness: Brightness.dark,
|
||||
accentColor: primaryColor)),
|
||||
accentColor: primaryColor,
|
||||
),
|
||||
),
|
||||
home: const MyHomePage(),
|
||||
);
|
||||
},
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -31,15 +31,17 @@ class ServerPrivateInfo {
|
||||
@HiveField(5)
|
||||
String? pubKeyId;
|
||||
|
||||
String get id => '$user@$ip:$port';
|
||||
late String id;
|
||||
|
||||
ServerPrivateInfo(
|
||||
{required this.name,
|
||||
ServerPrivateInfo({
|
||||
required this.name,
|
||||
required this.ip,
|
||||
required this.port,
|
||||
required this.user,
|
||||
required this.pwd,
|
||||
this.pubKeyId});
|
||||
this.pubKeyId,
|
||||
}) : id = '$user@$ip:$port';
|
||||
|
||||
ServerPrivateInfo.fromJson(Map<String, dynamic> 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<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data["name"] = name;
|
||||
|
||||
@@ -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<void> 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<void> 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<ServerStore>().put(spi);
|
||||
notifyListeners();
|
||||
locator<ServerStore>().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<ServerStore>().delete(info);
|
||||
locator<ServerStore>().delete(id);
|
||||
}
|
||||
|
||||
Future<void> 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<ServerStore>().update(old, newSpi);
|
||||
_servers[idx].client = await genClient(newSpi);
|
||||
notifyListeners();
|
||||
locator<ServerStore>().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<void> _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<void> _getNetSpeed(ServerPrivateInfo spi, String raw) async {
|
||||
final info = _servers.firstWhere((e) => e.spi == spi);
|
||||
info.status.netSpeed.update(await compute(parseNetSpeed, raw));
|
||||
Future<void> _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<void> _getCPU(ServerPrivateInfo spi, String raw, String tempType,
|
||||
String tempValue) async {
|
||||
final info = _servers.firstWhere((e) => e.spi == spi);
|
||||
Future<void> _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<void> _getTcp(ServerPrivateInfo spi, String raw) async {
|
||||
final info = _servers.firstWhere((e) => e.spi == spi);
|
||||
Future<void> _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<void> _getDisk(ServerPrivateInfo spi, String raw) async {
|
||||
final info = _servers.firstWhere((e) => e.spi == spi);
|
||||
info.status.disk = await compute(parseDisk, raw);
|
||||
Future<void> _getDisk(String id, String raw) async {
|
||||
getServer(id).status.disk = await compute(parseDisk, raw);
|
||||
}
|
||||
|
||||
Future<void> _getMem(ServerPrivateInfo spi, String raw) async {
|
||||
final info = _servers.firstWhere((e) => e.spi == spi);
|
||||
info.status.mem = await compute(parseMem, raw);
|
||||
Future<void> _getMem(String id, String raw) async {
|
||||
getServer(id).status.mem = await compute(parseMem, raw);
|
||||
}
|
||||
|
||||
Future<String?> 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<String, int> _triedTimes = {};
|
||||
|
||||
bool shouldTry(String id) {
|
||||
final maxCount = locator<SettingStore>().maxRetryCount.fetch()!;
|
||||
if (maxCount <= 0) {
|
||||
return true;
|
||||
}
|
||||
final times = _triedTimes[id] ?? 0;
|
||||
if (times >= serverMaxTryTimes) {
|
||||
if (times >= maxCount) {
|
||||
return false;
|
||||
}
|
||||
_triedTimes[id] = times + 1;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -1,3 +1 @@
|
||||
const serverMaxTryTimes = 7;
|
||||
|
||||
final numReg = RegExp(r'\s{1,}');
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -25,4 +25,7 @@ class SettingStore extends PersistentStore {
|
||||
|
||||
StoreProperty<int> get termColorIdx =>
|
||||
property('termColorIdx', defaultValue: 0);
|
||||
|
||||
/// Max retry count when connect to server
|
||||
StoreProperty<int> get maxRetryCount => property('maxRetryCount', defaultValue: 7);
|
||||
}
|
||||
|
||||
@@ -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"),
|
||||
|
||||
@@ -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("未知错误"),
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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": "未知错误",
|
||||
|
||||
@@ -345,7 +345,7 @@ class _ServerDetailPageState extends State<ServerDetailPage>
|
||||
'${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<ServerDetailPage>
|
||||
'${ns.speedOut(device: device)} | ${ns.totalOut(device: device)}',
|
||||
style: textSize11,
|
||||
textAlign: TextAlign.right,
|
||||
textScaleFactor: 0.87,
|
||||
textScaleFactor: 0.9,
|
||||
),
|
||||
)
|
||||
],
|
||||
|
||||
@@ -73,7 +73,7 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
|
||||
[
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
_serverProvider.delServer(widget.spi!);
|
||||
_serverProvider.delServer(widget.spi!.id);
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
|
||||
@@ -123,13 +123,12 @@ class _ServerPageState extends State<ServerPage>
|
||||
}
|
||||
|
||||
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<ServerPage>
|
||||
);
|
||||
}
|
||||
|
||||
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<ServerPage>
|
||||
return '$temp | $upTime';
|
||||
}
|
||||
}
|
||||
case ServerConnectionState.connecting:
|
||||
case ServerState.connecting:
|
||||
return _s.serverTabConnecting;
|
||||
case ServerConnectionState.failed:
|
||||
case ServerState.failed:
|
||||
if (failedInfo == null) {
|
||||
return _s.serverTabFailed;
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ class _SettingPageState extends State<SettingPage> {
|
||||
late int _selectedColorValue;
|
||||
late int _launchPageIdx;
|
||||
late int _termThemeIdx;
|
||||
late double _maxRetryCount;
|
||||
late double _updateInterval;
|
||||
|
||||
@override
|
||||
@@ -49,6 +50,7 @@ class _SettingPageState extends State<SettingPage> {
|
||||
_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<SettingPage> {
|
||||
_buildLaunchPage(),
|
||||
_buildDistLogoSwitch(),
|
||||
_buildTermTheme(),
|
||||
_buildMaxRetry(),
|
||||
].map((e) => RoundRectCard(e)).toList(),
|
||||
),
|
||||
);
|
||||
@@ -286,4 +289,48 @@ class _SettingPageState extends State<SettingPage> {
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
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,
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,7 +177,7 @@ class _SFTPPageState extends State<SFTPPage> {
|
||||
);
|
||||
|
||||
Widget _buildFileView() {
|
||||
if (_client == null || _si?.cs != ServerConnectionState.connected) {
|
||||
if (_client == null || _si?.cs != ServerState.connected) {
|
||||
return centerCircleLoading;
|
||||
}
|
||||
|
||||
|
||||
@@ -105,14 +105,18 @@ class _SSHPageState extends State<SSHPage> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final termTheme = _isDark ? termDarkTheme : termLightTheme;
|
||||
return AnnotatedRegion(
|
||||
value: _isDark ? SystemUiOverlayStyle.light : SystemUiOverlayStyle.dark,
|
||||
child: Scaffold(
|
||||
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) {
|
||||
|
||||
Reference in New Issue
Block a user