mirror of
https://github.com/lollipopkit/flutter_server_box.git
synced 2025-12-17 07:14:28 +01:00
#76 new: switch net view
This commit is contained in:
@@ -13,3 +13,19 @@ extension NumX on num {
|
|||||||
return '$finalValue ${suffix[squareTimes]}';
|
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]}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
39
lib/data/model/app/net_view.dart
Normal file
39
lib/data/model/app/net_view.dart
Normal file
@@ -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);
|
||||||
|
}
|
||||||
@@ -28,34 +28,61 @@ class NetSpeed {
|
|||||||
|
|
||||||
BigInt get timeDiff => _now[0].time - _old[0].time;
|
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 (_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 idx = deviceIdx(device);
|
||||||
final speedInBytesPerSecond =
|
return buildStandardOutput(_speedIn(idx));
|
||||||
(_now[idx].bytesIn - _old[idx].bytesIn) / timeDiff;
|
|
||||||
return buildStandardOutput(speedInBytesPerSecond);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String totalIn({String? device}) {
|
String sizeIn({String? device, bool all = false}) {
|
||||||
if (_old[0].device == '' || _now[0].device == '') return '0kb';
|
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 idx = deviceIdx(device);
|
||||||
final totalInBytes = _now[idx].bytesIn;
|
return _sizeIn(idx).convertBytes;
|
||||||
return totalInBytes.toInt().convertBytes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String speedOut({String? device}) {
|
String speedOut({String? device, bool all = false}) {
|
||||||
if (_old[0].device == '' || _now[0].device == '') return '0kb/s';
|
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 idx = deviceIdx(device);
|
||||||
final speedOutBytesPerSecond =
|
return buildStandardOutput(_speedOut(idx));
|
||||||
(_now[idx].bytesOut - _old[idx].bytesOut) / timeDiff;
|
|
||||||
return buildStandardOutput(speedOutBytesPerSecond);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String totalOut({String? device}) {
|
String sizeOut({String? device, bool all = false}) {
|
||||||
if (_old[0].device == '' || _now[0].device == '') return '0kb';
|
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 idx = deviceIdx(device);
|
||||||
final totalOutBytes = _now[idx].bytesOut;
|
return _sizeOut(idx).convertBytes;
|
||||||
return totalOutBytes.toInt().convertBytes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int deviceIdx(String? device) {
|
int deviceIdx(String? device) {
|
||||||
|
|||||||
@@ -57,4 +57,9 @@ class ServerPrivateInfo {
|
|||||||
bool shouldReconnect(ServerPrivateInfo old) {
|
bool shouldReconnect(ServerPrivateInfo old) {
|
||||||
return id != old.id || pwd != old.pwd || pubKeyId != old.pubKeyId;
|
return id != old.id || pwd != old.pwd || pubKeyId != old.pubKeyId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -218,7 +218,7 @@ class ServerProvider extends BusyProvider {
|
|||||||
s.client = await genClient(spi);
|
s.client = await genClient(spi);
|
||||||
final time2 = DateTime.now();
|
final time2 = DateTime.now();
|
||||||
final spentTime = time2.difference(time1).inMilliseconds;
|
final spentTime = time2.difference(time1).inMilliseconds;
|
||||||
_logger.info('Connected to [$sid] in $spentTime ms.');
|
_logger.info('Connected to $sid in $spentTime ms.');
|
||||||
|
|
||||||
// after connected
|
// after connected
|
||||||
s.state = ServerState.connected;
|
s.state = ServerState.connected;
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ class ServerStore extends PersistentStore {
|
|||||||
|
|
||||||
void update(ServerPrivateInfo old, ServerPrivateInfo newInfo) {
|
void update(ServerPrivateInfo old, ServerPrivateInfo newInfo) {
|
||||||
if (!have(old)) {
|
if (!have(old)) {
|
||||||
throw Exception('Old ServerPrivateInfo not found');
|
throw Exception('Old spi: $old not found');
|
||||||
}
|
}
|
||||||
delete(old.id);
|
delete(old.id);
|
||||||
put(newInfo);
|
put(newInfo);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import 'package:toolbox/core/persistant_store.dart';
|
|||||||
import 'package:toolbox/core/utils/platform.dart';
|
import 'package:toolbox/core/utils/platform.dart';
|
||||||
import 'package:toolbox/data/model/ssh/virtual_key.dart';
|
import 'package:toolbox/data/model/ssh/virtual_key.dart';
|
||||||
|
|
||||||
|
import '../model/app/net_view.dart';
|
||||||
import '../res/default.dart';
|
import '../res/default.dart';
|
||||||
|
|
||||||
class SettingStore extends PersistentStore {
|
class SettingStore extends PersistentStore {
|
||||||
@@ -91,4 +92,7 @@ class SettingStore extends PersistentStore {
|
|||||||
|
|
||||||
StoreProperty<List<VirtKey>> get sshVirtKeys =>
|
StoreProperty<List<VirtKey>> get sshVirtKeys =>
|
||||||
property('sshVirtKeys', defaultValue: defaultSSHVirtKeys);
|
property('sshVirtKeys', defaultValue: defaultSSHVirtKeys);
|
||||||
|
|
||||||
|
StoreProperty<NetViewType> get netViewType =>
|
||||||
|
property('netViewType', defaultValue: NetViewType.speed);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,7 +81,6 @@ class _ServerDetailPageState extends State<ServerDetailPage>
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
buildDefaultDragHandles: false,
|
|
||||||
footer: height13,
|
footer: height13,
|
||||||
children: _buildMainList(si.status),
|
children: _buildMainList(si.status),
|
||||||
),
|
),
|
||||||
@@ -378,7 +377,7 @@ class _ServerDetailPageState extends State<ServerDetailPage>
|
|||||||
SizedBox(
|
SizedBox(
|
||||||
width: width,
|
width: width,
|
||||||
child: Text(
|
child: Text(
|
||||||
'${ns.speedIn(device: device)} | ${ns.totalIn(device: device)}',
|
'${ns.speedIn(device: device)} | ${ns.sizeIn(device: device)}',
|
||||||
style: textSize11,
|
style: textSize11,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
textScaleFactor: 0.87,
|
textScaleFactor: 0.87,
|
||||||
@@ -387,7 +386,7 @@ class _ServerDetailPageState extends State<ServerDetailPage>
|
|||||||
SizedBox(
|
SizedBox(
|
||||||
width: width,
|
width: width,
|
||||||
child: Text(
|
child: Text(
|
||||||
'${ns.speedOut(device: device)} | ${ns.totalOut(device: device)}',
|
'${ns.speedOut(device: device)} | ${ns.sizeOut(device: device)}',
|
||||||
style: textSize11,
|
style: textSize11,
|
||||||
textAlign: TextAlign.right,
|
textAlign: TextAlign.right,
|
||||||
textScaleFactor: 0.87,
|
textScaleFactor: 0.87,
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import 'package:nil/nil.dart';
|
|||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:toolbox/core/extension/order.dart';
|
import 'package:toolbox/core/extension/order.dart';
|
||||||
import 'package:toolbox/core/utils/misc.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/model/server/snippet.dart';
|
||||||
import 'package:toolbox/data/provider/snippet.dart';
|
import 'package:toolbox/data/provider/snippet.dart';
|
||||||
import 'package:toolbox/view/page/process.dart';
|
import 'package:toolbox/view/page/process.dart';
|
||||||
@@ -48,6 +49,7 @@ class _ServerPageState extends State<ServerPage>
|
|||||||
late ServerProvider _serverProvider;
|
late ServerProvider _serverProvider;
|
||||||
late SettingStore _settingStore;
|
late SettingStore _settingStore;
|
||||||
late S _s;
|
late S _s;
|
||||||
|
late NetViewType _netViewType;
|
||||||
|
|
||||||
String? _tag;
|
String? _tag;
|
||||||
|
|
||||||
@@ -56,6 +58,7 @@ class _ServerPageState extends State<ServerPage>
|
|||||||
super.initState();
|
super.initState();
|
||||||
_serverProvider = locator<ServerProvider>();
|
_serverProvider = locator<ServerProvider>();
|
||||||
_settingStore = locator<SettingStore>();
|
_settingStore = locator<SettingStore>();
|
||||||
|
_netViewType = _settingStore.netViewType.fetch() ?? NetViewType.speed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -117,7 +120,6 @@ class _ServerPageState extends State<ServerPage>
|
|||||||
all: _s.all,
|
all: _s.all,
|
||||||
),
|
),
|
||||||
padding: const EdgeInsets.fromLTRB(7, 10, 7, 7),
|
padding: const EdgeInsets.fromLTRB(7, 10, 7, 7),
|
||||||
buildDefaultDragHandles: false,
|
|
||||||
onReorder: (oldIndex, newIndex) => setState(() {
|
onReorder: (oldIndex, newIndex) => setState(() {
|
||||||
pro.serverOrder.moveByItem(
|
pro.serverOrder.moveByItem(
|
||||||
filtered,
|
filtered,
|
||||||
@@ -173,7 +175,7 @@ class _ServerPageState extends State<ServerPage>
|
|||||||
children: [
|
children: [
|
||||||
_buildPercentCircle(ss.cpu.usedPercent()),
|
_buildPercentCircle(ss.cpu.usedPercent()),
|
||||||
_buildPercentCircle(ss.mem.usedPercent * 100),
|
_buildPercentCircle(ss.mem.usedPercent * 100),
|
||||||
_buildIOData('Conn:\n${ss.tcp.maxConn}', 'Fail:\n${ss.tcp.fail}'),
|
_buildNet(ss),
|
||||||
_buildIOData(
|
_buildIOData(
|
||||||
'Total:\n${rootDisk.size}', 'Used:\n${rootDisk.usedPercent}%')
|
'Total:\n${rootDisk.size}', 'Used:\n${rootDisk.usedPercent}%')
|
||||||
],
|
],
|
||||||
@@ -330,6 +332,14 @@ class _ServerPageState extends State<ServerPage>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
Widget _buildExplainText(String text) {
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
width: _media.size.width * 0.2,
|
width: _media.size.width * 0.2,
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import 'package:shared_preferences/shared_preferences.dart';
|
|||||||
import 'package:toolbox/core/extension/locale.dart';
|
import 'package:toolbox/core/extension/locale.dart';
|
||||||
import 'package:toolbox/core/extension/navigator.dart';
|
import 'package:toolbox/core/extension/navigator.dart';
|
||||||
import 'package:toolbox/core/route.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/data/model/app/tab.dart';
|
||||||
import 'package:toolbox/view/page/ssh/virt_key_setting.dart';
|
import 'package:toolbox/view/page/ssh/virt_key_setting.dart';
|
||||||
import 'package:toolbox/view/widget/input_field.dart';
|
import 'package:toolbox/view/widget/input_field.dart';
|
||||||
@@ -47,6 +48,7 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
final _editorDarkThemeKey = GlobalKey<PopupMenuButtonState<String>>();
|
final _editorDarkThemeKey = GlobalKey<PopupMenuButtonState<String>>();
|
||||||
final _keyboardTypeKey = GlobalKey<PopupMenuButtonState<int>>();
|
final _keyboardTypeKey = GlobalKey<PopupMenuButtonState<int>>();
|
||||||
final _rotateQuarterKey = GlobalKey<PopupMenuButtonState<int>>();
|
final _rotateQuarterKey = GlobalKey<PopupMenuButtonState<int>>();
|
||||||
|
final _netViewTypeKey = GlobalKey<PopupMenuButtonState<NetViewType>>();
|
||||||
|
|
||||||
late final SettingStore _setting;
|
late final SettingStore _setting;
|
||||||
late final ServerProvider _serverProvider;
|
late final ServerProvider _serverProvider;
|
||||||
@@ -65,6 +67,7 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
final _editorDarkTheme = ValueNotifier('');
|
final _editorDarkTheme = ValueNotifier('');
|
||||||
final _keyboardType = ValueNotifier(0);
|
final _keyboardType = ValueNotifier(0);
|
||||||
final _rotateQuarter = ValueNotifier(0);
|
final _rotateQuarter = ValueNotifier(0);
|
||||||
|
final _netViewType = ValueNotifier(NetViewType.speed);
|
||||||
|
|
||||||
final _pushToken = ValueNotifier<String?>(null);
|
final _pushToken = ValueNotifier<String?>(null);
|
||||||
|
|
||||||
@@ -91,6 +94,7 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
_editorDarkTheme.value = _setting.editorDarkTheme.fetch()!;
|
_editorDarkTheme.value = _setting.editorDarkTheme.fetch()!;
|
||||||
_keyboardType.value = _setting.keyboardType.fetch()!;
|
_keyboardType.value = _setting.keyboardType.fetch()!;
|
||||||
_rotateQuarter.value = _setting.fullScreenRotateQuarter.fetch()!;
|
_rotateQuarter.value = _setting.fullScreenRotateQuarter.fetch()!;
|
||||||
|
_netViewType.value = _setting.netViewType.fetch()!;
|
||||||
SharedPreferences.getInstance().then((value) => _sp = value);
|
SharedPreferences.getInstance().then((value) => _sp = value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,6 +168,7 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
Widget _buildServer() {
|
Widget _buildServer() {
|
||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
|
_buildNetViewType(),
|
||||||
_buildUpdateInterval(),
|
_buildUpdateInterval(),
|
||||||
_buildMaxRetry(),
|
_buildMaxRetry(),
|
||||||
_buildDiskIgnorePath(),
|
_buildDiskIgnorePath(),
|
||||||
@@ -795,7 +800,7 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
'none',
|
'none',
|
||||||
];
|
];
|
||||||
if (names.length != TextInputType.values.length) {
|
if (names.length != TextInputType.values.length) {
|
||||||
throw 'names.length != TextInputType.values.length';
|
throw Exception('names.length != TextInputType.values.length');
|
||||||
}
|
}
|
||||||
final items = TextInputType.values.map(
|
final items = TextInputType.values.map(
|
||||||
(key) {
|
(key) {
|
||||||
@@ -892,4 +897,35 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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<NetViewType>(
|
||||||
|
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();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,7 +71,6 @@ class _SnippetListPageState extends State<SnippetListPage> {
|
|||||||
return ReorderableListView.builder(
|
return ReorderableListView.builder(
|
||||||
padding: const EdgeInsets.all(13),
|
padding: const EdgeInsets.all(13),
|
||||||
itemCount: filtered.length,
|
itemCount: filtered.length,
|
||||||
buildDefaultDragHandles: false,
|
|
||||||
onReorder: (oldIdx, newIdx) => setState(() {
|
onReorder: (oldIdx, newIdx) => setState(() {
|
||||||
provider.snippets.moveByItem(
|
provider.snippets.moveByItem(
|
||||||
filtered,
|
filtered,
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ class _SSHVirtKeySettingPageState extends State<SSHVirtKeySettingPage> {
|
|||||||
final allKeys = [...keys, ...disabled];
|
final allKeys = [...keys, ...disabled];
|
||||||
return ReorderableListView.builder(
|
return ReorderableListView.builder(
|
||||||
padding: const EdgeInsets.fromLTRB(11, 3, 0, 3),
|
padding: const EdgeInsets.fromLTRB(11, 3, 0, 3),
|
||||||
buildDefaultDragHandles: false,
|
|
||||||
itemBuilder: (_, idx) {
|
itemBuilder: (_, idx) {
|
||||||
final key = allKeys[idx];
|
final key = allKeys[idx];
|
||||||
return ListTile(
|
return ListTile(
|
||||||
|
|||||||
Reference in New Issue
Block a user