diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index f66f714e..8db87248 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -672,7 +672,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 872; + CURRENT_PROJECT_VERSION = 873; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_BITCODE = NO; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; @@ -682,7 +682,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.872; + MARKETING_VERSION = 1.0.873; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -808,7 +808,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 872; + CURRENT_PROJECT_VERSION = 873; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_BITCODE = NO; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; @@ -818,7 +818,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.872; + MARKETING_VERSION = 1.0.873; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -836,7 +836,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 872; + CURRENT_PROJECT_VERSION = 873; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_BITCODE = NO; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; @@ -846,7 +846,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.872; + MARKETING_VERSION = 1.0.873; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -867,7 +867,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 872; + CURRENT_PROJECT_VERSION = 873; DEVELOPMENT_TEAM = BA88US33G6; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; @@ -880,7 +880,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.0.872; + MARKETING_VERSION = 1.0.873; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget; @@ -906,7 +906,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 872; + CURRENT_PROJECT_VERSION = 873; DEVELOPMENT_TEAM = BA88US33G6; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; @@ -919,7 +919,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.0.872; + MARKETING_VERSION = 1.0.873; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -942,7 +942,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 872; + CURRENT_PROJECT_VERSION = 873; DEVELOPMENT_TEAM = BA88US33G6; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; @@ -955,7 +955,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.0.872; + MARKETING_VERSION = 1.0.873; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -978,7 +978,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 872; + CURRENT_PROJECT_VERSION = 873; DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_PREVIEWS = YES; @@ -990,7 +990,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.872; + MARKETING_VERSION = 1.0.873; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd; @@ -1019,7 +1019,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 872; + CURRENT_PROJECT_VERSION = 873; DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_PREVIEWS = YES; @@ -1031,7 +1031,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.872; + MARKETING_VERSION = 1.0.873; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd; PRODUCT_NAME = ServerBox; @@ -1057,7 +1057,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 872; + CURRENT_PROJECT_VERSION = 873; DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_PREVIEWS = YES; @@ -1069,7 +1069,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.872; + MARKETING_VERSION = 1.0.873; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd; PRODUCT_NAME = ServerBox; diff --git a/lib/core/extension/context/dialog.dart b/lib/core/extension/context/dialog.dart index 50f4e44f..4939ea40 100644 --- a/lib/core/extension/context/dialog.dart +++ b/lib/core/extension/context/dialog.dart @@ -7,6 +7,7 @@ import 'package:toolbox/core/extension/context/locale.dart'; import 'package:toolbox/data/res/store.dart'; import 'package:toolbox/view/widget/choice_chip.dart'; import 'package:toolbox/view/widget/tag.dart'; +import 'package:toolbox/view/widget/val_builder.dart'; import '../../../data/res/ui.dart'; import '../../../view/widget/input_field.dart'; @@ -180,9 +181,9 @@ extension DialogX on BuildContext { ), const Divider(), SingleChildScrollView( - child: ValueListenableBuilder( - valueListenable: tag, - builder: (_, val, __) { + child: ValBuilder( + listenable: tag, + builder: (val) { final items = itemsBuilder(val); return Choice( onChanged: (value) => vals = value, diff --git a/lib/data/res/build_data.dart b/lib/data/res/build_data.dart index ab44c9ef..9fc0a3c1 100644 --- a/lib/data/res/build_data.dart +++ b/lib/data/res/build_data.dart @@ -2,9 +2,9 @@ class BuildData { static const String name = "ServerBox"; - static const int build = 872; + static const int build = 873; static const String engine = "3.19.5"; - static const String buildAt = "2024-04-23 15:08:31"; - static const int modifications = 4; + static const String buildAt = "2024-04-23 17:37:20"; + static const int modifications = 2; static const int script = 45; } diff --git a/lib/view/page/home/appbar.dart b/lib/view/page/home/appbar.dart index a541e704..07c0893d 100644 --- a/lib/view/page/home/appbar.dart +++ b/lib/view/page/home/appbar.dart @@ -12,9 +12,9 @@ final class _AppBar extends CustomAppBar { @override Widget build(BuildContext context) { - return ValueListenableBuilder( - valueListenable: selectIndex, - builder: (_, idx, __) { + return ValBuilder( + listenable: selectIndex, + builder: (idx) { if (idx == AppTab.ssh.index) { return SizedBox( height: CustomAppBar.barHeight ?? diff --git a/lib/view/page/home/home.dart b/lib/view/page/home/home.dart index 9161dd07..bce94f5c 100644 --- a/lib/view/page/home/home.dart +++ b/lib/view/page/home/home.dart @@ -31,6 +31,7 @@ import 'package:toolbox/data/res/url.dart'; import 'package:toolbox/view/widget/appbar.dart'; import 'package:toolbox/view/widget/cardx.dart'; import 'package:toolbox/view/widget/markdown.dart'; +import 'package:toolbox/view/widget/val_builder.dart'; part 'appbar.dart'; diff --git a/lib/view/page/private_key/edit.dart b/lib/view/page/private_key/edit.dart index 9ba9edc5..571965ed 100644 --- a/lib/view/page/private_key/edit.dart +++ b/lib/view/page/private_key/edit.dart @@ -12,6 +12,7 @@ import 'package:toolbox/core/utils/misc.dart'; import 'package:toolbox/data/res/misc.dart'; import 'package:toolbox/data/res/provider.dart'; import 'package:toolbox/view/widget/input_field.dart'; +import 'package:toolbox/view/widget/val_builder.dart'; import '../../../core/utils/server.dart'; import '../../../data/model/server/private_key_info.dart'; @@ -215,9 +216,9 @@ class _PrivateKeyEditPageState extends State { icon: Icons.password, ), SizedBox(height: MediaQuery.of(context).size.height * 0.1), - ValueListenableBuilder( - valueListenable: _loading, - builder: (_, val, __) => val ?? UIs.placeholder, + ValBuilder( + listenable: _loading, + builder: (val) => val ?? UIs.placeholder, ), ], ); diff --git a/lib/view/page/pve.dart b/lib/view/page/pve.dart index cd55863e..37208fb7 100644 --- a/lib/view/page/pve.dart +++ b/lib/view/page/pve.dart @@ -19,6 +19,7 @@ import 'package:toolbox/view/widget/kv_row.dart'; import 'package:toolbox/view/widget/percent_circle.dart'; import 'package:toolbox/view/widget/row.dart'; import 'package:toolbox/view/widget/two_line_text.dart'; +import 'package:toolbox/view/widget/val_builder.dart'; final class PvePage extends StatefulWidget { final ServerPrivateInfo spi; @@ -64,9 +65,9 @@ final class _PvePageState extends State { appBar: CustomAppBar( title: TwoLineText(up: 'PVE', down: widget.spi.name), actions: [ - ValueListenableBuilder( - valueListenable: _pve.err, - builder: (_, val, __) => val == null + ValBuilder( + listenable: _pve.err, + builder: (val) => val == null ? UIs.placeholder : IconBtn( icon: Icons.refresh, @@ -79,9 +80,9 @@ final class _PvePageState extends State { ), ], ), - body: ValueListenableBuilder( - valueListenable: _pve.err, - builder: (_, val, __) { + body: ValBuilder( + listenable: _pve.err, + builder: (val) { if (val != null) { _timer?.cancel(); return Padding( @@ -91,9 +92,9 @@ final class _PvePageState extends State { ), ); } - return ValueListenableBuilder( - valueListenable: _pve.data, - builder: (_, val, __) { + return ValBuilder( + listenable: _pve.data, + builder: (val) { return _buildBody(val); }, ); diff --git a/lib/view/page/server/detail/view.dart b/lib/view/page/server/detail/view.dart index 26778850..5112cfa4 100644 --- a/lib/view/page/server/detail/view.dart +++ b/lib/view/page/server/detail/view.dart @@ -20,6 +20,7 @@ import 'package:toolbox/data/res/store.dart'; import 'package:toolbox/view/widget/expand_tile.dart'; import 'package:toolbox/view/widget/kv_row.dart'; import 'package:toolbox/view/widget/server_func_btns.dart'; +import 'package:toolbox/view/widget/val_builder.dart'; import '../../../../core/extension/numx.dart'; import '../../../../core/route.dart'; @@ -573,9 +574,9 @@ class _ServerDetailPageState extends State children: [ Text(l10n.net), UIs.width13, - ValueListenableBuilder( - valueListenable: _netSortType, - builder: (_, val, __) => InkWell( + ValBuilder( + listenable: _netSortType, + builder: (val) => InkWell( onTap: () => _netSortType.value = val.next, child: AnimatedSwitcher( duration: const Duration(milliseconds: 377), diff --git a/lib/view/page/server/edit.dart b/lib/view/page/server/edit.dart index ff11e7cc..b5ad649e 100644 --- a/lib/view/page/server/edit.dart +++ b/lib/view/page/server/edit.dart @@ -466,7 +466,10 @@ class _ServerEditPageState extends State { )); return CardX( child: ExpandTile( - leading: const Icon(Icons.map), + leading: const Padding( + padding: EdgeInsets.only(left: 10), + child: Icon(Icons.map), + ), initiallyExpanded: _jumpServer.value != null, title: Text(l10n.jumpServer), children: children, diff --git a/lib/view/page/setting/entry.dart b/lib/view/page/setting/entry.dart index 9c26f15c..f12df445 100644 --- a/lib/view/page/setting/entry.dart +++ b/lib/view/page/setting/entry.dart @@ -3,6 +3,7 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_highlight/theme_map.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; +import 'package:icons_plus/icons_plus.dart'; import 'package:provider/provider.dart'; import 'package:toolbox/core/build_mode.dart'; import 'package:toolbox/core/extension/colorx.dart'; @@ -19,6 +20,7 @@ import 'package:toolbox/data/res/rebuild.dart'; import 'package:toolbox/data/res/store.dart'; import 'package:toolbox/view/widget/expand_tile.dart'; import 'package:toolbox/view/widget/markdown.dart'; +import 'package:toolbox/view/widget/val_builder.dart'; import '../../../core/persistant_store.dart'; import '../../../core/route.dart'; @@ -36,6 +38,8 @@ import '../../widget/input_field.dart'; import '../../widget/cardx.dart'; import '../../widget/store_switch.dart'; +const _kIconSize = 23.0; + class SettingPage extends StatefulWidget { const SettingPage({super.key}); @@ -195,27 +199,28 @@ class _SettingPageState extends State { } Widget _buildCheckUpdate() { - return Consumer( - builder: (ctx, app, __) { - String display; - if (app.newestBuild != null) { - if (app.newestBuild! > BuildData.build) { - display = l10n.versionHaveUpdate(app.newestBuild!); + return ListTile( + leading: const Icon(Icons.update), + title: Text(l10n.autoCheckUpdate), + subtitle: Consumer( + builder: (ctx, app, __) { + String display; + if (app.newestBuild != null) { + if (app.newestBuild! > BuildData.build) { + display = l10n.versionHaveUpdate(app.newestBuild!); + } else { + display = l10n.versionUpdated(BuildData.build); + } } else { - display = l10n.versionUpdated(BuildData.build); + display = l10n.versionUnknownUpdate(BuildData.build); } - } else { - display = l10n.versionUnknownUpdate(BuildData.build); - } - return ListTile( - title: Text(l10n.autoCheckUpdate), - subtitle: Text(display, style: UIs.textGrey), - onTap: () => Funcs.throttle( - () => doUpdate(ctx, force: BuildMode.isDebug), - ), - trailing: StoreSwitch(prop: _setting.autoCheckAppUpdate), - ); - }, + return Text(display, style: UIs.textGrey); + }, + ), + onTap: () => Funcs.throttle( + () => doUpdate(context, force: BuildMode.isDebug), + ), + trailing: StoreSwitch(prop: _setting.autoCheckAppUpdate), ); } @@ -238,9 +243,9 @@ class _SettingPageState extends State { _setting.serverStatusUpdateInterval.put(val); } }, - trailing: ValueListenableBuilder( - valueListenable: _setting.serverStatusUpdateInterval.listenable(), - builder: (_, val, __) => Text( + trailing: ValBuilder( + listenable: _setting.serverStatusUpdateInterval.listenable(), + builder: (val) => Text( '$val ${l10n.second}', style: UIs.text15, ), @@ -250,14 +255,11 @@ class _SettingPageState extends State { Widget _buildAppColor() { return ListTile( - trailing: ClipOval( - child: Container( - color: primaryColor, - height: 27, - width: 27, - ), - ), + leading: const Icon(Icons.colorize), title: Text(l10n.primaryColorSeed), + trailing: ClipOval( + child: Container(color: primaryColor, height: 27, width: 27), + ), onTap: () async { final ctrl = TextEditingController(text: primaryColor.toHex); await context.showRoundDialog( @@ -360,9 +362,9 @@ class _SettingPageState extends State { // } Widget _buildMaxRetry() { - return ValueListenableBuilder( - valueListenable: _setting.maxRetryCount.listenable(), - builder: (_, val, __) => ListTile( + return ValBuilder( + listenable: _setting.maxRetryCount.listenable(), + builder: (val) => ListTile( title: Text( l10n.maxRetryCount, textAlign: TextAlign.start, @@ -392,9 +394,8 @@ class _SettingPageState extends State { // Issue #57 final len = ThemeMode.values.length; return ListTile( - title: Text( - l10n.themeMode, - ), + leading: const Icon(MingCute.moon_stars_fill), + title: Text(l10n.themeMode), onTap: () async { final selected = await context.showPickSingleDialog( items: List.generate(len + 2, (index) => index), @@ -406,9 +407,9 @@ class _SettingPageState extends State { RebuildNodes.app.rebuild(); } }, - trailing: ValueListenableBuilder( - valueListenable: _setting.themeMode.listenable(), - builder: (_, val, __) => Text( + trailing: ValBuilder( + listenable: _setting.themeMode.listenable(), + builder: (val) => Text( _buildThemeModeStr(val), style: UIs.text15, ), @@ -434,6 +435,7 @@ class _SettingPageState extends State { Widget _buildFont() { final fontName = getFileName(_setting.fontPath.fetch()); return ListTile( + leading: const Icon(MingCute.font_fill), title: Text(l10n.font), trailing: Text( fontName ?? l10n.notSelected, @@ -483,11 +485,12 @@ class _SettingPageState extends State { Widget _buildTermFontSize() { return ListTile( + leading: const Icon(MingCute.font_size_line), title: Text(l10n.fontSize), subtitle: Text(l10n.termFontSizeTip, style: UIs.textGrey), - trailing: ValueListenableBuilder( - valueListenable: _setting.termFontSize.listenable(), - builder: (_, val, __) => Text( + trailing: ValBuilder( + listenable: _setting.termFontSize.listenable(), + builder: (val) => Text( val.toString(), style: UIs.text15, ), @@ -535,6 +538,7 @@ class _SettingPageState extends State { Widget _buildLocale() { return ListTile( + leading: const Icon(IonIcons.language), title: Text(l10n.language), onTap: () async { final selected = await context.showPickSingleDialog( @@ -548,9 +552,9 @@ class _SettingPageState extends State { RebuildNodes.app.rebuild(); } }, - trailing: ValueListenableBuilder( - valueListenable: _setting.locale.listenable(), - builder: (_, ___, __) => Text( + trailing: ListenBuilder( + listenable: _setting.locale.listenable(), + builder: () => Text( l10n.languageName, style: UIs.text15, ), @@ -560,6 +564,7 @@ class _SettingPageState extends State { Widget _buildSSHVirtualKeyAutoOff() { return ListTile( + leading: const Icon(MingCute.hotkey_fill), title: Text(l10n.sshVirtualKeyAutoOff), subtitle: const Text('Ctrl & Alt', style: UIs.textGrey), trailing: StoreSwitch(prop: _setting.sshVirtualKeyAutoOff), @@ -568,10 +573,11 @@ class _SettingPageState extends State { Widget _buildEditorTheme() { return ListTile( + leading: const Icon(MingCute.sun_fill), title: Text('${l10n.light} ${l10n.theme.toLowerCase()}'), - trailing: ValueListenableBuilder( - valueListenable: _setting.editorTheme.listenable(), - builder: (_, val, __) => Text(val, style: UIs.text15), + trailing: ValBuilder( + listenable: _setting.editorTheme.listenable(), + builder: (val) => Text(val, style: UIs.text15), ), onTap: () async { final selected = await context.showPickSingleDialog( @@ -588,10 +594,11 @@ class _SettingPageState extends State { Widget _buildEditorDarkTheme() { return ListTile( + leading: const Icon(MingCute.moon_stars_fill), title: Text('${l10n.dark} ${l10n.theme.toLowerCase()}'), - trailing: ValueListenableBuilder( - valueListenable: _setting.editorDarkTheme.listenable(), - builder: (_, val, __) => Text(val, style: UIs.text15), + trailing: ValBuilder( + listenable: _setting.editorDarkTheme.listenable(), + builder: (val) => Text(val, style: UIs.text15), ), onTap: () async { final selected = await context.showPickSingleDialog( @@ -608,6 +615,7 @@ class _SettingPageState extends State { Widget _buildFullScreenSwitch() { return ListTile( + leading: const Icon(Bootstrap.phone_landscape_fill), title: Text(l10n.fullScreen), subtitle: Text(l10n.fullScreenTip, style: UIs.textGrey), trailing: StoreSwitch( @@ -619,6 +627,7 @@ class _SettingPageState extends State { Widget _buildFullScreenJitter() { return ListTile( + leading: const Icon(AntDesign.shake_outline), title: Text(l10n.fullScreenJitter), subtitle: Text(l10n.fullScreenJitterHelp, style: UIs.textGrey), trailing: StoreSwitch( @@ -673,6 +682,7 @@ class _SettingPageState extends State { Widget _buildSSHVirtKeys() { return ListTile( + leading: const Icon(BoxIcons.bxs_keyboard), title: Text(l10n.editVirtKeys), trailing: const Icon(Icons.keyboard_arrow_right), onTap: () => AppRoute.sshVirtKeySetting().go(context), @@ -691,6 +701,7 @@ class _SettingPageState extends State { Widget _buildSftpOpenLastPath() { return ListTile( + leading: const Icon(MingCute.history_line), title: Text(l10n.openLastPath), subtitle: Text(l10n.openLastPathTip, style: UIs.textGrey), trailing: StoreSwitch(prop: _setting.sftpOpenLastPath), @@ -699,6 +710,7 @@ class _SettingPageState extends State { Widget _buildSftpShowFoldersFirst() { return ListTile( + leading: const Icon(MingCute.folder_fill), title: Text(l10n.sftpShowFoldersFirst), trailing: StoreSwitch(prop: _setting.sftpShowFoldersFirst), ); @@ -706,10 +718,11 @@ class _SettingPageState extends State { Widget _buildNetViewType() { return ListTile( + leading: const Icon(ZondIcons.network, size: _kIconSize), title: Text(l10n.netViewType), - trailing: ValueListenableBuilder( - valueListenable: _setting.netViewType.listenable(), - builder: (_, val, __) => Text( + trailing: ValBuilder( + listenable: _setting.netViewType.listenable(), + builder: (val) => Text( val.toStr, style: UIs.text15, ), @@ -730,7 +743,8 @@ class _SettingPageState extends State { Widget _buildDeleteServers() { return ListTile( title: Text(l10n.deleteServers), - trailing: const Icon(Icons.delete_forever), + leading: const Icon(Icons.delete_forever), + trailing: const Icon(Icons.keyboard_arrow_right), onTap: () async { context.showRoundDialog>( title: Text(l10n.choose), @@ -775,9 +789,9 @@ class _SettingPageState extends State { return ListTile( title: Text(l10n.textScaler), subtitle: Text(l10n.textScalerTip, style: UIs.textGrey), - trailing: ValueListenableBuilder( - valueListenable: _setting.textFactor.listenable(), - builder: (_, val, __) => Text( + trailing: ValBuilder( + listenable: _setting.textFactor.listenable(), + builder: (val) => Text( val.toString(), style: UIs.text15, ), @@ -815,6 +829,7 @@ class _SettingPageState extends State { Widget _buildServerFuncBtns() { return ExpandTile( + leading: const Icon(TeenyIcons.button, size: _kIconSize), title: Text(l10n.serverFuncBtns), children: [ _buildServerFuncBtnsSwitch(), @@ -841,6 +856,7 @@ class _SettingPageState extends State { Widget _buildServerSeq() { return ListTile( + leading: const Icon(OctIcons.sort_desc, size: _kIconSize), title: Text(l10n.serverOrder), trailing: const Icon(Icons.keyboard_arrow_right), onTap: () => AppRoute.serverOrder().go(context), @@ -849,6 +865,7 @@ class _SettingPageState extends State { Widget _buildServerDetailCardSeq() { return ListTile( + leading: const Icon(OctIcons.sort_desc, size: _kIconSize), title: Text(l10n.serverDetailOrder), trailing: const Icon(Icons.keyboard_arrow_right), onTap: () => AppRoute.serverDetailOrder().go(context), @@ -857,10 +874,11 @@ class _SettingPageState extends State { Widget _buildEditorFontSize() { return ListTile( + leading: const Icon(MingCute.font_size_line), title: Text(l10n.fontSize), - trailing: ValueListenableBuilder( - valueListenable: _setting.editorFontSize.listenable(), - builder: (_, val, __) => Text( + trailing: ValBuilder( + listenable: _setting.editorFontSize.listenable(), + builder: (val) => Text( val.toString(), style: UIs.text15, ), @@ -904,6 +922,7 @@ class _SettingPageState extends State { Widget _buildSftpRmrDir() { return ListTile( + leading: const Icon(MingCute.delete_2_fill), title: const Text('rm -r'), subtitle: Text(l10n.sftpRmrDirSummary, style: UIs.textGrey), trailing: StoreSwitch(prop: _setting.sftpRmrDir), @@ -926,6 +945,7 @@ class _SettingPageState extends State { }; if (func == null) return null; return ListTile( + leading: const Icon(Icons.phone_android), title: Text('${OS.type} ${l10n.setting}'), trailing: const Icon(Icons.keyboard_arrow_right), onTap: () => func(context), @@ -934,6 +954,7 @@ class _SettingPageState extends State { Widget _buildEditorHighlight() { return ListTile( + leading: const Icon(MingCute.code_line, size: _kIconSize), title: Text(l10n.highlight), subtitle: Text(l10n.editorHighlightTip, style: UIs.textGrey), trailing: StoreSwitch(prop: _setting.editorHighlight), @@ -950,6 +971,7 @@ class _SettingPageState extends State { Widget _buildUsePodman() { return ListTile( + leading: const Icon(IonIcons.logo_docker), title: Text(l10n.usePodmanByDefault), trailing: StoreSwitch(prop: _setting.usePodman), ); @@ -957,6 +979,7 @@ class _SettingPageState extends State { Widget _buildContainerTrySudo() { return ListTile( + leading: const Icon(Clarity.administrator_solid), title: Text(l10n.trySudo), subtitle: Text(l10n.containerTrySudoTip, style: UIs.textGrey), trailing: StoreSwitch(prop: _setting.containerTrySudo), @@ -973,6 +996,7 @@ class _SettingPageState extends State { Widget _buildContainerParseStat() { return ListTile( + leading: const Icon(IonIcons.stats_chart, size: _kIconSize), title: Text(l10n.parseContainerStats), subtitle: Text(l10n.parseContainerStatsTip, style: UIs.textGrey), trailing: StoreSwitch(prop: _setting.containerParseStat), @@ -981,6 +1005,7 @@ class _SettingPageState extends State { Widget _buildServerMore() { return ExpandTile( + leading: const Icon(MingCute.more_3_fill), title: Text(l10n.more), children: [ _buildRememberPwdInMem(), @@ -1016,10 +1041,11 @@ class _SettingPageState extends State { } return ListTile( + leading: const Icon(MingCute.moon_stars_fill, size: _kIconSize), title: Text(l10n.theme), - trailing: ValueListenableBuilder( - valueListenable: _setting.termTheme.listenable(), - builder: (_, val, __) => Text( + trailing: ValBuilder( + listenable: _setting.termTheme.listenable(), + builder: (val) => Text( index2Str(val), style: UIs.text15, ), @@ -1039,6 +1065,7 @@ class _SettingPageState extends State { Widget _buildAppMore() { return ExpandTile( + leading: const Icon(MingCute.more_3_fill), title: Text(l10n.more), children: [ if (isAndroid || isIOS) _buildCollectUsage(), @@ -1065,6 +1092,7 @@ class _SettingPageState extends State { Widget _buildCpuView() { return ExpandTile( + leading: const Icon(OctIcons.cpu, size: _kIconSize), title: Text('CPU ${l10n.view}'), children: [ ListTile( @@ -1082,6 +1110,7 @@ class _SettingPageState extends State { Widget _buildEditorWrap() { return ListTile( + leading: const Icon(MingCute.align_center_line), title: Text(l10n.softWrap), trailing: StoreSwitch(prop: _setting.editorSoftWrap), ); diff --git a/lib/view/page/setting/seq/srv_detail_seq.dart b/lib/view/page/setting/seq/srv_detail_seq.dart index 5ae8e132..5a2a50b3 100644 --- a/lib/view/page/setting/seq/srv_detail_seq.dart +++ b/lib/view/page/setting/seq/srv_detail_seq.dart @@ -3,6 +3,7 @@ import 'package:toolbox/core/extension/context/locale.dart'; import 'package:toolbox/core/extension/context/snackbar.dart'; import 'package:toolbox/data/model/app/server_detail_card.dart'; import 'package:toolbox/data/res/store.dart'; +import 'package:toolbox/view/widget/val_builder.dart'; import '../../../../core/extension/order.dart'; import '../../../widget/appbar.dart'; @@ -29,9 +30,9 @@ class _ServerDetailOrderPageState extends State { } Widget _buildBody() { - return ValueListenableBuilder( - valueListenable: prop.listenable(), - builder: (_, keys, __) { + return ValBuilder( + listenable: prop.listenable(), + builder: (keys) { final disabled = ServerDetailCards.names.where((e) => !keys.contains(e)).toList(); final allKeys = [...keys, ...disabled]; diff --git a/lib/view/page/setting/seq/srv_func_seq.dart b/lib/view/page/setting/seq/srv_func_seq.dart index 68a58f17..e114decd 100644 --- a/lib/view/page/setting/seq/srv_func_seq.dart +++ b/lib/view/page/setting/seq/srv_func_seq.dart @@ -4,6 +4,7 @@ import 'package:toolbox/core/extension/context/snackbar.dart'; import 'package:toolbox/data/model/app/menu/server_func.dart'; import 'package:toolbox/data/res/store.dart'; import 'package:toolbox/data/res/ui.dart'; +import 'package:toolbox/view/widget/val_builder.dart'; import '../../../../core/extension/order.dart'; import '../../../widget/appbar.dart'; @@ -30,9 +31,9 @@ class _ServerDetailOrderPageState extends State { } Widget _buildBody() { - return ValueListenableBuilder( - valueListenable: prop.listenable(), - builder: (_, keys, __) { + return ValBuilder( + listenable: prop.listenable(), + builder: (keys) { final disabled = ServerFuncBtn.values .map((e) => e.index) .where((e) => !keys.contains(e)) diff --git a/lib/view/page/setting/seq/virt_key.dart b/lib/view/page/setting/seq/virt_key.dart index 2154ef3a..a03eb1c2 100644 --- a/lib/view/page/setting/seq/virt_key.dart +++ b/lib/view/page/setting/seq/virt_key.dart @@ -9,6 +9,7 @@ import 'package:toolbox/data/res/store.dart'; import 'package:toolbox/data/res/ui.dart'; import 'package:toolbox/view/widget/cardx.dart'; import 'package:toolbox/view/widget/store_switch.dart'; +import 'package:toolbox/view/widget/val_builder.dart'; import '../../../widget/appbar.dart'; @@ -48,9 +49,9 @@ class _SSHVirtKeySettingPageState extends State { } Widget _buildBody() { - return ValueListenableBuilder( - valueListenable: prop.listenable(), - builder: (_, keys, __) { + return ValBuilder( + listenable: prop.listenable(), + builder: (keys) { final disabled = VirtKey.values .map((e) => e.index) .where((e) => !keys.contains(e)) diff --git a/lib/view/page/snippet/edit.dart b/lib/view/page/snippet/edit.dart index 385c39bf..cd1b0ef0 100644 --- a/lib/view/page/snippet/edit.dart +++ b/lib/view/page/snippet/edit.dart @@ -9,6 +9,7 @@ import 'package:toolbox/data/res/provider.dart'; import 'package:toolbox/view/widget/cardx.dart'; import 'package:toolbox/view/widget/input_field.dart'; import 'package:toolbox/view/widget/markdown.dart'; +import 'package:toolbox/view/widget/val_builder.dart'; import '../../../data/model/server/snippet.dart'; import '../../../data/res/ui.dart'; @@ -132,9 +133,9 @@ class _SnippetEditPageState extends State label: l10n.note, icon: Icons.note, ), - ValueListenableBuilder( - valueListenable: _tags, - builder: (_, vals, __) { + ValBuilder( + listenable: _tags, + builder: (vals) { return TagEditor( tags: _tags.value, onChanged: (p0) => setState(() { @@ -164,33 +165,34 @@ class _SnippetEditPageState extends State Widget _buildAutoRunOn() { return CardX( - child: ValueListenableBuilder( - valueListenable: _autoRunOn, - builder: (_, vals, __) { - return ListTile( - leading: const Icon(Icons.settings_remote, size: 19), - title: Text(l10n.autoRun), - trailing: const Icon(Icons.keyboard_arrow_right), - subtitle: vals.isEmpty - ? null - : Text( - vals.join(', '), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - onTap: () async { - vals.removeWhere((e) => !Pros.server.serverOrder.contains(e)); - final serverIds = await context.showPickDialog( - items: Pros.server.serverOrder, - initial: vals, - ); - if (serverIds != null) { - _autoRunOn.value = serverIds; - } - }, - ); - }, - )); + child: ValBuilder( + listenable: _autoRunOn, + builder: (vals) { + return ListTile( + leading: const Icon(Icons.settings_remote, size: 19), + title: Text(l10n.autoRun), + trailing: const Icon(Icons.keyboard_arrow_right), + subtitle: vals.isEmpty + ? null + : Text( + vals.join(', '), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + onTap: () async { + vals.removeWhere((e) => !Pros.server.serverOrder.contains(e)); + final serverIds = await context.showPickDialog( + items: Pros.server.serverOrder, + initial: vals, + ); + if (serverIds != null) { + _autoRunOn.value = serverIds; + } + }, + ); + }, + ), + ); } Widget _buildTip() { diff --git a/lib/view/page/storage/local.dart b/lib/view/page/storage/local.dart index 567295b7..80a5c725 100644 --- a/lib/view/page/storage/local.dart +++ b/lib/view/page/storage/local.dart @@ -13,6 +13,7 @@ import 'package:toolbox/data/res/provider.dart'; import 'package:toolbox/view/widget/input_field.dart'; import 'package:toolbox/view/widget/omit_start_text.dart'; import 'package:toolbox/view/widget/cardx.dart'; +import 'package:toolbox/view/widget/val_builder.dart'; import '../../../core/extension/numx.dart'; import '../../../core/route.dart'; @@ -76,9 +77,9 @@ class _LocalStoragePageState extends State { icon: const Icon(Icons.downloading), onPressed: () => AppRoute.sftpMission().go(context), ), - ValueListenableBuilder<_SortType>( - valueListenable: _sortType, - builder: (context, value, child) { + ValBuilder<_SortType>( + listenable: _sortType, + builder: (value) { return PopupMenuButton<_SortType>( icon: const Icon(Icons.sort), itemBuilder: (context) { @@ -107,9 +108,9 @@ class _LocalStoragePageState extends State { ), body: FadeIn( key: UniqueKey(), - child: ValueListenableBuilder( - valueListenable: _sortType, - builder: (_, val, __) { + child: ValBuilder( + listenable: _sortType, + builder: (val) { return _buildBody(); }, ), diff --git a/lib/view/page/storage/sftp.dart b/lib/view/page/storage/sftp.dart index 0b39ae44..e07f345c 100644 --- a/lib/view/page/storage/sftp.dart +++ b/lib/view/page/storage/sftp.dart @@ -17,6 +17,7 @@ import 'package:toolbox/data/res/provider.dart'; import 'package:toolbox/data/res/store.dart'; import 'package:toolbox/view/widget/omit_start_text.dart'; import 'package:toolbox/view/widget/cardx.dart'; +import 'package:toolbox/view/widget/val_builder.dart'; import '../../../core/extension/numx.dart'; import '../../../core/route.dart'; @@ -72,9 +73,9 @@ class _SftpPageState extends State with AfterLayoutMixin { icon: const Icon(Icons.downloading), onPressed: () => AppRoute.sftpMission().go(context), ), - ValueListenableBuilder( - valueListenable: _sortOption, - builder: (context, value, child) { + ValBuilder( + listenable: _sortOption, + builder: (value) { return PopupMenuButton<_SortType>( icon: const Icon(Icons.sort), itemBuilder: (context) { @@ -294,11 +295,13 @@ class _SftpPageState extends State with AfterLayoutMixin { return RefreshIndicator( child: FadeIn( key: Key(widget.spi.name + _status.path!.path), - child: ValueListenableBuilder( - valueListenable: _sortOption, - builder: (_, sortOption, __) { - final files = sortOption.sortBy - .sort(_status.files!, reversed: sortOption.reversed); + child: ValBuilder( + listenable: _sortOption, + builder: (sortOption) { + final files = sortOption.sortBy.sort( + _status.files!, + reversed: sortOption.reversed, + ); return ListView.builder( itemCount: files.length, padding: const EdgeInsets.symmetric(horizontal: 7, vertical: 3), diff --git a/lib/view/widget/store_switch.dart b/lib/view/widget/store_switch.dart index 5a1698b8..1b4cebc3 100644 --- a/lib/view/widget/store_switch.dart +++ b/lib/view/widget/store_switch.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; +import 'package:toolbox/view/widget/val_builder.dart'; import '../../core/persistant_store.dart'; @@ -22,9 +23,9 @@ class StoreSwitch extends StatelessWidget { @override Widget build(BuildContext context) { - return ValueListenableBuilder( - valueListenable: prop.listenable(), - builder: (context, bool value, widget) { + return ValBuilder( + listenable: prop.listenable(), + builder: (value) { return Switch( value: value, onChanged: (value) async { diff --git a/lib/view/widget/tag.dart b/lib/view/widget/tag.dart index ec238779..6d4d29eb 100644 --- a/lib/view/widget/tag.dart +++ b/lib/view/widget/tag.dart @@ -5,6 +5,7 @@ import 'package:toolbox/core/extension/context/locale.dart'; import 'package:toolbox/data/res/ui.dart'; import 'package:toolbox/view/widget/input_field.dart'; import 'package:toolbox/view/widget/cardx.dart'; +import 'package:toolbox/view/widget/val_builder.dart'; import '../../data/res/color.dart'; @@ -196,9 +197,9 @@ class TagSwitcher extends StatelessWidget implements PreferredSizeWidget { @override Widget build(BuildContext context) { - return ValueListenableBuilder( - valueListenable: tags, - builder: (_, vals, __) { + return ValBuilder( + listenable: tags, + builder: (vals) { if (vals.isEmpty) return UIs.placeholder; final items = [null, ...vals]; return Container( diff --git a/lib/view/widget/val_builder.dart b/lib/view/widget/val_builder.dart new file mode 100644 index 00000000..03645cd9 --- /dev/null +++ b/lib/view/widget/val_builder.dart @@ -0,0 +1,35 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; + +final class ValBuilder extends ValueListenableBuilder { + ValBuilder({ + super.key, + required ValueListenable listenable, + required Widget Function(T) builder, + }) : super( + valueListenable: listenable, + builder: (_, val, __) => builder(val), + ); +} + +final class ValChildBuilder extends ValueListenableBuilder { + ValChildBuilder({ + super.key, + required ValueListenable listenable, + required Widget Function(T, Widget?) builder, + super.child, + }) : super( + valueListenable: listenable, + builder: (_, val, child) => builder(val, child), + ); +} + +final class ListenBuilder extends ListenableBuilder { + ListenBuilder({ + super.key, + required super.listenable, + required Widget Function() builder, + }) : super( + builder: (_, __) => builder(), + ); +} diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj index 2bece36d..0dcaaac1 100644 --- a/macos/Runner.xcodeproj/project.pbxproj +++ b/macos/Runner.xcodeproj/project.pbxproj @@ -471,7 +471,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 872; + CURRENT_PROJECT_VERSION = 873; DEVELOPMENT_TEAM = BA88US33G6; INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = "Server Box"; @@ -481,7 +481,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 10.15; - MARKETING_VERSION = 1.0.872; + MARKETING_VERSION = 1.0.873; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "Server Box"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -608,7 +608,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 872; + CURRENT_PROJECT_VERSION = 873; DEVELOPMENT_TEAM = BA88US33G6; INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = "Server Box"; @@ -618,7 +618,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 10.15; - MARKETING_VERSION = 1.0.872; + MARKETING_VERSION = 1.0.873; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "Server Box"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -638,7 +638,7 @@ "CODE_SIGN_IDENTITY[sdk=macosx*]" = "3rd Party Mac Developer Application"; CODE_SIGN_STYLE = Manual; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 872; + CURRENT_PROJECT_VERSION = 873; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=macosx*]" = BA88US33G6; INFOPLIST_FILE = Runner/Info.plist; @@ -649,7 +649,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 10.15; - MARKETING_VERSION = 1.0.872; + MARKETING_VERSION = 1.0.873; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "Server Box"; PROVISIONING_PROFILE_SPECIFIER = "";