From 131ece725a56f8aec17aad31d7cb7e85acebec7d Mon Sep 17 00:00:00 2001 From: lollipopkit Date: Thu, 9 May 2024 18:26:31 +0800 Subject: [PATCH] opt.: server tab navigation bar when landscape --- ios/Runner.xcodeproj/project.pbxproj | 36 ++++----- lib/data/model/server/server.ext.dart | 2 +- lib/data/res/build_data.dart | 6 +- lib/view/page/home/home.dart | 11 +-- lib/view/page/server/tab.dart | 5 +- lib/view/widget/auto_hide.dart | 102 +++++++++++++++++++++++++ lib/view/widget/auto_hide_fab.dart | 86 --------------------- lib/view/widget/kv_row.dart | 11 +-- macos/Runner.xcodeproj/project.pbxproj | 12 +-- 9 files changed, 145 insertions(+), 126 deletions(-) create mode 100644 lib/view/widget/auto_hide.dart delete mode 100644 lib/view/widget/auto_hide_fab.dart diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 4374de59..9e17dcc2 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -690,7 +690,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 882; + CURRENT_PROJECT_VERSION = 884; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_BITCODE = NO; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; @@ -700,7 +700,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.882; + MARKETING_VERSION = 1.0.884; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -826,7 +826,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 882; + CURRENT_PROJECT_VERSION = 884; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_BITCODE = NO; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; @@ -836,7 +836,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.882; + MARKETING_VERSION = 1.0.884; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -854,7 +854,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 882; + CURRENT_PROJECT_VERSION = 884; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_BITCODE = NO; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; @@ -864,7 +864,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.882; + MARKETING_VERSION = 1.0.884; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -885,7 +885,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 882; + CURRENT_PROJECT_VERSION = 884; DEVELOPMENT_TEAM = BA88US33G6; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; @@ -898,7 +898,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.0.882; + MARKETING_VERSION = 1.0.884; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget; @@ -924,7 +924,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 882; + CURRENT_PROJECT_VERSION = 884; DEVELOPMENT_TEAM = BA88US33G6; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; @@ -937,7 +937,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.0.882; + MARKETING_VERSION = 1.0.884; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -960,7 +960,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 882; + CURRENT_PROJECT_VERSION = 884; DEVELOPMENT_TEAM = BA88US33G6; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; @@ -973,7 +973,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.0.882; + MARKETING_VERSION = 1.0.884; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -996,7 +996,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 882; + CURRENT_PROJECT_VERSION = 884; DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_PREVIEWS = YES; @@ -1008,7 +1008,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.882; + MARKETING_VERSION = 1.0.884; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd; @@ -1037,7 +1037,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 882; + CURRENT_PROJECT_VERSION = 884; DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_PREVIEWS = YES; @@ -1049,7 +1049,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.882; + MARKETING_VERSION = 1.0.884; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd; PRODUCT_NAME = ServerBox; @@ -1075,7 +1075,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 882; + CURRENT_PROJECT_VERSION = 884; DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_PREVIEWS = YES; @@ -1087,7 +1087,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.882; + MARKETING_VERSION = 1.0.884; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd; PRODUCT_NAME = ServerBox; diff --git a/lib/data/model/server/server.ext.dart b/lib/data/model/server/server.ext.dart index 1363ef58..6e771e5d 100644 --- a/lib/data/model/server/server.ext.dart +++ b/lib/data/model/server/server.ext.dart @@ -10,7 +10,7 @@ extension ServerX on Server { final cmdTemp = () { final val = status.customCmds['server_card_top_right']; if (val == null) return null; - // This returned value is used on server card top right, so it should + // This returned value is used on server card top right, so it should // be a single line string. return val.split('\n').lastOrNull; }(); diff --git a/lib/data/res/build_data.dart b/lib/data/res/build_data.dart index d02fb226..c3e879ce 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 = 882; + static const int build = 884; static const String engine = "3.19.6"; - static const String buildAt = "2024-05-09 15:29:37"; - static const int modifications = 3; + static const String buildAt = "2024-05-09 17:08:49"; + static const int modifications = 4; static const int script = 46; } diff --git a/lib/view/page/home/home.dart b/lib/view/page/home/home.dart index ee634728..8f775394 100644 --- a/lib/view/page/home/home.dart +++ b/lib/view/page/home/home.dart @@ -175,20 +175,19 @@ class _HomePageState extends State : ValBuilder( listenable: _isLandscape, builder: (ls) { - if (ls) return const SizedBox(); return ListenableBuilder( listenable: _selectIndex, - builder: (_, __) => _buildBottomBar(), + builder: (_, __) => _buildBottomBar(ls), ); }, ), ); } - Widget _buildBottomBar() { + Widget _buildBottomBar(bool ls) { return NavigationBar( selectedIndex: _selectIndex.value, - height: kBottomNavigationBarHeight * 1.1, + height: kBottomNavigationBarHeight * (ls ? 0.75 : 1.1), animationDuration: const Duration(milliseconds: 250), onDestinationSelected: (int index) { if (_selectIndex.value == index) return; @@ -203,7 +202,9 @@ class _HomePageState extends State _switchingPage = false; }); }, - labelBehavior: NavigationDestinationLabelBehavior.onlyShowSelected, + labelBehavior: ls + ? NavigationDestinationLabelBehavior.alwaysHide + : NavigationDestinationLabelBehavior.onlyShowSelected, destinations: [ NavigationDestination( icon: const Icon(BoxIcons.bx_server), diff --git a/lib/view/page/server/tab.dart b/lib/view/page/server/tab.dart index 6572e918..0f1d3228 100644 --- a/lib/view/page/server/tab.dart +++ b/lib/view/page/server/tab.dart @@ -18,7 +18,7 @@ import 'package:toolbox/data/model/server/try_limiter.dart'; import 'package:toolbox/data/res/color.dart'; import 'package:toolbox/data/res/provider.dart'; import 'package:toolbox/data/res/store.dart'; -import 'package:toolbox/view/widget/auto_hide_fab.dart'; +import 'package:toolbox/view/widget/auto_hide.dart'; import 'package:toolbox/view/widget/percent_circle.dart'; import '../../../core/route.dart'; @@ -101,7 +101,8 @@ class _ServerPageState extends State return _buildBody(); }, ), - floatingActionButton: AutoHideFab( + floatingActionButton: AutoHide( + direction: AxisDirection.right, controller: _scrollController, child: FloatingActionButton( heroTag: 'addServer', diff --git a/lib/view/widget/auto_hide.dart b/lib/view/widget/auto_hide.dart new file mode 100644 index 00000000..691a2b56 --- /dev/null +++ b/lib/view/widget/auto_hide.dart @@ -0,0 +1,102 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; + +final class AutoHide extends StatefulWidget { + final Widget child; + final ScrollController controller; + final AxisDirection direction; + + const AutoHide({ + super.key, + required this.child, + required this.controller, + required this.direction, + }); + + @override + State createState() => _AutoHideState(); +} + +final class _AutoHideState extends State { + bool _visible = true; + bool _isScrolling = false; + Timer? _timer; + + @override + void initState() { + super.initState(); + widget.controller.addListener(_scrollListener); + _setupTimer(); + } + + @override + void dispose() { + widget.controller.removeListener(_scrollListener); + _timer?.cancel(); + _timer = null; + super.dispose(); + } + + void _setupTimer() { + _timer?.cancel(); + _timer = Timer.periodic(const Duration(seconds: 3), (_) { + debugPrint('[AutoHideFab._timer] trigger timer'); + if (_isScrolling) return; + if (!_visible) return; + if (!widget.controller.positions.any((e) => e.maxScrollExtent >= 0)) { + return; + } + setState(() { + _visible = false; + }); + _timer?.cancel(); + _timer = null; + }); + } + + void _scrollListener() { + if (_isScrolling) return; + _isScrolling = true; + + if (!_visible) { + setState(() { + _visible = true; + }); + _setupTimer(); + } + + _isScrolling = false; + } + + @override + Widget build(BuildContext context) { + return AnimatedContainer( + duration: Durations.medium1, + curve: Curves.easeInOutCubic, + transform: _transform, + child: widget.child, + ); + } + + Matrix4? get _transform { + switch (widget.direction) { + case AxisDirection.down: + return _visible + ? Matrix4.identity() + : Matrix4.translationValues(0, 55, 0); + case AxisDirection.up: + return _visible + ? Matrix4.identity() + : Matrix4.translationValues(0, -55, 0); + case AxisDirection.left: + return _visible + ? Matrix4.identity() + : Matrix4.translationValues(-55, 0, 0); + case AxisDirection.right: + return _visible + ? Matrix4.identity() + : Matrix4.translationValues(55, 0, 0); + } + } +} diff --git a/lib/view/widget/auto_hide_fab.dart b/lib/view/widget/auto_hide_fab.dart deleted file mode 100644 index 089e6527..00000000 --- a/lib/view/widget/auto_hide_fab.dart +++ /dev/null @@ -1,86 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; - -final class AutoHideFab extends StatefulWidget { - final Widget child; - final ScrollController controller; - - const AutoHideFab({ - super.key, - required this.child, - required this.controller, - }); - - @override - State createState() => _AutoHideFabState(); -} - -final class _AutoHideFabState extends State { - bool _visible = true; - bool _isScrolling = false; - Timer? _timer; - - @override - void initState() { - super.initState(); - widget.controller.addListener(_scrollListener); - } - - @override - void dispose() { - widget.controller.removeListener(_scrollListener); - _timer?.cancel(); - _timer = null; - super.dispose(); - } - - void _setupTimer() { - if (_timer != null) { - _timer!.cancel(); - _timer = null; - } - _timer = Timer.periodic(const Duration(seconds: 3), (_) { - if (_isScrolling) return; - if (!_visible) return; - if (widget.controller.position.maxScrollExtent <= 0) return; - setState(() { - _visible = false; - }); - }); - } - - void _scrollListener() { - if (_isScrolling) return; - _isScrolling = true; - if (widget.controller.position.userScrollDirection == - ScrollDirection.reverse) { - if (_visible) { - setState(() { - _visible = false; - }); - _timer?.cancel(); - _timer = null; - } - } else { - if (!_visible) { - setState(() { - _visible = true; - }); - _setupTimer(); - } - } - _isScrolling = false; - } - - @override - Widget build(BuildContext context) { - return AnimatedContainer( - duration: Durations.medium1, - curve: Curves.easeInOutCubic, - transform: Matrix4.translationValues(_visible ? 0.0 : 55, 0.0, 0.0), - child: widget.child, - ); - } -} diff --git a/lib/view/widget/kv_row.dart b/lib/view/widget/kv_row.dart index f1b6de68..63d1fc54 100644 --- a/lib/view/widget/kv_row.dart +++ b/lib/view/widget/kv_row.dart @@ -28,11 +28,12 @@ final class KvRow extends StatelessWidget { children: [ kBuilder?.call() ?? Text(k, style: UIs.text12), UIs.width7, - vBuilder?.call() ?? Text( - v, - style: UIs.text11Grey, - overflow: TextOverflow.ellipsis, - ), + vBuilder?.call() ?? + Text( + v, + style: UIs.text11Grey, + overflow: TextOverflow.ellipsis, + ), if (onTap != null) UIs.width7, if (onTap != null) const Icon(Icons.keyboard_arrow_right, size: 16), ], diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj index af6ee5c5..dbe945c1 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 = 882; + CURRENT_PROJECT_VERSION = 884; 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.882; + MARKETING_VERSION = 1.0.884; 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 = 882; + CURRENT_PROJECT_VERSION = 884; 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.882; + MARKETING_VERSION = 1.0.884; 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 = 882; + CURRENT_PROJECT_VERSION = 884; 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.882; + MARKETING_VERSION = 1.0.884; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "Server Box"; PROVISIONING_PROFILE_SPECIFIER = "";