From 0d5707a1df9ebad3002a08609027906517c5e4c1 Mon Sep 17 00:00:00 2001 From: lollipopkit Date: Fri, 21 Jul 2023 14:25:07 +0800 Subject: [PATCH] #76 new: switch `net` view --- lib/core/extension/numx.dart | 16 ++++++ lib/data/model/app/net_view.dart | 39 +++++++++++++ lib/data/model/server/net_speed.dart | 55 ++++++++++++++----- .../model/server/server_private_info.dart | 5 ++ lib/data/provider/server.dart | 2 +- lib/data/store/server.dart | 2 +- lib/data/store/setting.dart | 4 ++ lib/view/page/server/detail.dart | 5 +- lib/view/page/server/tab.dart | 14 ++++- lib/view/page/setting.dart | 38 ++++++++++++- lib/view/page/snippet/list.dart | 1 - lib/view/page/ssh/virt_key_setting.dart | 1 - 12 files changed, 158 insertions(+), 24 deletions(-) create mode 100644 lib/data/model/app/net_view.dart diff --git a/lib/core/extension/numx.dart b/lib/core/extension/numx.dart index dcb48ec4..efee581c 100644 --- a/lib/core/extension/numx.dart +++ b/lib/core/extension/numx.dart @@ -13,3 +13,19 @@ extension NumX on num { return '$finalValue ${suffix[squareTimes]}'; } } + +extension BigIntX on BigInt { + String get convertBytes { + const suffix = ['B', 'KB', 'MB', 'GB', 'TB']; + double value = toDouble(); + int squareTimes = 0; + for (; value / 1024 > 1 && squareTimes < suffix.length - 1; squareTimes++) { + value /= 1024; + } + var finalValue = value.toStringAsFixed(1); + if (finalValue.endsWith('.0')) { + finalValue = finalValue.replaceFirst('.0', ''); + } + return '$finalValue ${suffix[squareTimes]}'; + } +} diff --git a/lib/data/model/app/net_view.dart b/lib/data/model/app/net_view.dart new file mode 100644 index 00000000..8e95c0d8 --- /dev/null +++ b/lib/data/model/app/net_view.dart @@ -0,0 +1,39 @@ +import 'package:hive_flutter/hive_flutter.dart'; +import 'package:toolbox/data/model/server/server_status.dart'; + +@HiveType(typeId: 5) +enum NetViewType { + @HiveField(0) + count, + @HiveField(1) + speed, + @HiveField(2) + size; + + NetViewData build(ServerStatus ss) { + switch (this) { + case NetViewType.count: + return NetViewData( + 'Conn:\n${ss.tcp.maxConn}', + 'Fail:\n${ss.tcp.fail}', + ); + case NetViewType.speed: + return NetViewData( + 'In:\n${ss.netSpeed.speedIn(all: true)}', + 'Out:\n${ss.netSpeed.speedOut(all: true)}', + ); + case NetViewType.size: + return NetViewData( + 'In:\n${ss.netSpeed.sizeIn(all: true)}', + 'Out:\n${ss.netSpeed.sizeOut(all: true)}', + ); + } + } +} + +class NetViewData { + final String up; + final String down; + + NetViewData(this.up, this.down); +} diff --git a/lib/data/model/server/net_speed.dart b/lib/data/model/server/net_speed.dart index 148b85a5..ce3d7dd9 100644 --- a/lib/data/model/server/net_speed.dart +++ b/lib/data/model/server/net_speed.dart @@ -28,34 +28,61 @@ class NetSpeed { BigInt get timeDiff => _now[0].time - _old[0].time; - String speedIn({String? device}) { + double _speedIn(int i) => (_now[i].bytesIn - _old[i].bytesIn) / timeDiff; + double _speedOut(int i) => (_now[i].bytesOut - _old[i].bytesOut) / timeDiff; + BigInt _sizeIn(int i) => _now[i].bytesIn; + BigInt _sizeOut(int i) => _now[i].bytesOut; + + String speedIn({String? device, bool all = false}) { if (_old[0].device == '' || _now[0].device == '') return '0kb/s'; + if (all) { + var speed = 0.0; + for (var i = 0; i < _now.length; i++) { + speed += _speedIn(i); + } + return buildStandardOutput(speed); + } final idx = deviceIdx(device); - final speedInBytesPerSecond = - (_now[idx].bytesIn - _old[idx].bytesIn) / timeDiff; - return buildStandardOutput(speedInBytesPerSecond); + return buildStandardOutput(_speedIn(idx)); } - String totalIn({String? device}) { + String sizeIn({String? device, bool all = false}) { if (_old[0].device == '' || _now[0].device == '') return '0kb'; + if (all) { + var size = BigInt.from(0); + for (var i = 0; i < _now.length; i++) { + size += _sizeIn(i); + } + return size.convertBytes; + } final idx = deviceIdx(device); - final totalInBytes = _now[idx].bytesIn; - return totalInBytes.toInt().convertBytes; + return _sizeIn(idx).convertBytes; } - String speedOut({String? device}) { + String speedOut({String? device, bool all = false}) { if (_old[0].device == '' || _now[0].device == '') return '0kb/s'; + if (all) { + var speed = 0.0; + for (var i = 0; i < _now.length; i++) { + speed += _speedOut(i); + } + return buildStandardOutput(speed); + } final idx = deviceIdx(device); - final speedOutBytesPerSecond = - (_now[idx].bytesOut - _old[idx].bytesOut) / timeDiff; - return buildStandardOutput(speedOutBytesPerSecond); + return buildStandardOutput(_speedOut(idx)); } - String totalOut({String? device}) { + String sizeOut({String? device, bool all = false}) { if (_old[0].device == '' || _now[0].device == '') return '0kb'; + if (all) { + var size = BigInt.from(0); + for (var i = 0; i < _now.length; i++) { + size += _sizeOut(i); + } + return size.convertBytes; + } final idx = deviceIdx(device); - final totalOutBytes = _now[idx].bytesOut; - return totalOutBytes.toInt().convertBytes; + return _sizeOut(idx).convertBytes; } int deviceIdx(String? device) { diff --git a/lib/data/model/server/server_private_info.dart b/lib/data/model/server/server_private_info.dart index 33e52b80..54232bf1 100644 --- a/lib/data/model/server/server_private_info.dart +++ b/lib/data/model/server/server_private_info.dart @@ -57,4 +57,9 @@ class ServerPrivateInfo { bool shouldReconnect(ServerPrivateInfo old) { return id != old.id || pwd != old.pwd || pubKeyId != old.pubKeyId; } + + @override + String toString() { + return id; + } } diff --git a/lib/data/provider/server.dart b/lib/data/provider/server.dart index 2e304b3c..eb33d151 100644 --- a/lib/data/provider/server.dart +++ b/lib/data/provider/server.dart @@ -218,7 +218,7 @@ class ServerProvider extends BusyProvider { s.client = await genClient(spi); final time2 = DateTime.now(); final spentTime = time2.difference(time1).inMilliseconds; - _logger.info('Connected to [$sid] in $spentTime ms.'); + _logger.info('Connected to $sid in $spentTime ms.'); // after connected s.state = ServerState.connected; diff --git a/lib/data/store/server.dart b/lib/data/store/server.dart index bb6725e8..028adb21 100644 --- a/lib/data/store/server.dart +++ b/lib/data/store/server.dart @@ -24,7 +24,7 @@ class ServerStore extends PersistentStore { void update(ServerPrivateInfo old, ServerPrivateInfo newInfo) { if (!have(old)) { - throw Exception('Old ServerPrivateInfo not found'); + throw Exception('Old spi: $old not found'); } delete(old.id); put(newInfo); diff --git a/lib/data/store/setting.dart b/lib/data/store/setting.dart index 1fa27ffb..d2ce1c5a 100644 --- a/lib/data/store/setting.dart +++ b/lib/data/store/setting.dart @@ -3,6 +3,7 @@ import 'package:toolbox/core/persistant_store.dart'; import 'package:toolbox/core/utils/platform.dart'; import 'package:toolbox/data/model/ssh/virtual_key.dart'; +import '../model/app/net_view.dart'; import '../res/default.dart'; class SettingStore extends PersistentStore { @@ -91,4 +92,7 @@ class SettingStore extends PersistentStore { StoreProperty> get sshVirtKeys => property('sshVirtKeys', defaultValue: defaultSSHVirtKeys); + + StoreProperty get netViewType => + property('netViewType', defaultValue: NetViewType.speed); } diff --git a/lib/view/page/server/detail.dart b/lib/view/page/server/detail.dart index d8173673..f8578d11 100644 --- a/lib/view/page/server/detail.dart +++ b/lib/view/page/server/detail.dart @@ -81,7 +81,6 @@ class _ServerDetailPageState extends State ); }); }, - buildDefaultDragHandles: false, footer: height13, children: _buildMainList(si.status), ), @@ -378,7 +377,7 @@ class _ServerDetailPageState extends State SizedBox( width: width, child: Text( - '${ns.speedIn(device: device)} | ${ns.totalIn(device: device)}', + '${ns.speedIn(device: device)} | ${ns.sizeIn(device: device)}', style: textSize11, textAlign: TextAlign.center, textScaleFactor: 0.87, @@ -387,7 +386,7 @@ class _ServerDetailPageState extends State SizedBox( width: width, child: Text( - '${ns.speedOut(device: device)} | ${ns.totalOut(device: device)}', + '${ns.speedOut(device: device)} | ${ns.sizeOut(device: device)}', style: textSize11, textAlign: TextAlign.right, textScaleFactor: 0.87, diff --git a/lib/view/page/server/tab.dart b/lib/view/page/server/tab.dart index ed5ac841..d463721c 100644 --- a/lib/view/page/server/tab.dart +++ b/lib/view/page/server/tab.dart @@ -7,6 +7,7 @@ import 'package:nil/nil.dart'; import 'package:provider/provider.dart'; import 'package:toolbox/core/extension/order.dart'; import 'package:toolbox/core/utils/misc.dart'; +import 'package:toolbox/data/model/app/net_view.dart'; import 'package:toolbox/data/model/server/snippet.dart'; import 'package:toolbox/data/provider/snippet.dart'; import 'package:toolbox/view/page/process.dart'; @@ -48,6 +49,7 @@ class _ServerPageState extends State late ServerProvider _serverProvider; late SettingStore _settingStore; late S _s; + late NetViewType _netViewType; String? _tag; @@ -56,6 +58,7 @@ class _ServerPageState extends State super.initState(); _serverProvider = locator(); _settingStore = locator(); + _netViewType = _settingStore.netViewType.fetch() ?? NetViewType.speed; } @override @@ -117,7 +120,6 @@ class _ServerPageState extends State all: _s.all, ), padding: const EdgeInsets.fromLTRB(7, 10, 7, 7), - buildDefaultDragHandles: false, onReorder: (oldIndex, newIndex) => setState(() { pro.serverOrder.moveByItem( filtered, @@ -173,7 +175,7 @@ class _ServerPageState extends State children: [ _buildPercentCircle(ss.cpu.usedPercent()), _buildPercentCircle(ss.mem.usedPercent * 100), - _buildIOData('Conn:\n${ss.tcp.maxConn}', 'Fail:\n${ss.tcp.fail}'), + _buildNet(ss), _buildIOData( 'Total:\n${rootDisk.size}', 'Used:\n${rootDisk.usedPercent}%') ], @@ -330,6 +332,14 @@ class _ServerPageState extends State ); } + Widget _buildNet(ServerStatus ss) { + final data = _netViewType.build(ss); + return AnimatedSwitcher( + duration: const Duration(milliseconds: 177), + child: _buildIOData(data.up, data.down), + ); + } + Widget _buildExplainText(String text) { return SizedBox( width: _media.size.width * 0.2, diff --git a/lib/view/page/setting.dart b/lib/view/page/setting.dart index 5e3ad318..ac59abe3 100644 --- a/lib/view/page/setting.dart +++ b/lib/view/page/setting.dart @@ -10,6 +10,7 @@ import 'package:shared_preferences/shared_preferences.dart'; import 'package:toolbox/core/extension/locale.dart'; import 'package:toolbox/core/extension/navigator.dart'; import 'package:toolbox/core/route.dart'; +import 'package:toolbox/data/model/app/net_view.dart'; import 'package:toolbox/data/model/app/tab.dart'; import 'package:toolbox/view/page/ssh/virt_key_setting.dart'; import 'package:toolbox/view/widget/input_field.dart'; @@ -47,6 +48,7 @@ class _SettingPageState extends State { final _editorDarkThemeKey = GlobalKey>(); final _keyboardTypeKey = GlobalKey>(); final _rotateQuarterKey = GlobalKey>(); + final _netViewTypeKey = GlobalKey>(); late final SettingStore _setting; late final ServerProvider _serverProvider; @@ -65,6 +67,7 @@ class _SettingPageState extends State { final _editorDarkTheme = ValueNotifier(''); final _keyboardType = ValueNotifier(0); final _rotateQuarter = ValueNotifier(0); + final _netViewType = ValueNotifier(NetViewType.speed); final _pushToken = ValueNotifier(null); @@ -91,6 +94,7 @@ class _SettingPageState extends State { _editorDarkTheme.value = _setting.editorDarkTheme.fetch()!; _keyboardType.value = _setting.keyboardType.fetch()!; _rotateQuarter.value = _setting.fullScreenRotateQuarter.fetch()!; + _netViewType.value = _setting.netViewType.fetch()!; SharedPreferences.getInstance().then((value) => _sp = value); } @@ -164,6 +168,7 @@ class _SettingPageState extends State { Widget _buildServer() { return Column( children: [ + _buildNetViewType(), _buildUpdateInterval(), _buildMaxRetry(), _buildDiskIgnorePath(), @@ -795,7 +800,7 @@ class _SettingPageState extends State { 'none', ]; if (names.length != TextInputType.values.length) { - throw 'names.length != TextInputType.values.length'; + throw Exception('names.length != TextInputType.values.length'); } final items = TextInputType.values.map( (key) { @@ -892,4 +897,35 @@ class _SettingPageState extends State { }, ); } + + Widget _buildNetViewType() { + final items = NetViewType.values + .map((e) => PopupMenuItem( + value: e, + child: Text(e.name), + )) + .toList(); + return ListTile( + title: Text('net view type'), + trailing: ValueBuilder( + listenable: _netViewType, + build: () => PopupMenuButton( + key: _netViewTypeKey, + itemBuilder: (BuildContext context) => items, + initialValue: _netViewType.value, + onSelected: (idx) { + _netViewType.value = idx; + _setting.netViewType.put(idx); + }, + child: Text( + _netViewType.value.name, + style: textSize15, + ), + ), + ), + onTap: () { + _keyboardTypeKey.currentState?.showButtonMenu(); + }, + ); + } } diff --git a/lib/view/page/snippet/list.dart b/lib/view/page/snippet/list.dart index 3093a887..ede4d2ca 100644 --- a/lib/view/page/snippet/list.dart +++ b/lib/view/page/snippet/list.dart @@ -71,7 +71,6 @@ class _SnippetListPageState extends State { return ReorderableListView.builder( padding: const EdgeInsets.all(13), itemCount: filtered.length, - buildDefaultDragHandles: false, onReorder: (oldIdx, newIdx) => setState(() { provider.snippets.moveByItem( filtered, diff --git a/lib/view/page/ssh/virt_key_setting.dart b/lib/view/page/ssh/virt_key_setting.dart index 0a715d26..98bf2242 100644 --- a/lib/view/page/ssh/virt_key_setting.dart +++ b/lib/view/page/ssh/virt_key_setting.dart @@ -43,7 +43,6 @@ class _SSHVirtKeySettingPageState extends State { final allKeys = [...keys, ...disabled]; return ReorderableListView.builder( padding: const EdgeInsets.fromLTRB(11, 3, 0, 3), - buildDefaultDragHandles: false, itemBuilder: (_, idx) { final key = allKeys[idx]; return ListTile(