new: VersionRelated

This commit is contained in:
lollipopkit
2024-03-20 20:26:22 -06:00
parent d5ce11c788
commit fae3a20a9e
12 changed files with 166 additions and 95 deletions

View File

@@ -21,29 +21,27 @@ enum ServerFuncBtn {
snippet, snippet,
@HiveField(6) @HiveField(6)
iperf, iperf,
@HiveField(7) // @HiveField(7)
pve, // pve,
; ;
static const defaultFuncs = [ static final defaultIdxs = [
terminal, terminal,
sftp, sftp,
container, container,
process, process,
pkg, pkg,
snippet, snippet,
pve, ].map((e) => e.index).toList();
];
Icon get icon => switch (this) { Icon icon([double? sizeDiff]) => switch (this) {
sftp => const Icon(Icons.insert_drive_file, size: 15), sftp => Icon(Icons.insert_drive_file, size: 15 + (sizeDiff ?? 0)),
snippet => const Icon(Icons.code, size: 15), snippet => Icon(Icons.code, size: 15 + (sizeDiff ?? 0)),
pkg => const Icon(Icons.system_security_update, size: 15), pkg => Icon(Icons.system_security_update, size: 15 + (sizeDiff ?? 0)),
container => const Icon(FontAwesome.docker_brand, size: 14), container => Icon(FontAwesome.docker_brand, size: 14 + (sizeDiff ?? 0)),
process => const Icon(Icons.list_alt_outlined, size: 15), process => Icon(Icons.list_alt_outlined, size: 15 + (sizeDiff ?? 0)),
terminal => const Icon(Icons.terminal, size: 15), terminal => Icon(Icons.terminal, size: 15 + (sizeDiff ?? 0)),
iperf => const Icon(Icons.speed, size: 15), iperf => Icon(Icons.speed, size: 15 + (sizeDiff ?? 0)),
pve => const Icon(FontAwesome.server_solid, size: 13),
}; };
String get toStr => switch (this) { String get toStr => switch (this) {
@@ -54,10 +52,5 @@ enum ServerFuncBtn {
process => l10n.process, process => l10n.process,
terminal => l10n.terminal, terminal => l10n.terminal,
iperf => 'iperf', iperf => 'iperf',
pve => 'PVE',
}; };
int toJson() => index;
static ServerFuncBtn fromJson(int i) => values[i];
} }

View File

@@ -27,8 +27,6 @@ class ServerFuncBtnAdapter extends TypeAdapter<ServerFuncBtn> {
return ServerFuncBtn.snippet; return ServerFuncBtn.snippet;
case 6: case 6:
return ServerFuncBtn.iperf; return ServerFuncBtn.iperf;
case 7:
return ServerFuncBtn.pve;
default: default:
return ServerFuncBtn.terminal; return ServerFuncBtn.terminal;
} }
@@ -58,9 +56,6 @@ class ServerFuncBtnAdapter extends TypeAdapter<ServerFuncBtn> {
case ServerFuncBtn.iperf: case ServerFuncBtn.iperf:
writer.writeByte(6); writer.writeByte(6);
break; break;
case ServerFuncBtn.pve:
writer.writeByte(7);
break;
} }
} }

View File

@@ -0,0 +1,56 @@
import 'package:toolbox/core/extension/context/locale.dart';
import 'package:toolbox/core/extension/listx.dart';
import 'package:toolbox/data/model/app/version_related.dart';
import 'package:toolbox/data/res/store.dart';
enum ServerDetailCards implements VersionRelated {
about,
cpu,
mem,
swap,
gpu,
disk,
net,
sensor,
temp,
battery,
pve(sinceBuild: 818),
;
@override
final int? sinceBuild;
const ServerDetailCards({this.sinceBuild});
static ServerDetailCards? fromName(String str) =>
ServerDetailCards.values.firstWhereOrNull((e) => e.name == str);
static final names = values.map((e) => e.name).toList();
String get toStr => switch (this) {
about => l10n.about,
cpu => 'CPU',
mem => 'RAM',
swap => 'Swap',
gpu => 'GPU',
disk => l10n.disk,
net => l10n.net,
sensor => l10n.sensors,
temp => l10n.temperature,
battery => l10n.battery,
pve => 'PVE',
};
/// If:
/// Version 1 => user set [about], default is [about, cpu]
/// Version 2 => default is [about, cpu, mem] => auto add [mem] to user's setting
static void autoAddNewCards(int cur) {
if (cur >= pve.sinceBuild!) {
final prop = Stores.setting.detailCardOrder;
final list = prop.fetch();
if (list.contains(pve.name)) return;
list.add(pve.name);
prop.put(list);
}
}
}

