refactors (#539)

This commit is contained in:
lollipopkit🏳️‍⚧️
2024-08-16 01:24:43 +08:00
committed by GitHub
parent 7e5bb54c98
commit 38366a2ef3
45 changed files with 527 additions and 640 deletions

View File

@@ -4,7 +4,6 @@ import 'package:fl_lib/fl_lib.dart';
import 'package:flutter/material.dart';
import 'package:flutter_markdown/flutter_markdown.dart';
import 'package:icons_plus/icons_plus.dart';
import 'package:provider/provider.dart';
import 'package:server_box/core/extension/context/locale.dart';
import 'package:server_box/data/model/app/server_detail_card.dart';
import 'package:server_box/data/model/app/shell_func.dart';
@@ -22,14 +21,13 @@ import 'package:server_box/view/widget/server_func_btns.dart';
import 'package:server_box/core/route.dart';
import 'package:server_box/data/model/server/server.dart';
import 'package:server_box/data/provider/server.dart';
part 'misc.dart';
class ServerDetailPage extends StatefulWidget {
const ServerDetailPage({super.key, required this.spi});
final ServerPrivateInfo spi;
final Spi spi;
@override
State<ServerDetailPage> createState() => _ServerDetailPageState();
@@ -79,16 +77,14 @@ class _ServerDetailPageState extends State<ServerDetailPage>
@override
Widget build(BuildContext context) {
return Consumer<ServerProvider>(builder: (_, provider, __) {
final s = widget.spi.server;
if (s == null) {
return Scaffold(
appBar: const CustomAppBar(),
body: Center(child: Text(libL10n.empty)),
);
}
return _buildMainPage(s);
});
final s = widget.spi.server;
if (s == null) {
return Scaffold(
appBar: const CustomAppBar(),
body: Center(child: Text(libL10n.empty)),
);
}
return s.listenVal(_buildMainPage);
}
Widget _buildMainPage(Server si) {
@@ -96,12 +92,12 @@ class _ServerDetailPageState extends State<ServerDetailPage>
final logo = _buildLogo(si);
final children = [
logo,
if (buildFuncs) ServerFuncBtns(spi: widget.spi),
if (buildFuncs) ServerFuncBtns(spi: si.spi),
];
for (final card in _cardsOrder) {
final buildFunc = _cardBuildMap[card];
if (buildFunc != null) {
children.add(buildFunc(si.status));
children.add(buildFunc(si));
}
}
return Scaffold(
@@ -122,8 +118,8 @@ class _ServerDetailPageState extends State<ServerDetailPage>
title: Text(si.spi.name),
actions: [
ShareBtn(
data: widget.spi.toJsonString(),
tip: widget.spi.name,
data: si.spi.toJsonString(),
tip: si.spi.name,
tip2: '${libL10n.share} ${l10n.server} ~ ServerBox',
),
IconButton(
@@ -160,7 +156,8 @@ class _ServerDetailPageState extends State<ServerDetailPage>
);
}
Widget _buildAbout(ServerStatus ss) {
Widget _buildAbout(Server si) {
final ss = si.status;
return CardX(
child: ExpandTile(
leading: const Icon(MingCute.information_fill, size: 20),
@@ -188,7 +185,8 @@ class _ServerDetailPageState extends State<ServerDetailPage>
);
}
Widget _buildCPUView(ServerStatus ss) {
Widget _buildCPUView(Server si) {
final ss = si.status;
final percent = ss.cpu.usedPercent(coreIdx: 0).toInt();
final details = [
_buildDetailPercent(ss.cpu.user, 'user'),
@@ -352,7 +350,8 @@ class _ServerDetailPageState extends State<ServerDetailPage>
);
}
Widget _buildMemView(ServerStatus ss) {
Widget _buildMemView(Server si) {
final ss = si.status;
final free = ss.mem.free / ss.mem.total * 100;
final avail = ss.mem.availPercent * 100;
final used = ss.mem.usedPercent * 100;
@@ -399,7 +398,8 @@ class _ServerDetailPageState extends State<ServerDetailPage>
);
}
Widget _buildSwapView(ServerStatus ss) {
Widget _buildSwapView(Server si) {
final ss = si.status;
if (ss.swap.total == 0) return UIs.placeholder;
final used = ss.swap.usedPercent * 100;
final cached = ss.swap.cached / ss.swap.total * 100;
@@ -434,7 +434,8 @@ class _ServerDetailPageState extends State<ServerDetailPage>
);
}
Widget _buildGpuView(ServerStatus ss) {
Widget _buildGpuView(Server si) {
final ss = si.status;
if (ss.nvidia == null || ss.nvidia?.isEmpty == true) return UIs.placeholder;
final children = ss.nvidia?.map((e) => _buildGpuItem(e)).toList() ?? [];
return CardX(
@@ -544,7 +545,8 @@ class _ServerDetailPageState extends State<ServerDetailPage>
);
}
Widget _buildDiskView(ServerStatus ss) {
Widget _buildDiskView(Server si) {
final ss = si.status;
final children = List.generate(
ss.disk.length, (idx) => _buildDiskItem(ss.disk[idx], ss));
return CardX(
@@ -608,7 +610,8 @@ class _ServerDetailPageState extends State<ServerDetailPage>
);
}
Widget _buildNetView(ServerStatus ss) {
Widget _buildNetView(Server si) {
final ss = si.status;
final ns = ss.netSpeed;
final children = <Widget>[];
final devices = ns.devices;
@@ -691,14 +694,15 @@ class _ServerDetailPageState extends State<ServerDetailPage>
);
}
Widget _buildTemperature(ServerStatus ss) {
Widget _buildTemperature(Server si) {
final ss = si.status;
if (ss.temps.isEmpty) {
return UIs.placeholder;
}
return CardX(
child: ExpandTile(
title: Text(l10n.temperature),
leading: const Icon(Icons.ac_unit, size: 17),
leading: const Icon(Icons.ac_unit, size: 20),
initiallyExpanded: _getInitExpand(ss.temps.devices.length),
childrenPadding: const EdgeInsets.only(bottom: 7),
children: ss.temps.devices
@@ -726,7 +730,8 @@ class _ServerDetailPageState extends State<ServerDetailPage>
);
}
Widget _buildBatteries(ServerStatus ss) {
Widget _buildBatteries(Server si) {
final ss = si.status;
if (ss.batteries.isEmpty) {
return UIs.placeholder;
}
@@ -767,7 +772,8 @@ class _ServerDetailPageState extends State<ServerDetailPage>
);
}
Widget _buildSensors(ServerStatus ss) {
Widget _buildSensors(Server si) {
final ss = si.status;
if (ss.sensors.isEmpty) return UIs.placeholder;
return CardX(
child: ExpandTile(
@@ -830,20 +836,21 @@ class _ServerDetailPageState extends State<ServerDetailPage>
);
}
Widget _buildPve(_) {
final addr = widget.spi.custom?.pveAddr;
if (addr == null) return UIs.placeholder;
Widget _buildPve(Server si) {
final addr = si.spi.custom?.pveAddr;
if (addr == null || addr.isEmpty) return UIs.placeholder;
return CardX(
child: ListTile(
title: const Text('PVE'),
leading: const Icon(FontAwesome.server_solid, size: 17),
trailing: const Icon(Icons.chevron_right),
onTap: () => AppRoutes.pve(spi: widget.spi).go(context),
onTap: () => AppRoutes.pve(spi: si.spi).go(context),
),
);
}
Widget _buildCustom(ServerStatus ss) {
Widget _buildCustom(Server si) {
final ss = si.status;
if (ss.customCmds.isEmpty) return UIs.placeholder;
return CardX(
child: ExpandTile(

View File

@@ -3,11 +3,10 @@ import 'dart:convert';
import 'package:fl_lib/fl_lib.dart';
import 'package:flutter/material.dart';
import 'package:icons_plus/icons_plus.dart';
import 'package:provider/provider.dart';
import 'package:server_box/core/extension/context/locale.dart';
import 'package:server_box/data/model/server/custom.dart';
import 'package:server_box/data/model/server/wol_cfg.dart';
import 'package:server_box/data/res/provider.dart';
import 'package:server_box/data/provider/server.dart';
import 'package:server_box/core/route.dart';
import 'package:server_box/data/model/server/server_private_info.dart';
@@ -16,7 +15,7 @@ import 'package:server_box/data/provider/private_key.dart';
class ServerEditPage extends StatefulWidget {
const ServerEditPage({super.key, this.spi});
final ServerPrivateInfo? spi;
final Spi? spi;
@override
State<ServerEditPage> createState() => _ServerEditPageState();
@@ -148,7 +147,7 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
hint: 'root',
suggestion: false,
),
TagTile(tags: _tags, allTags: Pros.server.tags.value).cardx,
TagTile(tags: _tags, allTags: ServerProvider.tags.value).cardx,
ListTile(
title: Text(l10n.autoConnect),
trailing: ListenableBuilder(
@@ -219,10 +218,10 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
Widget _buildKeyAuth() {
const padding = EdgeInsets.only(left: 23, right: 13);
return Consumer<PrivateKeyProvider>(
builder: (_, key, __) {
final tiles = List<Widget>.generate(key.pkis.length, (index) {
final e = key.pkis[index];
return PrivateKeyProvider.pkis.listenVal(
(pkis) {
final tiles = List<Widget>.generate(pkis.length, (index) {
final e = pkis[index];
return ListTile(
contentPadding: padding,
leading: Text(
@@ -289,7 +288,6 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
return ExpandTile(
title: Text(l10n.more),
children: [
UIs.height7,
Input(
controller: _logoUrlCtrl,
type: TextInputType.url,
@@ -300,13 +298,9 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
),
_buildAltUrl(),
_buildEnvs(),
UIs.height7,
..._buildPVEs(),
UIs.height7,
..._buildCustomCmds(),
UIs.height7,
Text(l10n.temperature, style: UIs.text13Grey),
UIs.height7,
CenterGreyTitle(l10n.temperature),
Input(
controller: _preferTempDevCtrl,
type: TextInputType.text,
@@ -336,26 +330,14 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
List<Widget> _buildPVEs() {
const addr = 'https://127.0.0.1:8006';
return [
const Text('PVE', style: UIs.text13Grey),
UIs.height7,
Autocomplete<String>(
optionsBuilder: (val) {
final v = val.text;
if (v.startsWith(addr.substring(0, v.length))) {
return [addr];
}
return [];
},
onSelected: (val) => _pveAddrCtrl.text = val,
fieldViewBuilder: (_, ctrl, node, __) => Input(
controller: ctrl,
type: TextInputType.url,
icon: MingCute.web_line,
node: node,
label: 'URL',
hint: addr,
suggestion: false,
),
const CenterGreyTitle('PVE'),
Input(
controller: _pveAddrCtrl,
type: TextInputType.url,
icon: MingCute.web_line,
label: 'URL',
hint: addr,
suggestion: false,
),
ListTile(
leading: const Icon(MingCute.certificate_line),
@@ -376,8 +358,7 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
List<Widget> _buildCustomCmds() {
return [
Text(l10n.customCmd, style: UIs.text13Grey),
UIs.height7,
CenterGreyTitle(l10n.customCmd),
_customCmds.listenVal(
(vals) {
return ListTile(
@@ -455,9 +436,10 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
return ListenableBuilder(
listenable: _jumpServer,
builder: (_, __) {
final children = Pros.server.servers
.where((element) => element.spi.jumpId == null)
.where((element) => element.spi.id != widget.spi?.id)
final children = ServerProvider.servers.values
.map((e) => e.value)
.where((e) => e.spi.jumpId == null)
.where((e) => e.spi.id != widget.spi?.id)
.map(
(e) => ListTile(
title: Text(e.spi.name),
@@ -552,7 +534,7 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
}
}
final spi = ServerPrivateInfo(
final spi = Spi(
name: _nameController.text.isEmpty
? _ipController.text
: _nameController.text,
@@ -561,7 +543,7 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
user: _usernameController.text,
pwd: _passwordController.text.selfIfNotNullEmpty,
keyId: _keyIdx.value != null
? Pros.key.pkis.elementAt(_keyIdx.value!).id
? PrivateKeyProvider.pkis.value.elementAt(_keyIdx.value!).id
: null,
tags: _tags.value.isEmpty ? null : _tags.value.toList(),
alterUrl: _altUrlController.text.selfIfNotNullEmpty,
@@ -573,9 +555,9 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
);
if (widget.spi == null) {
Pros.server.addServer(spi);
ServerProvider.addServer(spi);
} else {
Pros.server.updateServer(widget.spi!, spi);
ServerProvider.updateServer(widget.spi!, spi);
}
context.pop();
@@ -589,7 +571,7 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
}
}
void _initWithSpi(ServerPrivateInfo spi) {
void _initWithSpi(Spi spi) {
_nameController.text = spi.name;
_ipController.text = spi.ip;
_portController.text = spi.port.toString();
@@ -597,7 +579,7 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
if (spi.keyId == null) {
_passwordController.text = spi.pwd ?? '';
} else {
_keyIdx.value = Pros.key.pkis.indexWhere(
_keyIdx.value = PrivateKeyProvider.pkis.value.indexWhere(
(e) => e.id == widget.spi!.keyId,
);
}
@@ -656,7 +638,7 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
final code = codes?.firstOrNull?.rawValue;
if (code == null) return;
try {
final spi = ServerPrivateInfo.fromJson(json.decode(code));
final spi = Spi.fromJson(json.decode(code));
_initWithSpi(spi);
} catch (e, s) {
context.showErrDialog(e, s);
@@ -680,7 +662,7 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
actions: Btn.ok(
onTap: () async {
context.pop();
Pros.server.delServer(widget.spi!.id);
ServerProvider.delServer(widget.spi!.id);
context.pop(true);
},
red: true,

View File

@@ -4,12 +4,10 @@ import 'dart:math' as math;
import 'package:fl_lib/fl_lib.dart';
import 'package:flutter/material.dart';
import 'package:icons_plus/icons_plus.dart';
import 'package:provider/provider.dart';
import 'package:server_box/core/extension/context/locale.dart';
import 'package:server_box/core/extension/ssh_client.dart';
import 'package:server_box/data/model/app/shell_func.dart';
import 'package:server_box/data/model/server/try_limiter.dart';
import 'package:server_box/data/res/provider.dart';
import 'package:server_box/data/res/store.dart';
import 'package:server_box/view/widget/percent_circle.dart';
@@ -86,7 +84,7 @@ class _ServerPageState extends State<ServerPage>
Widget _buildPortrait() {
return Scaffold(
appBar: _buildTagsSwitcher(Pros.server),
appBar: _buildTagsSwitcher(),
body: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () => _autoHideKey.currentState?.show(),
@@ -138,74 +136,74 @@ class _ServerPageState extends State<ServerPage>
}
Widget _buildLandscapeBody() {
return Consumer<ServerProvider>(builder: (_, pro, __) {
if (pro.serverOrder.isEmpty) {
return ServerProvider.serverOrder.listenVal((order) {
if (order.isEmpty) {
return Center(
child: Text(libL10n.empty, textAlign: TextAlign.center),
);
}
return PageView.builder(
itemCount: pro.serverOrder.length,
itemCount: order.length,
itemBuilder: (_, idx) {
final id = pro.serverOrder[idx];
final srv = pro.pick(id: id);
final id = order[idx];
final srv = ServerProvider.pick(id: id);
if (srv == null) return UIs.placeholder;
final title = _buildServerCardTitle(srv);
final List<Widget> children = [
title,
..._buildNormalCard(srv.status, srv.spi).joinWith(SizedBox(
height: _media.size.height / 10,
))
];
return srv.listenVal((srv) {
final title = _buildServerCardTitle(srv);
final List<Widget> children = [
title,
..._buildNormalCard(srv.status, srv.spi).joinWith(SizedBox(
height: _media.size.height / 10,
))
];
return Padding(
padding: _media.padding,
child: ListenableBuilder(
listenable: _getCardNoti(id),
builder: (_, __) {
return Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: children,
);
},
),
);
return Padding(
padding: _media.padding,
child: ListenableBuilder(
listenable: _getCardNoti(id),
builder: (_, __) {
return Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: children,
);
},
),
);
});
},
);
});
}
Widget _buildBody() {
final child = Consumer<ServerProvider>(
builder: (_, pro, __) {
if (!pro.tags.value.contains(_tag)) {
return ServerProvider.serverOrder.listenVal(
(order) {
if (!ServerProvider.tags.value.contains(_tag)) {
_tag = null;
}
if (pro.serverOrder.isEmpty) {
if (order.isEmpty) {
return Center(
child: Text(libL10n.empty, textAlign: TextAlign.center),
);
}
final filtered = _filterServers(pro);
final filtered = _filterServers(order);
if (_useDoubleColumn &&
Stores.setting.doubleColumnServersPage.fetch()) {
return _buildBodyMedium(pro: pro, filtered: filtered);
return _buildBodyMedium(filtered);
}
return _buildBodySmall(pro: pro, filtered: filtered);
return _buildBodySmall(filtered: filtered);
},
);
return child;
}
TagSwitcher _buildTagsSwitcher(ServerProvider provider) {
TagSwitcher _buildTagsSwitcher() {
return TagSwitcher(
tags: provider.tags,
tags: ServerProvider.tags,
width: _media.size.width,
onTagChanged: (p0) => setState(() {
_tag = p0;
@@ -215,7 +213,6 @@ class _ServerPageState extends State<ServerPage>
}
Widget _buildBodySmall({
required ServerProvider pro,
required List<String> filtered,
EdgeInsets? padding = const EdgeInsets.fromLTRB(7, 0, 7, 7),
}) {
@@ -227,15 +224,14 @@ class _ServerPageState extends State<ServerPage>
itemBuilder: (_, index) {
// Issue #130
if (index == count - 1) return UIs.height77;
return _buildEachServerCard(pro.pick(id: filtered[index]));
final vnode = ServerProvider.pick(id: filtered[index]);
if (vnode == null) return UIs.placeholder;
return vnode.listenVal(_buildEachServerCard);
},
);
}
Widget _buildBodyMedium({
required ServerProvider pro,
required List<String> filtered,
}) {
Widget _buildBodyMedium(List<String> filtered) {
final mid = (filtered.length / 2).ceil();
final filteredLeft = filtered.sublist(0, mid);
final filteredRight = filtered.sublist(mid);
@@ -243,14 +239,12 @@ class _ServerPageState extends State<ServerPage>
children: [
Expanded(
child: _buildBodySmall(
pro: pro,
filtered: filteredLeft,
padding: const EdgeInsets.only(left: 7),
),
),
Expanded(
child: _buildBodySmall(
pro: pro,
filtered: filteredRight,
padding: const EdgeInsets.only(right: 7),
),
@@ -416,7 +410,7 @@ class _ServerPageState extends State<ServerPage>
];
}
List<Widget> _buildNormalCard(ServerStatus ss, ServerPrivateInfo spi) {
List<Widget> _buildNormalCard(ServerStatus ss, Spi spi) {
return [
UIs.height13,
Row(
@@ -491,7 +485,7 @@ class _ServerPageState extends State<ServerPage>
),
() {
TryLimiter.reset(s.spi.id);
Pros.server.refresh(spi: s.spi);
ServerProvider.refresh(spi: s.spi);
},
),
ServerConn.disconnected => (
@@ -500,7 +494,7 @@ class _ServerPageState extends State<ServerPage>
size: 19,
color: Colors.grey,
),
() => Pros.server.refresh(spi: s.spi)
() => ServerProvider.refresh(spi: s.spi)
),
ServerConn.finished => (
const Icon(
@@ -508,7 +502,7 @@ class _ServerPageState extends State<ServerPage>
size: 17,
color: Colors.grey,
),
() => Pros.server.closeServer(id: s.spi.id),
() => ServerProvider.closeServer(id: s.spi.id),
),
_ when Stores.setting.serverTabUseOldUI.fetch() => (
ServerFuncBtnsTopRight(spi: s.spi),
@@ -653,14 +647,14 @@ ${ss.err?.message ?? 'null'}
@override
Future<void> afterFirstLayout(BuildContext context) async {
await Pros.server.load();
Pros.server.startAutoRefresh();
ServerProvider.refresh();
ServerProvider.startAutoRefresh();
}
List<String> _filterServers(ServerProvider pro) => pro.serverOrder
.where((e) => pro.serverOrder.contains(e))
List<String> _filterServers(List<String> order) => order
.where((e) =>
_tag == null || (pro.pick(id: e)?.spi.tags?.contains(_tag) ?? false))
_tag == null ||
(ServerProvider.pick(id: e)?.value.spi.tags?.contains(_tag) ?? false))
.toList();
static const _kCardHeightMin = 23.0;
@@ -747,7 +741,7 @@ class _CardStatus {
}
extension _ServerX on Server {
String? getTopRightStr(ServerPrivateInfo spi) {
String? getTopRightStr(Spi spi) {
switch (conn) {
case ServerConn.disconnected:
return null;