opt.: TagSwitcher related

This commit is contained in:
lollipopkit🏳️‍⚧️
2024-08-16 19:09:54 +08:00
parent f7ef8a3915
commit 7558b4806d
13 changed files with 135 additions and 198 deletions

View File

@@ -44,7 +44,7 @@ final class _IntroPage extends StatelessWidget {
final selected = await ctx.showPickSingleDialog(
title: libL10n.language,
items: AppLocalizations.supportedLocales,
name: (p0) => p0.nativeName,
display: (p0) => p0.nativeName,
initial: _setting.locale.fetch().toLocale,
);
if (selected != null) {

View File

@@ -1,10 +1,12 @@
import 'dart:convert';
import 'package:choice/choice.dart';
import 'package:fl_lib/fl_lib.dart';
import 'package:flutter/material.dart';
import 'package:icons_plus/icons_plus.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/server.dart';
import 'package:server_box/data/model/server/wol_cfg.dart';
import 'package:server_box/data/provider/server.dart';
@@ -45,7 +47,7 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
final _keyIdx = ValueNotifier<int?>(null);
final _autoConnect = ValueNotifier(true);
final _jumpServer = ValueNotifier<String?>(null);
final _jumpServer = nvn<String?>();
final _pveIgnoreCert = ValueNotifier(false);
final _env = <String, String>{}.vn;
final _customCmds = <String, String>{}.vn;
@@ -217,16 +219,16 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
}
Widget _buildKeyAuth() {
const padding = EdgeInsets.only(left: 23, right: 13);
return PrivateKeyProvider.pkis.listenVal(
(pkis) {
final tiles = List<Widget>.generate(pkis.length, (index) {
final e = pkis[index];
return ListTile(
contentPadding: padding,
leading: Text(
'#${index + 1}',
style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 15),
contentPadding: const EdgeInsets.only(left: 10, right: 15),
leading: Radio<int>(
value: index,
groupValue: _keyIdx.value,
onChanged: (value) => _keyIdx.value = value,
),
title: Text(e.id, textAlign: TextAlign.start),
subtitle: Text(
@@ -234,10 +236,9 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
textAlign: TextAlign.start,
style: UIs.textGrey,
),
trailing: Radio<int>(
value: index,
groupValue: _keyIdx.value,
onChanged: (value) => _keyIdx.value = value,
trailing: Btn.icon(
icon: const Icon(Icons.edit),
onTap: () => AppRoutes.keyEdit(pki: e).go(context),
),
onTap: () => _keyIdx.value = index,
);
@@ -245,11 +246,8 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
tiles.add(
ListTile(
title: Text(libL10n.add),
contentPadding: padding,
trailing: const Padding(
padding: EdgeInsets.only(right: 13),
child: Icon(Icons.add),
),
contentPadding: const EdgeInsets.only(left: 23, right: 23),
trailing: const Icon(Icons.add),
onTap: () => AppRoutes.keyEdit().go(context),
),
);
@@ -433,43 +431,49 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
}
Widget _buildJumpServer() {
return ListenableBuilder(
listenable: _jumpServer,
builder: (_, __) {
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),
subtitle: Text(e.spi.id, style: UIs.textGrey),
trailing: Radio<String>(
groupValue: _jumpServer.value,
value: e.spi.id,
onChanged: (val) => _jumpServer.value = val,
),
onTap: () => _jumpServer.value = e.spi.id,
contentPadding: const EdgeInsets.symmetric(horizontal: 17),
),
)
.toList();
children.add(ListTile(
title: Text(libL10n.clear),
trailing: const Icon(Icons.clear),
onTap: () => _jumpServer.value = null,
contentPadding: const EdgeInsets.symmetric(horizontal: 17),
));
return CardX(
child: ExpandTile(
leading: const Icon(Icons.map),
initiallyExpanded: _jumpServer.value != null,
title: Text(l10n.jumpServer),
children: children,
const padding = EdgeInsets.only(left: 13, right: 13, bottom: 7);
final srvs = ServerProvider.servers.values
.map((e) => e.value)
.where((e) => e.spi.jumpId == null)
.where((e) => e.spi.id != widget.spi?.id)
.toList();
final choice = _jumpServer.listenVal(
(val) {
final srv = srvs.firstWhereOrNull((e) => e.id == _jumpServer.value);
return Choice<Server>(
multiple: false,
clearable: true,
value: srv != null ? [srv] : [],
builder: (state, _) => Wrap(
children: List<Widget>.generate(
srvs.length,
(index) {
final item = srvs[index];
return ChoiceChipX<Server>(
label: item.spi.name,
state: state,
value: item,
onSelected: (srv, on) {
if (on) {
_jumpServer.value = srv.spi.id;
} else {
_jumpServer.value = null;
}
},
);
},
),
),
);
},
);
return ExpandTile(
leading: const Icon(Icons.map),
initiallyExpanded: _jumpServer.value != null,
childrenPadding: padding,
title: Text(l10n.jumpServer),
children: [choice],
).cardx;
}
void _onSave() async {

View File

@@ -40,7 +40,7 @@ class _ServerPageState extends State<ServerPage>
Timer? _timer;
String? _tag;
final _tag = ''.vn;
bool _useDoubleColumn = false;
final _scrollController = ScrollController();
@@ -84,7 +84,11 @@ class _ServerPageState extends State<ServerPage>
Widget _buildPortrait() {
return Scaffold(
appBar: _buildTagsSwitcher(),
appBar: TagSwitcher(
tags: ServerProvider.tags,
onTagChanged: (p0) => _tag.value = p0,
tag: _tag,
),
body: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () => _autoHideKey.currentState?.show(),
@@ -182,36 +186,26 @@ class _ServerPageState extends State<ServerPage>
Widget _buildBody() {
return ServerProvider.serverOrder.listenVal(
(order) {
if (!ServerProvider.tags.value.contains(_tag)) {
_tag = null;
}
if (order.isEmpty) {
return Center(
child: Text(libL10n.empty, textAlign: TextAlign.center),
);
}
final filtered = _filterServers(order);
if (_useDoubleColumn &&
Stores.setting.doubleColumnServersPage.fetch()) {
return _buildBodyMedium(filtered);
}
return _buildBodySmall(filtered: filtered);
return _tag.listenVal(
(val) {
final filtered = _filterServers(order);
if (_useDoubleColumn &&
Stores.setting.doubleColumnServersPage.fetch()) {
return _buildBodyMedium(filtered);
}
return _buildBodySmall(filtered: filtered);
},
);
},
);
}
TagSwitcher _buildTagsSwitcher() {
return TagSwitcher(
tags: ServerProvider.tags,
width: _media.size.width,
onTagChanged: (p0) => setState(() {
_tag = p0;
}),
initTag: _tag,
);
}
Widget _buildBodySmall({
required List<String> filtered,
EdgeInsets? padding = const EdgeInsets.fromLTRB(7, 0, 7, 7),
@@ -259,7 +253,7 @@ class _ServerPageState extends State<ServerPage>
}
return CardX(
key: Key(srv.spi.id + (_tag ?? '')),
key: Key(srv.spi.id + _tag.value),
child: InkWell(
onTap: () {
if (srv.canViewDetails) {
@@ -651,11 +645,15 @@ ${ss.err?.message ?? 'null'}
ServerProvider.startAutoRefresh();
}
List<String> _filterServers(List<String> order) => order
.where((e) =>
_tag == null ||
(ServerProvider.pick(id: e)?.value.spi.tags?.contains(_tag) ?? false))
.toList();
List<String> _filterServers(List<String> order) {
final tag = _tag.value;
if (tag.isEmpty) return order;
return order.where((e) {
final tags = ServerProvider.pick(id: e)?.value.spi.tags;
if (tags == null) return false;
return tags.contains(tag);
}).toList();
}
static const _kCardHeightMin = 23.0;
static const _kCardHeightFlip = 99.0;

View File

@@ -202,7 +202,7 @@ class _SettingPageState extends State<SettingPage> {
title: libL10n.setting,
items: List.generate(10, (idx) => idx == 1 ? null : idx),
initial: _setting.serverStatusUpdateInterval.fetch(),
name: (p0) => p0 == 0 ? l10n.manual : '$p0 ${l10n.second}',
display: (p0) => p0 == 0 ? l10n.manual : '$p0 ${l10n.second}',
);
if (val != null) {
_setting.serverStatusUpdateInterval.put(val);
@@ -331,7 +331,7 @@ class _SettingPageState extends State<SettingPage> {
final selected = await context.showPickSingleDialog(
title: l10n.maxRetryCount,
items: List.generate(10, (index) => index),
name: (p0) => '$p0 ${l10n.times}',
display: (p0) => '$p0 ${l10n.times}',
initial: val,
);
if (selected != null) {
@@ -356,7 +356,7 @@ class _SettingPageState extends State<SettingPage> {
final selected = await context.showPickSingleDialog(
title: libL10n.themeMode,
items: List.generate(len + 2, (index) => index),
name: (p0) => _buildThemeModeStr(p0),
display: (p0) => _buildThemeModeStr(p0),
initial: _setting.themeMode.fetch(),
);
if (selected != null) {
@@ -503,7 +503,7 @@ class _SettingPageState extends State<SettingPage> {
final selected = await context.showPickSingleDialog(
title: libL10n.language,
items: AppLocalizations.supportedLocales,
name: (p0) => p0.nativeName,
display: (p0) => p0.nativeName,
initial: _setting.locale.fetch().toLocale,
);
if (selected != null) {
@@ -543,7 +543,7 @@ class _SettingPageState extends State<SettingPage> {
final selected = await context.showPickSingleDialog(
title: l10n.theme,
items: themeMap.keys.toList(),
name: (p0) => p0,
display: (p0) => p0,
initial: _setting.editorTheme.fetch(),
);
if (selected != null) {
@@ -565,7 +565,7 @@ class _SettingPageState extends State<SettingPage> {
final selected = await context.showPickSingleDialog(
title: l10n.theme,
items: themeMap.keys.toList(),
name: (p0) => p0,
display: (p0) => p0,
initial: _setting.editorDarkTheme.fetch(),
);
if (selected != null) {
@@ -688,7 +688,7 @@ class _SettingPageState extends State<SettingPage> {
final selected = await context.showPickSingleDialog(
title: l10n.netViewType,
items: NetViewType.values,
name: (p0) => p0.toStr,
display: (p0) => p0.toStr,
initial: _setting.netViewType.fetch(),
);
if (selected != null) {
@@ -997,7 +997,7 @@ class _SettingPageState extends State<SettingPage> {
final selected = await context.showPickSingleDialog(
title: l10n.theme,
items: List.generate(3, (index) => index),
name: (p0) => index2Str(p0),
display: (p0) => index2Str(p0),
initial: _setting.termTheme.fetch(),
);
if (selected != null) {

View File

@@ -169,7 +169,7 @@ class _SnippetEditPageState extends State<SnippetEditPage>
final serverIds = await context.showPickDialog(
title: l10n.autoRun,
items: ServerProvider.serverOrder.value,
name: (e) => ServerProvider.pick(id: e)?.value.spi.name ?? e,
display: (e) => ServerProvider.pick(id: e)?.value.spi.name ?? e,
initial: vals,
clearable: true,
);

View File

@@ -14,19 +14,16 @@ class SnippetListPage extends StatefulWidget {
}
class _SnippetListPageState extends State<SnippetListPage> {
late MediaQueryData _media;
String? _tag;
@override
void didChangeDependencies() {
super.didChangeDependencies();
_media = MediaQuery.of(context);
}
final _tag = ''.vn;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: TagSwitcher(
tags: SnippetProvider.tags,
onTagChanged: (tag) => _tag.value = tag,
tag: _tag,
),
body: _buildBody(),
floatingActionButton: FloatingActionButton(
heroTag: 'snippetAdd',
@@ -43,40 +40,38 @@ class _SnippetListPageState extends State<SnippetListPage> {
return Center(child: Text(libL10n.empty));
}
final filtered = snippets
.where((e) => _tag == null || (e.tags?.contains(_tag) ?? false))
.toList();
return _tag.listenVal((tag) => _buildSnippetList(snippets, tag));
},
);
}
return ReorderableListView.builder(
padding: const EdgeInsets.symmetric(horizontal: 11),
itemCount: filtered.length,
onReorder: (oldIdx, newIdx) => setState(() {
snippets.moveByItem(
oldIdx,
newIdx,
filtered: filtered,
onMove: (p0) {
Stores.setting.snippetOrder.put(p0.map((e) => e.name).toList());
},
);
}),
header: TagSwitcher(
tags: SnippetProvider.tags,
onTagChanged: (tag) => setState(() => _tag = tag),
initTag: _tag,
width: _media.size.width,
),
footer: UIs.height77,
buildDefaultDragHandles: false,
itemBuilder: (context, idx) {
final snippet = filtered.elementAt(idx);
return ReorderableDelayedDragStartListener(
key: ValueKey(idx),
index: idx,
child: _buildSnippetItem(snippet),
);
Widget _buildSnippetList(List<Snippet> snippets, String tag) {
final filtered = tag.isEmpty
? snippets
: snippets.where((e) => e.tags?.contains(tag) ?? false).toList();
return ReorderableListView.builder(
padding: const EdgeInsets.symmetric(horizontal: 11),
itemCount: filtered.length,
onReorder: (oldIdx, newIdx) => setState(() {
snippets.moveByItem(
oldIdx,
newIdx,
filtered: filtered,
onMove: (p0) {
Stores.setting.snippetOrder.put(p0.map((e) => e.name).toList());
},
);
}),
footer: UIs.height77,
buildDefaultDragHandles: false,
itemBuilder: (context, idx) {
final snippet = filtered.elementAt(idx);
return ReorderableDelayedDragStartListener(
key: ValueKey(idx),
index: idx,
child: _buildSnippetItem(snippet),
);
},
);
}

View File

@@ -305,7 +305,7 @@ class SSHPageState extends State<SSHPage>
.where((element) => element.tags?.contains(e) ?? false)
.toList();
},
name: (e) => e.name,
display: (e) => e.name,
);
if (snippets == null || snippets.isEmpty) return;

View File

@@ -287,8 +287,9 @@ class _LocalStoragePageState extends State<LocalStoragePage> {
title: libL10n.select,
items: ServerProvider.serverOrder.value
.map((e) => ServerProvider.pick(id: e)?.value.spi)
.whereType<Spi>()
.toList(),
name: (e) => e.name,
display: (e) => e.name,
);
if (spi == null) return;

View File

@@ -118,7 +118,7 @@ void _onTapMoreBtns(
.where((element) => element.tags?.contains(e) ?? false)
.toList();
},
name: (e) => e.name,
display: (e) => e.name,
);
if (snippets == null || snippets.isEmpty) return;
final snippet = snippets.firstOrNull;

View File

@@ -151,7 +151,7 @@ packages:
source: hosted
version: "2.0.3"
choice:
dependency: transitive
dependency: "direct main"
description:
name: choice
sha256: "52d07065e8056beba5b26cff7786134cbfa24927b1f5bf60a05d50058597b2d9"
@@ -389,11 +389,9 @@ packages:
fl_lib:
dependency: "direct main"
description:
path: "."
ref: "v1.0.134"
resolved-ref: "24b9778e8fb482ee233b70bcc4a38587aa7f76b1"
url: "https://github.com/lppcg/fl_lib"
source: git
path: "../fl_lib"
relative: true
source: path
version: "0.0.1"
flutter:
dependency: "direct main"
@@ -927,54 +925,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.3.0"
permission_handler:
dependency: transitive
description:
name: permission_handler
sha256: "18bf33f7fefbd812f37e72091a15575e72d5318854877e0e4035a24ac1113ecb"
url: "https://pub.dev"
source: hosted
version: "11.3.1"
permission_handler_android:
dependency: transitive
description:
name: permission_handler_android
sha256: eaf2a1ec4472775451e88ca6a7b86559ef2f1d1ed903942ed135e38ea0097dca
url: "https://pub.dev"
source: hosted
version: "12.0.8"
permission_handler_apple:
dependency: transitive
description:
name: permission_handler_apple
sha256: e6f6d73b12438ef13e648c4ae56bd106ec60d17e90a59c4545db6781229082a0
url: "https://pub.dev"
source: hosted
version: "9.4.5"
permission_handler_html:
dependency: transitive
description:
name: permission_handler_html
sha256: "6cac773d389e045a8d4f85418d07ad58ef9e42a56e063629ce14c4c26344de24"
url: "https://pub.dev"
source: hosted
version: "0.1.2"
permission_handler_platform_interface:
dependency: transitive
description:
name: permission_handler_platform_interface
sha256: fe0ffe274d665be8e34f9c59705441a7d248edebbe5d9e3ec2665f88b79358ea
url: "https://pub.dev"
source: hosted
version: "4.2.2"
permission_handler_windows:
dependency: transitive
description:
name: permission_handler_windows
sha256: "1a790728016f79a41216d88672dbc5df30e686e811ad4e698bfc51f76ad91f1e"
url: "https://pub.dev"
source: hosted
version: "0.2.1"
petitparser:
dependency: transitive
description:
@@ -1184,14 +1134,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.0.0"
shortid:
dependency: transitive
description:
name: shortid
sha256: d0b40e3dbb50497dad107e19c54ca7de0d1a274eb9b4404991e443dadb9ebedb
url: "https://pub.dev"
source: hosted
version: "0.1.2"
sky_engine:
dependency: transitive
description: flutter
@@ -1547,10 +1489,10 @@ packages:
dependency: transitive
description:
name: window_manager
sha256: "8699323b30da4cdbe2aa2e7c9de567a6abd8a97d9a5c850a3c86dcd0b34bbfbf"
sha256: e052224c7d8f0d1d0b2e03b7b1047bb08ea800d919a79453518311839881fa5f
url: "https://pub.dev"
source: hosted
version: "0.3.9"
version: "0.4.0"
xdg_directories:
dependency: transitive
description:

View File

@@ -28,6 +28,7 @@ dependencies:
wake_on_lan: ^4.1.1+3
extended_image: ^8.2.1
json_annotation: ^4.9.0
choice: ^2.3.2
dartssh2:
git:
url: https://github.com/lollipopkit/dartssh2
@@ -59,7 +60,7 @@ dependencies:
fl_lib:
git:
url: https://github.com/lppcg/fl_lib
ref: v1.0.134
ref: v1.0.140
dependency_overrides:
# dartssh2:

View File

@@ -8,7 +8,6 @@
#include <dynamic_color/dynamic_color_plugin_c_api.h>
#include <local_auth_windows/local_auth_plugin.h>
#include <permission_handler_windows/permission_handler_windows_plugin.h>
#include <screen_retriever/screen_retriever_plugin.h>
#include <share_plus/share_plus_windows_plugin_c_api.h>
#include <url_launcher_windows/url_launcher_windows.h>
@@ -19,8 +18,6 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
registry->GetRegistrarForPlugin("DynamicColorPluginCApi"));
LocalAuthPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("LocalAuthPlugin"));
PermissionHandlerWindowsPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin"));
ScreenRetrieverPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("ScreenRetrieverPlugin"));
SharePlusWindowsPluginCApiRegisterWithRegistrar(

View File

@@ -5,7 +5,6 @@
list(APPEND FLUTTER_PLUGIN_LIST
dynamic_color
local_auth_windows
permission_handler_windows
screen_retriever
share_plus
url_launcher_windows