View File

@@ -0,0 +1,9 @@
import 'package:toolbox/data/model/app/server_detail_card.dart';
abstract interface class VersionRelated {
int? get sinceBuild;
static final funcs = <void Function(int cur)>[
ServerDetailCards.autoAddNewCards,
];
}

View File

@@ -54,6 +54,23 @@ enum VirtKey {
} }
} }
static final defaultOrder = [
VirtKey.esc,
VirtKey.alt,
VirtKey.home,
VirtKey.up,
VirtKey.end,
VirtKey.sftp,
VirtKey.snippet,
VirtKey.tab,
VirtKey.ctrl,
VirtKey.left,
VirtKey.down,
VirtKey.right,
VirtKey.clipboard,
VirtKey.ime,
];
TerminalKey? get key { TerminalKey? get key {
switch (this) { switch (this) {
case VirtKey.esc: case VirtKey.esc:

View File

@@ -1,39 +1,7 @@
import 'dart:ui'; import 'dart:ui';
import 'package:toolbox/data/model/ssh/virtual_key.dart';
abstract final class Defaults { abstract final class Defaults {
// default server details page cards order
static const detailCardOrder = [
'about',
'cpu',
'mem',
'swap',
'gpu',
'disk',
'net',
'sensor',
'temp',
'battery'
];
static const sshVirtKeys = [
VirtKey.esc,
VirtKey.alt,
VirtKey.home,
VirtKey.up,
VirtKey.end,
VirtKey.sftp,
VirtKey.snippet,
VirtKey.tab,
VirtKey.ctrl,
VirtKey.left,
VirtKey.down,
VirtKey.right,
VirtKey.clipboard,
VirtKey.ime,
];
static const primaryColor = Color.fromARGB(255, 145, 58, 31); static const primaryColor = Color.fromARGB(255, 145, 58, 31);
static const launchPageIdx = 0; static const launchPageIdx = 0;

View File

@@ -1,6 +1,8 @@
import 'package:toolbox/core/persistant_store.dart'; import 'package:toolbox/core/persistant_store.dart';
import 'package:toolbox/core/utils/platform/base.dart'; import 'package:toolbox/core/utils/platform/base.dart';
import 'package:toolbox/data/model/app/menu/server_func.dart'; import 'package:toolbox/data/model/app/menu/server_func.dart';
import 'package:toolbox/data/model/app/server_detail_card.dart';
import 'package:toolbox/data/model/ssh/virtual_key.dart';
import '../model/app/net_view.dart'; import '../model/app/net_view.dart';
import '../res/default.dart'; import '../res/default.dart';
@@ -82,8 +84,10 @@ class SettingStore extends PersistentStore {
late final snippetOrder = listProperty<String>('snippetOrder', []); late final snippetOrder = listProperty<String>('snippetOrder', []);
// Server details page cards order // Server details page cards order
late final detailCardOrder = late final detailCardOrder = listProperty(
listProperty('detailCardOrder', Defaults.detailCardOrder); 'detailCardOrder',
ServerDetailCards.values.map((e) => e.name).toList(),
);
// SSH term font size // SSH term font size
late final termFontSize = property('termFontSize', 13.0); late final termFontSize = property('termFontSize', 13.0);
@@ -129,7 +133,7 @@ class SettingStore extends PersistentStore {
late final sshVirtKeys = listProperty( late final sshVirtKeys = listProperty(
'sshVirtKeys', 'sshVirtKeys',
Defaults.sshVirtKeys.map((e) => e.index).toList(), VirtKey.defaultOrder.map((e) => e.index).toList(),
); );
late final netViewType = property( late final netViewType = property(
@@ -203,14 +207,7 @@ class SettingStore extends PersistentStore {
late final serverFuncBtns = listProperty( late final serverFuncBtns = listProperty(
'serverBtns', 'serverBtns',
[ ServerFuncBtn.defaultIdxs,
ServerFuncBtn.terminal,
ServerFuncBtn.sftp,
ServerFuncBtn.container,
ServerFuncBtn.process,
ServerFuncBtn.pkg,
ServerFuncBtn.snippet,
].map((e) => e.index).toList(),
); );
/// Docker is more popular than podman, set to `false` to use docker /// Docker is more popular than podman, set to `false` to use docker
@@ -257,6 +254,8 @@ class SettingStore extends PersistentStore {
/// Set it to true, if you use Safe Keyboard on Chinese Android /// Set it to true, if you use Safe Keyboard on Chinese Android
late final cnKeyboardComp = property('cnKeyboardComp', false); late final cnKeyboardComp = property('cnKeyboardComp', false);
late final lastVer = property('lastVer', 0);
// Never show these settings for users // Never show these settings for users
// //
// ------BEGIN------ // ------BEGIN------

View File

@@ -15,7 +15,9 @@ import 'package:toolbox/core/utils/platform/base.dart';
import 'package:toolbox/core/utils/sync/webdav.dart'; import 'package:toolbox/core/utils/sync/webdav.dart';
import 'package:toolbox/core/utils/ui.dart'; import 'package:toolbox/core/utils/ui.dart';
import 'package:toolbox/data/model/app/menu/server_func.dart'; import 'package:toolbox/data/model/app/menu/server_func.dart';
import 'package:toolbox/data/model/app/version_related.dart';
import 'package:toolbox/data/model/server/custom.dart'; import 'package:toolbox/data/model/server/custom.dart';
import 'package:toolbox/data/res/build_data.dart';
import 'package:toolbox/data/res/logger.dart'; import 'package:toolbox/data/res/logger.dart';
import 'package:toolbox/data/res/provider.dart'; import 'package:toolbox/data/res/provider.dart';
import 'package:toolbox/data/res/store.dart'; import 'package:toolbox/data/res/store.dart';
@@ -102,6 +104,8 @@ Future<void> _initApp() async {
if (Stores.setting.icloudSync.fetch()) ICloud.sync(); if (Stores.setting.icloudSync.fetch()) ICloud.sync();
} }
if (Stores.setting.webdavSync.fetch()) Webdav.sync(); if (Stores.setting.webdavSync.fetch()) Webdav.sync();
_doVersionRelated();
} }
void _setupProviders() { void _setupProviders() {
@@ -149,3 +153,13 @@ Future<void> _initDesktopWindow() async {
await windowManager.focus(); await windowManager.focus();
}); });
} }
Future<void> _doVersionRelated() async {
final curVer = Stores.setting.lastVer.fetch();
const newVer = BuildData.build;
if (curVer < newVer) {
/// Call [Iterable.toList] to consume the lazy iterable.
VersionRelated.funcs.map((e) => e(newVer)).toList();
Stores.setting.lastVer.put(newVer);
}
}

View File

@@ -1,10 +1,12 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:icons_plus/icons_plus.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:toolbox/core/extension/context/common.dart'; import 'package:toolbox/core/extension/context/common.dart';
import 'package:toolbox/core/extension/context/dialog.dart'; import 'package:toolbox/core/extension/context/dialog.dart';
import 'package:toolbox/core/extension/context/locale.dart'; import 'package:toolbox/core/extension/context/locale.dart';
import 'package:toolbox/core/extension/order.dart'; import 'package:toolbox/core/extension/order.dart';
import 'package:toolbox/core/extension/status_cmd_type.dart'; import 'package:toolbox/core/extension/status_cmd_type.dart';
import 'package:toolbox/data/model/app/server_detail_card.dart';
import 'package:toolbox/data/model/server/battery.dart'; import 'package:toolbox/data/model/server/battery.dart';
import 'package:toolbox/data/model/server/cpu.dart'; import 'package:toolbox/data/model/server/cpu.dart';
import 'package:toolbox/data/model/server/disk.dart'; import 'package:toolbox/data/model/server/disk.dart';
@@ -22,7 +24,6 @@ import '../../../core/route.dart';
import '../../../data/model/server/server.dart'; import '../../../data/model/server/server.dart';
import '../../../data/provider/server.dart'; import '../../../data/provider/server.dart';
import '../../../data/res/color.dart'; import '../../../data/res/color.dart';
import '../../../data/res/default.dart';
import '../../../data/res/ui.dart'; import '../../../data/res/ui.dart';
import '../../widget/appbar.dart'; import '../../widget/appbar.dart';
import '../../widget/cardx.dart'; import '../../widget/cardx.dart';
@@ -39,7 +40,7 @@ class ServerDetailPage extends StatefulWidget {
class _ServerDetailPageState extends State<ServerDetailPage> class _ServerDetailPageState extends State<ServerDetailPage>
with SingleTickerProviderStateMixin { with SingleTickerProviderStateMixin {
late final _cardBuildMap = Map.fromIterables( late final _cardBuildMap = Map.fromIterables(
Defaults.detailCardOrder, ServerDetailCards.names,
[ [
_buildAbout, _buildAbout,
_buildCPUView, _buildCPUView,
@@ -51,6 +52,7 @@ class _ServerDetailPageState extends State<ServerDetailPage>
_buildSensors, _buildSensors,
_buildTemperature, _buildTemperature,
_buildBatteries, _buildBatteries,
_buildPve,
], ],
); );
@@ -623,7 +625,7 @@ class _ServerDetailPageState extends State<ServerDetailPage>
title: Text(l10n.battery), title: Text(l10n.battery),
leading: const Icon(Icons.battery_charging_full, size: 17), leading: const Icon(Icons.battery_charging_full, size: 17),
childrenPadding: const EdgeInsets.only(bottom: 7), childrenPadding: const EdgeInsets.only(bottom: 7),
initiallyExpanded: _getInitExpand(ss.batteries.length), initiallyExpanded: _getInitExpand(ss.batteries.length, 2),
children: ss.batteries.map(_buildBatteryItem).toList(), children: ss.batteries.map(_buildBatteryItem).toList(),
), ),
); );
@@ -662,7 +664,7 @@ class _ServerDetailPageState extends State<ServerDetailPage>
title: Text(l10n.sensors), title: Text(l10n.sensors),
leading: const Icon(Icons.thermostat, size: 17), leading: const Icon(Icons.thermostat, size: 17),
childrenPadding: const EdgeInsets.only(bottom: 7), childrenPadding: const EdgeInsets.only(bottom: 7),
initiallyExpanded: _getInitExpand(ss.sensors.length, 3), initiallyExpanded: _getInitExpand(ss.sensors.length, 2),
children: ss.sensors.map(_buildSensorItem).toList(), children: ss.sensors.map(_buildSensorItem).toList(),
), ),
); );
@@ -700,6 +702,19 @@ class _ServerDetailPageState extends State<ServerDetailPage>
); );
} }
Widget _buildPve(_) {
if (widget.spi.custom?.pveAddr == null) return UIs.placeholder;
return CardX(
child: ListTile(
title: const Text('PVE'),
subtitle: Text(widget.spi.custom!.pveAddr!),
leading: const Icon(FontAwesome.server_solid, size: 17),
trailing: const Icon(Icons.chevron_right),
onTap: () => AppRoute.pve(spi: widget.spi).go(context),
),
);
}
Widget _buildAnimatedText(Key key, String text, TextStyle style) { Widget _buildAnimatedText(Key key, String text, TextStyle style) {
return AnimatedSwitcher( return AnimatedSwitcher(
duration: const Duration(milliseconds: 277), duration: const Duration(milliseconds: 277),
@@ -717,8 +732,8 @@ class _ServerDetailPageState extends State<ServerDetailPage>
} }
bool _getInitExpand(int len, [int? max]) { bool _getInitExpand(int len, [int? max]) {
if (_collapse && len <= (max ?? 7)) return true; if (!_collapse) return true;
return false; return len <= (max ?? 3);
} }
} }

