diff --git a/lib/intro.dart b/lib/intro.dart index 3d2c33a6..4b08ff2e 100644 --- a/lib/intro.dart +++ b/lib/intro.dart @@ -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) { diff --git a/lib/view/page/server/edit.dart b/lib/view/page/server/edit.dart index 1c4a68fc..634ca57f 100644 --- a/lib/view/page/server/edit.dart +++ b/lib/view/page/server/edit.dart @@ -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 with AfterLayoutMixin { final _keyIdx = ValueNotifier(null); final _autoConnect = ValueNotifier(true); - final _jumpServer = ValueNotifier(null); + final _jumpServer = nvn(); final _pveIgnoreCert = ValueNotifier(false); final _env = {}.vn; final _customCmds = {}.vn; @@ -217,16 +219,16 @@ class _ServerEditPageState extends State with AfterLayoutMixin { } Widget _buildKeyAuth() { - const padding = EdgeInsets.only(left: 23, right: 13); return PrivateKeyProvider.pkis.listenVal( (pkis) { final tiles = List.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( + 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 with AfterLayoutMixin { textAlign: TextAlign.start, style: UIs.textGrey, ), - trailing: Radio( - 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 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 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( - 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( + multiple: false, + clearable: true, + value: srv != null ? [srv] : [], + builder: (state, _) => Wrap( + children: List.generate( + srvs.length, + (index) { + final item = srvs[index]; + return ChoiceChipX( + 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 { diff --git a/lib/view/page/server/tab.dart b/lib/view/page/server/tab.dart index eab5f0a8..ffd9e7fb 100644 --- a/lib/view/page/server/tab.dart +++ b/lib/view/page/server/tab.dart @@ -40,7 +40,7 @@ class _ServerPageState extends State Timer? _timer; - String? _tag; + final _tag = ''.vn; bool _useDoubleColumn = false; final _scrollController = ScrollController(); @@ -84,7 +84,11 @@ class _ServerPageState extends State 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 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 filtered, EdgeInsets? padding = const EdgeInsets.fromLTRB(7, 0, 7, 7), @@ -259,7 +253,7 @@ class _ServerPageState extends State } 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 _filterServers(List order) => order - .where((e) => - _tag == null || - (ServerProvider.pick(id: e)?.value.spi.tags?.contains(_tag) ?? false)) - .toList(); + List _filterServers(List 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; diff --git a/lib/view/page/setting/entry.dart b/lib/view/page/setting/entry.dart index dbd260e8..e3933519 100644 --- a/lib/view/page/setting/entry.dart +++ b/lib/view/page/setting/entry.dart @@ -202,7 +202,7 @@ class _SettingPageState extends State { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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) { diff --git a/lib/view/page/snippet/edit.dart b/lib/view/page/snippet/edit.dart index d5d6e7a3..64f29aa4 100644 --- a/lib/view/page/snippet/edit.dart +++ b/lib/view/page/snippet/edit.dart @@ -169,7 +169,7 @@ class _SnippetEditPageState extends State 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, ); diff --git a/lib/view/page/snippet/list.dart b/lib/view/page/snippet/list.dart index b2e7d753..bba2ffa7 100644 --- a/lib/view/page/snippet/list.dart +++ b/lib/view/page/snippet/list.dart @@ -14,19 +14,16 @@ class SnippetListPage extends StatefulWidget { } class _SnippetListPageState extends State { - 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 { 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 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), + ); }, ); } diff --git a/lib/view/page/ssh/page.dart b/lib/view/page/ssh/page.dart index 3a9cc920..db3bb5ca 100644 --- a/lib/view/page/ssh/page.dart +++ b/lib/view/page/ssh/page.dart @@ -305,7 +305,7 @@ class SSHPageState extends State .where((element) => element.tags?.contains(e) ?? false) .toList(); }, - name: (e) => e.name, + display: (e) => e.name, ); if (snippets == null || snippets.isEmpty) return; diff --git a/lib/view/page/storage/local.dart b/lib/view/page/storage/local.dart index e73d320f..7c673be1 100644 --- a/lib/view/page/storage/local.dart +++ b/lib/view/page/storage/local.dart @@ -287,8 +287,9 @@ class _LocalStoragePageState extends State { title: libL10n.select, items: ServerProvider.serverOrder.value .map((e) => ServerProvider.pick(id: e)?.value.spi) + .whereType() .toList(), - name: (e) => e.name, + display: (e) => e.name, ); if (spi == null) return; diff --git a/lib/view/widget/server_func_btns.dart b/lib/view/widget/server_func_btns.dart index 22cf7626..e5fc7e0a 100644 --- a/lib/view/widget/server_func_btns.dart +++ b/lib/view/widget/server_func_btns.dart @@ -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; diff --git a/pubspec.lock b/pubspec.lock index 46232ca6..f572e12c 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -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: diff --git a/pubspec.yaml b/pubspec.yaml index 10030c1c..0ddd8b86 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -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: diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 28c6f2d7..b29d6496 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -8,7 +8,6 @@ #include #include -#include #include #include #include @@ -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( diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index 2e41e0f1..16e54273 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -5,7 +5,6 @@ list(APPEND FLUTTER_PLUGIN_LIST dynamic_color local_auth_windows - permission_handler_windows screen_retriever share_plus url_launcher_windows