diff --git a/assets/linux/wrt.png b/assets/linux/wrt.png new file mode 100644 index 00000000..bb208dd9 Binary files /dev/null and b/assets/linux/wrt.png differ diff --git a/lib/data/model/server/memory.dart b/lib/data/model/server/memory.dart index c82720ae..e3913e51 100644 --- a/lib/data/model/server/memory.dart +++ b/lib/data/model/server/memory.dart @@ -2,14 +2,12 @@ class Memory { int total; int used; int free; - int shared; int cache; int avail; Memory( {required this.total, required this.used, required this.free, - required this.shared, required this.cache, required this.avail}); } diff --git a/lib/data/provider/server.dart b/lib/data/provider/server.dart index d53177ed..69f18c01 100644 --- a/lib/data/provider/server.dart +++ b/lib/data/provider/server.dart @@ -37,13 +37,14 @@ const shellCmd = "export LANG=en_US.utf-8 \necho '$seperator' \n" "uptime \necho $seperator \n" "cat /proc/net/snmp \necho $seperator \n" "df -h \necho $seperator \n" - "free -m \necho $seperator \n" + "cat /proc/meminfo \necho $seperator \n" "cat /sys/class/thermal/thermal_zone*/type \necho $seperator \n" "cat /sys/class/thermal/thermal_zone*/temp"; const shellPath = '.serverbox.sh'; const memPrefix = 'Mem:'; final cpuTempReg = RegExp('(x86_pkg_temp|cpu_thermal)'); final numReg = RegExp(r'\s{1,}'); +final memItemReg = RegExp(r'([A-Z].+:)\s+([0-9]+) kB'); class ServerProvider extends BusyProvider { List _servers = []; @@ -54,7 +55,7 @@ class ServerProvider extends BusyProvider { final logger = Logger('ServerProvider'); Memory get emptyMemory => - Memory(total: 1, used: 0, free: 1, shared: 0, cache: 0, avail: 1); + Memory(total: 1, used: 0, free: 1, cache: 0, avail: 1); NetSpeedPart get emptyNetSpeedPart => NetSpeedPart('', 0, 0, 0); @@ -156,8 +157,8 @@ class ServerProvider extends BusyProvider { throw RangeError.index(idx, _servers); } _servers[idx].info = newSpi; - _servers[idx].client = await genClient(newSpi); locator().update(old, newSpi); + _servers[idx].client = await genClient(newSpi); notifyListeners(); refreshData(spi: newSpi); } @@ -194,8 +195,8 @@ class ServerProvider extends BusyProvider { // if client is null, return if (s.client == null) return; final raw = await s.client!.run("sh $shellPath").string; - final lines = raw.split(seperator).map((e) => e.trim()).toList(); - if (raw.isEmpty || lines.length == 1) { + final segments = raw.split(seperator).map((e) => e.trim()).toList(); + if (raw.isEmpty || segments.length == 1) { s.connectionState = ServerConnectionState.failed; if (s.status.failedInfo == null || s.status.failedInfo!.isEmpty) { s.status.failedInfo = 'No data received'; @@ -203,16 +204,16 @@ class ServerProvider extends BusyProvider { notifyListeners(); return; } - lines.removeAt(0); + segments.removeAt(0); try { - _getCPU(spi, lines[2], lines[7], lines[8]); - _getMem(spi, lines[6]); - _getSysVer(spi, lines[1]); - _getUpTime(spi, lines[3]); - _getDisk(spi, lines[5]); - _getTcp(spi, lines[4]); - _getNetSpeed(spi, lines[0]); + _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]); } catch (e) { s.connectionState = ServerConnectionState.failed; s.status.failedInfo = e.toString(); @@ -333,21 +334,22 @@ class ServerProvider extends BusyProvider { void _getMem(ServerPrivateInfo spi, String raw) { final info = _servers.firstWhere((e) => e.info == spi); - for (var item in raw.split('\n')) { - if (item.contains(memPrefix)) { - final split = item.replaceFirst(memPrefix, '').split(' '); - split.removeWhere((e) => e == ''); - final memList = split.map((e) => int.parse(e)).toList(); - info.status.memory = Memory( - total: memList[0], - used: memList[1], - free: memList[2], - shared: memList[3], - cache: memList[4], - avail: memList[5]); - break; - } - } + final items = raw.split('\n').map((e) => memItemReg.firstMatch(e)).toList(); + final total = int.parse( + items.firstWhere((e) => e?.group(1) == 'MemTotal:')?.group(2) ?? '1'); + final free = int.parse( + items.firstWhere((e) => e?.group(1) == 'MemFree:')?.group(2) ?? '0'); + final cached = int.parse( + items.firstWhere((e) => e?.group(1) == 'Cached:')?.group(2) ?? '0'); + final available = int.parse( + items.firstWhere((e) => e?.group(1) == 'MemAvailable:')?.group(2) ?? + '0'); + info.status.memory = Memory( + total: total, + used: total - available, + free: free, + cache: cached, + avail: available); } Future runSnippet(ServerPrivateInfo spi, Snippet snippet) async { diff --git a/lib/data/res/icon/linux_icons.dart b/lib/data/res/icon/linux_icons.dart index bf98b378..1dbe6a87 100644 --- a/lib/data/res/icon/linux_icons.dart +++ b/lib/data/res/icon/linux_icons.dart @@ -1,4 +1,12 @@ import 'package:toolbox/data/model/server/linux_icon.dart'; -final linuxIcons = LinuxIcons( - ['ubuntu', 'arch', 'centos', 'debian', 'fedora', 'opensuse', 'kali']); +final linuxIcons = LinuxIcons([ + 'ubuntu', + 'arch', + 'centos', + 'debian', + 'fedora', + 'opensuse', + 'kali', + 'wrt' +]); diff --git a/lib/generated/intl/messages_en.dart b/lib/generated/intl/messages_en.dart index 27b2bc15..765d39fb 100644 --- a/lib/generated/intl/messages_en.dart +++ b/lib/generated/intl/messages_en.dart @@ -164,8 +164,6 @@ class MessageLookup extends MessageLookupByLibrary { "Current platform does not support in app update.\nPlease build from source and install it."), "plzEnterHost": MessageLookupByLibrary.simpleMessage("Please enter host."), - "plzEnterPwd": - MessageLookupByLibrary.simpleMessage("Please enter password."), "plzSelectKey": MessageLookupByLibrary.simpleMessage("Please select a key."), "port": MessageLookupByLibrary.simpleMessage("Port"), @@ -204,6 +202,8 @@ class MessageLookup extends MessageLookupByLibrary { "start": MessageLookupByLibrary.simpleMessage("Start"), "stop": MessageLookupByLibrary.simpleMessage("Stop"), "sureDelete": m11, + "sureNoPwd": MessageLookupByLibrary.simpleMessage( + "Are you sure to use no password?"), "sureToDeleteServer": m12, "ttl": MessageLookupByLibrary.simpleMessage("ttl"), "unknown": MessageLookupByLibrary.simpleMessage("unknown"), diff --git a/lib/generated/intl/messages_zh.dart b/lib/generated/intl/messages_zh.dart index d76e1ceb..649c8193 100644 --- a/lib/generated/intl/messages_zh.dart +++ b/lib/generated/intl/messages_zh.dart @@ -145,7 +145,6 @@ class MessageLookup extends MessageLookupByLibrary { "platformNotSupportUpdate": MessageLookupByLibrary.simpleMessage("当前平台不支持更新,请编译最新源码后手动安装"), "plzEnterHost": MessageLookupByLibrary.simpleMessage("请输入主机"), - "plzEnterPwd": MessageLookupByLibrary.simpleMessage("请输入密码"), "plzSelectKey": MessageLookupByLibrary.simpleMessage("请选择私钥"), "port": MessageLookupByLibrary.simpleMessage("端口"), "privateKey": MessageLookupByLibrary.simpleMessage("私钥"), @@ -178,6 +177,7 @@ class MessageLookup extends MessageLookupByLibrary { "start": MessageLookupByLibrary.simpleMessage("开始"), "stop": MessageLookupByLibrary.simpleMessage("停止"), "sureDelete": m11, + "sureNoPwd": MessageLookupByLibrary.simpleMessage("确认使用无密码?"), "sureToDeleteServer": m12, "ttl": MessageLookupByLibrary.simpleMessage("缓存时间"), "unknown": MessageLookupByLibrary.simpleMessage("未知"), diff --git a/lib/generated/l10n.dart b/lib/generated/l10n.dart index 19aba532..58cd9f0d 100644 --- a/lib/generated/l10n.dart +++ b/lib/generated/l10n.dart @@ -790,11 +790,11 @@ class S { ); } - /// `Please enter password.` - String get plzEnterPwd { + /// `Are you sure to use no password?` + String get sureNoPwd { return Intl.message( - 'Please enter password.', - name: 'plzEnterPwd', + 'Are you sure to use no password?', + name: 'sureNoPwd', desc: '', args: [], ); diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index dbbe8f18..8e49f72a 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -73,7 +73,7 @@ "addPrivateKey": "Add private key", "choosePrivateKey": "Choose private key", "plzEnterHost": "Please enter host.", - "plzEnterPwd": "Please enter password.", + "sureNoPwd": "Are you sure to use no password?", "plzSelectKey": "Please select a key.", "exampleName": "Example name", "stop": "Stop", diff --git a/lib/l10n/intl_zh.arb b/lib/l10n/intl_zh.arb index c9e29711..a2e38bec 100644 --- a/lib/l10n/intl_zh.arb +++ b/lib/l10n/intl_zh.arb @@ -73,7 +73,7 @@ "addPrivateKey": "添加一个私钥", "choosePrivateKey": "选择私钥", "plzEnterHost": "请输入主机", - "plzEnterPwd": "请输入密码", + "sureNoPwd": "确认使用无密码?", "plzSelectKey": "请选择私钥", "exampleName": "名称示例", "stop": "停止", diff --git a/lib/view/page/server/detail.dart b/lib/view/page/server/detail.dart index dfb88d6d..c7d04435 100644 --- a/lib/view/page/server/detail.dart +++ b/lib/view/page/server/detail.dart @@ -155,6 +155,7 @@ class _ServerDetailPageState extends State } Widget _buildProgress(double percent) { + if (percent > 100) percent = 100; final pColor = primaryColor; final percentWithinOne = percent / 100; return LinearProgressIndicator( @@ -186,7 +187,7 @@ class _ServerDetailPageState extends State final pColor = primaryColor; final used = ss.memory.used / ss.memory.total; final width = _media.size.width - 17 * 2 - 17 * 2; - const mb = 1024 * 1024; + const mb = 1024; return RoundRectCard(Padding( padding: roundRectCardPadding, child: SizedBox( @@ -329,8 +330,8 @@ class _ServerDetailPageState extends State Icons.device_hub, size: 17, ), + Icon(Icons.arrow_downward, size: 17), Icon(Icons.arrow_upward, size: 17), - Icon(Icons.arrow_downward, size: 17) ], ), ); diff --git a/lib/view/page/server/edit.dart b/lib/view/page/server/edit.dart index 5c3a6980..3aff90cf 100644 --- a/lib/view/page/server/edit.dart +++ b/lib/view/page/server/edit.dart @@ -190,14 +190,28 @@ class _ServerEditPageState extends State with AfterLayoutMixin { ), floatingActionButton: FloatingActionButton( child: const Icon(Icons.send), - onPressed: () { + onPressed: () async { if (ipController.text == '') { showSnackBar(context, Text(s.plzEnterHost)); return; } if (!usePublicKey && passwordController.text == '') { - showSnackBar(context, Text(s.plzEnterPwd)); - return; + final cancel = await showRoundDialog( + context, + s.attention, + Text(s.sureNoPwd), + [ + TextButton( + onPressed: () => Navigator.of(context).pop(false), + child: Text(s.ok)), + TextButton( + onPressed: () => Navigator.of(context).pop(true), + child: Text(s.cancel)) + ], + barrierDismiss: false); + if (cancel ?? true) { + return; + } } if (usePublicKey && _pubKeyIndex == -1) { showSnackBar(context, Text(s.plzSelectKey)); diff --git a/pubspec.yaml b/pubspec.yaml index c7d3a74b..22748417 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -93,6 +93,7 @@ flutter: - assets/linux/arch.png - assets/linux/fedora.png - assets/linux/opensuse.png + - assets/linux/wrt.png # - images/a_dot_burr.jpeg # - images/a_dot_ham.jpeg # An image asset can refer to one or more resolution-specific "variants", see