View File

@@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import 'package:toolbox/core/extension/context/locale.dart'; import 'package:toolbox/core/extension/context/locale.dart';
import 'package:toolbox/core/extension/context/snackbar.dart'; import 'package:toolbox/core/extension/context/snackbar.dart';
import 'package:toolbox/core/utils/platform/base.dart'; import 'package:toolbox/core/utils/platform/base.dart';
import 'package:toolbox/data/res/default.dart'; import 'package:toolbox/data/model/app/server_detail_card.dart';
import 'package:toolbox/data/res/logger.dart'; import 'package:toolbox/data/res/logger.dart';
import 'package:toolbox/data/res/store.dart'; import 'package:toolbox/data/res/store.dart';
@@ -39,11 +39,12 @@ class _ServerDetailOrderPageState extends State<ServerDetailOrderPage> {
return List<String>.from(vals); return List<String>.from(vals);
} catch (e) { } catch (e) {
Loggers.app.info('ServerDetailOrderPage: $e'); Loggers.app.info('ServerDetailOrderPage: $e');
return Defaults.detailCardOrder; return ServerDetailCards.names;
} }
}(); }();
final disabled = final disabled = ServerDetailCards.names
Defaults.detailCardOrder.where((e) => !keys.contains(e)).toList(); .where((e) => !keys.contains(e))
.toList();
final allKeys = [...keys, ...disabled]; final allKeys = [...keys, ...disabled];
return ReorderableListView.builder( return ReorderableListView.builder(
padding: const EdgeInsets.all(7), padding: const EdgeInsets.all(7),

View File

@@ -1,10 +1,10 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:toolbox/core/extension/context/locale.dart'; import 'package:toolbox/core/extension/context/locale.dart';
import 'package:toolbox/core/extension/context/snackbar.dart'; import 'package:toolbox/core/extension/context/snackbar.dart';
import 'package:toolbox/core/utils/platform/base.dart';
import 'package:toolbox/data/model/app/menu/server_func.dart'; import 'package:toolbox/data/model/app/menu/server_func.dart';
import 'package:toolbox/data/res/logger.dart'; import 'package:toolbox/data/res/logger.dart';
import 'package:toolbox/data/res/store.dart'; import 'package:toolbox/data/res/store.dart';
import 'package:toolbox/data/res/ui.dart';
import '../../../../core/extension/order.dart'; import '../../../../core/extension/order.dart';
import '../../../widget/appbar.dart'; import '../../../widget/appbar.dart';
@@ -51,12 +51,20 @@ class _ServerDetailOrderPageState extends State<ServerFuncBtnsOrderPage> {
padding: const EdgeInsets.all(7), padding: const EdgeInsets.all(7),
itemBuilder: (_, idx) { itemBuilder: (_, idx) {
final key = allKeys[idx]; final key = allKeys[idx];
final funcBtn = ServerFuncBtn.values[key];
return CardX( return CardX(
key: ValueKey(idx), key: ValueKey(idx),
child: ListTile( child: ListTile(
title: Text(ServerFuncBtn.values[key].toStr), title: RichText(
text: TextSpan(
children: [
WidgetSpan(child: funcBtn.icon(2)),
const WidgetSpan(child: UIs.width7),
TextSpan(text: funcBtn.toStr, style: UIs.textGrey),
],
),
),
leading: _buildCheckBox(keys, key, idx, idx < keys.length), leading: _buildCheckBox(keys, key, idx, idx < keys.length),
trailing: isDesktop ? null : const Icon(Icons.drag_handle),
), ),
); );
}, },

View File

@@ -41,10 +41,8 @@ class ServerFuncBtnsTopRight extends StatelessWidget {
value: e, value: e,
child: Row( child: Row(
children: [ children: [
e.icon, e.icon(),
const SizedBox( const SizedBox(width: 10),
width: 10,
),
Text(e.toStr), Text(e.toStr),
], ],
), ),
@@ -68,9 +66,13 @@ class ServerFuncBtns extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final btns = () { final btns = () {
try { try {
return Stores.setting.serverFuncBtns final vals = <ServerFuncBtn>[];
.fetch() final list = Stores.setting.serverFuncBtns.fetch();
.map((e) => ServerFuncBtn.values[e]); for (final idx in list) {
if (idx < 0 || idx >= ServerFuncBtn.values.length) continue;
vals.add(ServerFuncBtn.values[idx]);
}
return vals;
} catch (e) { } catch (e) {
return ServerFuncBtn.values; return ServerFuncBtn.values;
} }
@@ -84,7 +86,7 @@ class ServerFuncBtns extends StatelessWidget {
onPressed: () => _onTapMoreBtns(e, spi, context), onPressed: () => _onTapMoreBtns(e, spi, context),
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
tooltip: e.toStr, tooltip: e.toStr,
icon: e.icon, icon: e.icon(),
) )
: Padding( : Padding(
padding: const EdgeInsets.only(bottom: 13), padding: const EdgeInsets.only(bottom: 13),
@@ -94,7 +96,7 @@ class ServerFuncBtns extends StatelessWidget {
IconButton( IconButton(
onPressed: () => _onTapMoreBtns(e, spi, context), onPressed: () => _onTapMoreBtns(e, spi, context),
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
icon: e.icon, icon: e.icon(),
), ),
Text(e.toStr, style: UIs.text11Grey) Text(e.toStr, style: UIs.text11Grey)
], ],
@@ -161,12 +163,6 @@ void _onTapMoreBtns(
check: () => _checkClient(context, spi.id), check: () => _checkClient(context, spi.id),
); );
break; break;
case ServerFuncBtn.pve:
AppRoute.pve(spi: spi).checkGo(
context: context,
check: () => _checkClient(context, spi.id),
);
break;
} }
} }