From 00fdcb1ee82d66f8a3dd680b3ca1323a52c84887 Mon Sep 17 00:00:00 2001 From: lollipopkit Date: Fri, 26 May 2023 18:03:43 +0800 Subject: [PATCH] Server detail page cards support sorting --- lib/core/extension/order.dart | 22 ++++++ lib/data/model/ssh/virtual_key.dart | 9 ++- lib/data/provider/server.dart | 23 +----- lib/data/res/misc.dart | 11 +++ lib/data/store/setting.dart | 9 ++- lib/view/page/server/detail.dart | 118 +++++++++++++++++----------- lib/view/page/server/tab.dart | 7 +- 7 files changed, 128 insertions(+), 71 deletions(-) create mode 100644 lib/core/extension/order.dart diff --git a/lib/core/extension/order.dart b/lib/core/extension/order.dart new file mode 100644 index 00000000..baa5a957 --- /dev/null +++ b/lib/core/extension/order.dart @@ -0,0 +1,22 @@ +import 'package:toolbox/core/persistant_store.dart'; + +typedef StringOrder = List; + +extension StringOrderX on StringOrder { + void move(int oldIndex, int newIndex, StoreProperty property) { + if (oldIndex == newIndex) return; + if (oldIndex < newIndex) { + newIndex -= 1; + } + final item = this[oldIndex]; + removeAt(oldIndex); + insert(newIndex, item); + property.put(this); + } + + void update(String id, String newId) { + final index = indexOf(id); + if (index == -1) return; + this[index] = newId; + } +} diff --git a/lib/data/model/ssh/virtual_key.dart b/lib/data/model/ssh/virtual_key.dart index dd19ebce..876cc81b 100644 --- a/lib/data/model/ssh/virtual_key.dart +++ b/lib/data/model/ssh/virtual_key.dart @@ -8,8 +8,13 @@ class VirtualKey { final IconData? icon; final VirtualKeyFunc? func; - VirtualKey(this.text, - {this.key, this.toggleable = false, this.icon, this.func,}); + VirtualKey( + this.text, { + this.key, + this.toggleable = false, + this.icon, + this.func, + }); } enum VirtualKeyFunc { toggleIME, backspace, copy, paste, snippet } diff --git a/lib/data/provider/server.dart b/lib/data/provider/server.dart index 0f76cef9..e9c08fce 100644 --- a/lib/data/provider/server.dart +++ b/lib/data/provider/server.dart @@ -3,6 +3,7 @@ import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:logging/logging.dart'; +import '../../core/extension/order.dart'; import '../../core/extension/uint8list.dart'; import '../../core/provider_base.dart'; import '../../core/utils/server.dart'; @@ -18,31 +19,11 @@ import '../store/server.dart'; import '../store/setting.dart'; typedef ServersMap = Map; -typedef ServerOrder = List; - -extension ServerOrderX on ServerOrder { - void move(int oldIndex, int newIndex) { - if (oldIndex == newIndex) return; - if (oldIndex < newIndex) { - newIndex -= 1; - } - final item = this[oldIndex]; - removeAt(oldIndex); - insert(newIndex, item); - locator().serverOrder.put(this); - } - - void update(String id, String newId) { - final index = indexOf(id); - if (index == -1) return; - this[index] = newId; - } -} class ServerProvider extends BusyProvider { final ServersMap _servers = {}; ServersMap get servers => _servers; - final ServerOrder serverOrder = []; + final StringOrder serverOrder = []; final _limiter = TryLimiter(); diff --git a/lib/data/res/misc.dart b/lib/data/res/misc.dart index 5f13d7a3..0c421bf0 100644 --- a/lib/data/res/misc.dart +++ b/lib/data/res/misc.dart @@ -12,3 +12,14 @@ const maxDebugLogLines = 100; /// Method Channels const pkgName = 'tech.lolli.toolbox'; const bgRunChannel = MethodChannel('$pkgName/app_retain'); + +// default server details page cards order +const defaultDetailCardOrder = [ + 'uptime', + 'cpu', + 'mem', + 'swap', + 'disk', + 'net', + 'temp' +]; diff --git a/lib/data/store/setting.dart b/lib/data/store/setting.dart index 60ca0ff0..3ae8900c 100644 --- a/lib/data/store/setting.dart +++ b/lib/data/store/setting.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:toolbox/core/persistant_store.dart'; import 'package:toolbox/core/utils/platform.dart'; +import 'package:toolbox/data/res/misc.dart'; class SettingStore extends PersistentStore { StoreProperty get primaryColor => property( @@ -42,11 +43,15 @@ class SettingStore extends PersistentStore { /// Backgroud running (Android) StoreProperty get bgRun => property('bgRun', defaultValue: isAndroid); - // Server order + /// Server order StoreProperty> get serverOrder => property('serverOrder', defaultValue: null); - // SSH term font size + /// Server details page cards order + StoreProperty> get detailCardOrder => + property('detailCardPrder', defaultValue: defaultDetailCardOrder); + + /// SSH term font size StoreProperty get termFontSize => property('termFontSize', defaultValue: 13); diff --git a/lib/view/page/server/detail.dart b/lib/view/page/server/detail.dart index 23d7e40d..47af18ac 100644 --- a/lib/view/page/server/detail.dart +++ b/lib/view/page/server/detail.dart @@ -1,9 +1,15 @@ import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:provider/provider.dart'; +import 'package:toolbox/core/extension/order.dart'; +import 'package:toolbox/data/model/server/cpu_status.dart'; +import 'package:toolbox/data/model/server/disk_info.dart'; +import 'package:toolbox/data/model/server/dist.dart'; +import 'package:toolbox/data/model/server/memory.dart'; +import 'package:toolbox/data/model/server/temp.dart'; +import 'package:toolbox/data/res/misc.dart'; import '../../../core/extension/numx.dart'; -import '../../../data/model/server/dist.dart'; import '../../../data/model/server/net_speed.dart'; import '../../../data/model/server/server.dart'; import '../../../data/model/server/server_status.dart'; @@ -27,6 +33,7 @@ class _ServerDetailPageState extends State with SingleTickerProviderStateMixin { late MediaQueryData _media; late S _s; + late List _cardsOrder; final _setting = locator(); @override @@ -36,6 +43,12 @@ class _ServerDetailPageState extends State _s = S.of(context)!; } + @override + void initState() { + super.initState(); + _cardsOrder = _setting.detailCardOrder.fetch()!; + } + @override Widget build(BuildContext context) { return Consumer(builder: (_, provider, __) { @@ -56,24 +69,39 @@ class _ServerDetailPageState extends State appBar: AppBar( title: Text(si.spi.name, style: textSize18), ), - body: ListView( - padding: const EdgeInsets.all(13), - children: [ - _buildLinuxIcon(si.status.sysVer), - _buildUpTimeAndSys(si.status), - _buildCPUView(si.status), - _buildMemView(si.status), - _buildSwapView(si.status), - _buildDiskView(si.status), - _buildNetView(si.status.netSpeed), - _buildTemperature(si.status), - // height of navigation bar - SizedBox(height: _media.padding.bottom), - ], + body: ReorderableListView( + padding: EdgeInsets.only( + left: 13, right: 13, top: 13, bottom: _media.padding.bottom), + onReorder: (int oldIndex, int newIndex) { + setState(() { + _cardsOrder.move(oldIndex, newIndex, _setting.detailCardOrder); + }); + }, + header: _buildLinuxIcon(si.status.sysVer), + footer: height13, + children: _buildMainList(si.status), ), ); } + List _buildMainList(ServerStatus ss) { + final map = Map.fromIterables( + defaultDetailCardOrder, + [ + _buildUpTimeAndSys(ss.sysVer, ss.uptime), + _buildCPUView(ss.cpu), + _buildMemView(ss.mem), + _buildSwapView(ss.swap), + _buildDiskView(ss.disk), + _buildNetView(ss.netSpeed), + _buildTemperature(ss.temps), + ], + ); + return _cardsOrder + .map((e) => SizedBox(key: ValueKey(e), child: map[e])) + .toList(); + } + Widget _buildLinuxIcon(String sysVer) { if (!_setting.showDistLogo.fetch()!) return placeholder; final iconPath = sysVer.dist?.iconPath; @@ -90,7 +118,7 @@ class _ServerDetailPageState extends State ); } - Widget _buildCPUView(ServerStatus ss) { + Widget _buildCPUView(CpuStatus cs) { return RoundRectCard( Padding( padding: roundRectCardPadding, @@ -99,25 +127,25 @@ class _ServerDetailPageState extends State mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( - '${ss.cpu.usedPercent(coreIdx: 0).toInt()}%', + '${cs.usedPercent(coreIdx: 0).toInt()}%', style: textSize27, textScaleFactor: 1.0, ), Row( children: [ - _buildDetailPercent(ss.cpu.user, 'user'), + _buildDetailPercent(cs.user, 'user'), width13, - _buildDetailPercent(ss.cpu.sys, 'sys'), + _buildDetailPercent(cs.sys, 'sys'), width13, - _buildDetailPercent(ss.cpu.iowait, 'io'), + _buildDetailPercent(cs.iowait, 'io'), width13, - _buildDetailPercent(ss.cpu.idle, 'idle') + _buildDetailPercent(cs.idle, 'idle') ], ) ], ), height13, - _buildCPUProgress(ss) + _buildCPUProgress(cs) ]), ), ); @@ -143,14 +171,14 @@ class _ServerDetailPageState extends State ); } - Widget _buildCPUProgress(ServerStatus ss) { + Widget _buildCPUProgress(CpuStatus cs) { final children = []; - for (var i = 0; i < ss.cpu.coresCount; i++) { + for (var i = 0; i < cs.coresCount; i++) { if (i == 0) continue; children.add( Padding( padding: const EdgeInsets.all(2), - child: _buildProgress(ss.cpu.usedPercent(coreIdx: i)), + child: _buildProgress(cs.usedPercent(coreIdx: i)), ), ); } @@ -168,16 +196,16 @@ class _ServerDetailPageState extends State ); } - Widget _buildUpTimeAndSys(ServerStatus ss) { + Widget _buildUpTimeAndSys(String sysVer, String uptime) { return RoundRectCard( Padding( padding: roundRectCardPadding, child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text(ss.sysVer, style: textSize11, textScaleFactor: 1.0), + Text(sysVer, style: textSize11, textScaleFactor: 1.0), Text( - ss.uptime, + uptime, style: textSize11, textScaleFactor: 1.0, ), @@ -187,10 +215,10 @@ class _ServerDetailPageState extends State ); } - Widget _buildMemView(ServerStatus ss) { - final free = ss.mem.free / ss.mem.total * 100; - final avail = ss.mem.availPercent * 100; - final used = ss.mem.usedPercent * 100; + Widget _buildMemView(Memory mem) { + final free = mem.free / mem.total * 100; + final avail = mem.availPercent * 100; + final used = mem.usedPercent * 100; return RoundRectCard( Padding( @@ -206,7 +234,7 @@ class _ServerDetailPageState extends State children: [ Text('${used.toStringAsFixed(0)}%', style: textSize27), width7, - Text('of ${(ss.mem.total * 1024).convertBytes}', + Text('of ${(mem.total * 1024).convertBytes}', style: textSize13Grey) ], ), @@ -227,10 +255,10 @@ class _ServerDetailPageState extends State ); } - Widget _buildSwapView(ServerStatus ss) { - if (ss.swap.total == 0) return placeholder; - final used = ss.swap.usedPercent * 100; - final cached = ss.swap.cached / ss.swap.total * 100; + Widget _buildSwapView(Swap swap) { + if (swap.total == 0) return placeholder; + final used = swap.usedPercent * 100; + final cached = swap.cached / swap.total * 100; return RoundRectCard( Padding( padding: roundRectCardPadding, @@ -245,7 +273,7 @@ class _ServerDetailPageState extends State children: [ Text('${used.toStringAsFixed(0)}%', style: textSize27), width7, - Text('of ${(ss.swap.total * 1024).convertBytes} ', + Text('of ${(swap.total * 1024).convertBytes} ', style: textSize13Grey) ], ), @@ -260,14 +288,14 @@ class _ServerDetailPageState extends State ); } - Widget _buildDiskView(ServerStatus ss) { - ss.disk.removeWhere((e) { + Widget _buildDiskView(List disk) { + disk.removeWhere((e) { for (final ingorePath in _setting.diskIgnorePath.fetch()!) { if (e.path.startsWith(ingorePath)) return true; } return false; }); - final children = ss.disk + final children = disk .map((disk) => Padding( padding: const EdgeInsets.symmetric(vertical: 3), child: Column( @@ -380,8 +408,8 @@ class _ServerDetailPageState extends State ); } - Widget _buildTemperature(ServerStatus ss) { - if (ss.temps.isEmpty) { + Widget _buildTemperature(Temperatures temps) { + if (temps.isEmpty) { return placeholder; } final List children = [ @@ -397,7 +425,7 @@ class _ServerDetailPageState extends State child: Divider(height: 7), ), ]; - children.addAll(ss.temps.devices.map((key) => Row( + children.addAll(temps.devices.map((key) => Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( @@ -406,7 +434,7 @@ class _ServerDetailPageState extends State textScaleFactor: 1.0, ), Text( - '${ss.temps.get(key)}°C', + '${temps.get(key)}°C', style: textSize11, textScaleFactor: 1.0, ), diff --git a/lib/view/page/server/tab.dart b/lib/view/page/server/tab.dart index 59ddf9aa..052610a3 100644 --- a/lib/view/page/server/tab.dart +++ b/lib/view/page/server/tab.dart @@ -5,6 +5,7 @@ import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:get_it/get_it.dart'; import 'package:provider/provider.dart'; import 'package:toolbox/core/extension/navigator.dart'; +import 'package:toolbox/core/extension/order.dart'; import 'package:toolbox/core/utils/misc.dart'; import '../../../core/route.dart'; @@ -94,7 +95,11 @@ class _ServerPageState extends State padding: const EdgeInsets.fromLTRB(7, 10, 7, 7), physics: const AlwaysScrollableScrollPhysics(), onReorder: (oldIndex, newIndex) => setState(() { - pro.serverOrder.move(oldIndex, newIndex); + pro.serverOrder.move( + oldIndex, + newIndex, + _settingStore.serverOrder, + ); }), children: pro.serverOrder .where((e) => pro.servers.containsKey(e))