diff --git a/flutter/lib/common/widgets/peer_tab_page.dart b/flutter/lib/common/widgets/peer_tab_page.dart index 64f353130..c91b01ca8 100644 --- a/flutter/lib/common/widgets/peer_tab_page.dart +++ b/flutter/lib/common/widgets/peer_tab_page.dart @@ -18,7 +18,6 @@ class PeerTabPage extends StatefulWidget { class _PeerTabPageState extends State with SingleTickerProviderStateMixin { - late final PageController _pageController = PageController(); final RxInt _tabIndex = 0.obs; @override @@ -28,7 +27,6 @@ class _PeerTabPageState extends State if (value == '') return; final tab = int.parse(value); _tabIndex.value = tab; - _pageController.jumpToPage(tab); }); await bind.mainGetLocalOption(key: 'peer-card-ui-type').then((value) { if (value == '') return; @@ -45,7 +43,6 @@ class _PeerTabPageState extends State _tabIndex.value = index; await bind.mainSetLocalOption( key: 'peer-tab-index', value: index.toString()); - _pageController.jumpToPage(index); switch (index) { case 0: bind.mainLoadRecentPeers(); @@ -64,7 +61,6 @@ class _PeerTabPageState extends State @override void dispose() { - _pageController.dispose(); super.dispose(); } @@ -82,7 +78,7 @@ class _PeerTabPageState extends State child: Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ - Expanded(child: _createTabBar(context)), + Expanded(child: _createSwitchBar(context)), const SizedBox(width: 10), const PeerSearchBar(), Offstage( @@ -92,12 +88,12 @@ class _PeerTabPageState extends State ], )), ), - _createTabBarView(), + _createPeersView(), ], ); } - Widget _createTabBar(BuildContext context) { + Widget _createSwitchBar(BuildContext context) { final textColor = Theme.of(context).textTheme.titleLarge?.color; return ListView( scrollDirection: Axis.horizontal, @@ -131,17 +127,13 @@ class _PeerTabPageState extends State }).toList()); } - Widget _createTabBarView() { + Widget _createPeersView() { final verticalMargin = isDesktop ? 12.0 : 6.0; return Expanded( - child: PageView( - physics: isDesktop - ? NeverScrollableScrollPhysics() - : BouncingScrollPhysics(), - controller: _pageController, - children: super.widget.children, - onPageChanged: (to) => _tabIndex.value = to) - .marginSymmetric(vertical: verticalMargin)); + child: Obx(() => widget + .children[_tabIndex.value]) //: (to) => _tabIndex.value = to) + .marginSymmetric(vertical: verticalMargin), + ); } Widget _createPeerViewTypeSwitch(BuildContext context) { diff --git a/flutter/lib/common/widgets/peers_view.dart b/flutter/lib/common/widgets/peers_view.dart index 63c29af6d..9316c792b 100644 --- a/flutter/lib/common/widgets/peers_view.dart +++ b/flutter/lib/common/widgets/peers_view.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_hbb/consts.dart'; import 'package:flutter_hbb/desktop/widgets/scroll_wrapper.dart'; import 'package:get/get.dart'; import 'package:provider/provider.dart'; @@ -25,12 +26,14 @@ class _PeersView extends StatefulWidget { final Peers peers; final OffstageFunc offstageFunc; final PeerCardBuilder peerCardBuilder; + final ScrollController? scrollController; const _PeersView( {required this.peers, required this.offstageFunc, required this.peerCardBuilder, - Key? key}) + Key? key, + this.scrollController}) : super(key: key); @override @@ -42,7 +45,6 @@ class _PeersViewState extends State<_PeersView> with WindowListener { static const int _maxQueryCount = 3; final space = isDesktop ? 12.0 : 8.0; final _curPeers = {}; - final _scrollController = ScrollController(); var _lastChangeTime = DateTime.now(); var _lastQueryPeers = {}; var _lastQueryTime = DateTime.now().subtract(const Duration(hours: 1)); @@ -93,9 +95,10 @@ class _PeersViewState extends State<_PeersView> with WindowListener { create: (context) => widget.peers, child: Consumer( builder: (context, peers, child) => peers.peers.isEmpty - ? Center( - child: Text(translate("Empty")), - ) + ? Container( + margin: EdgeInsets.only(top: kEmptyMarginTop), + alignment: Alignment.topCenter, + child: Text(translate("Empty"))) : _buildPeersView(peers)), ); } @@ -147,21 +150,7 @@ class _PeersViewState extends State<_PeersView> with WindowListener { ); }, peerSearchText); - if (isDesktop) { - return DesktopScrollWrapper( - scrollController: _scrollController, - child: SingleChildScrollView( - physics: NeverScrollableScrollPhysics(), - controller: _scrollController, - child: body), - ); - } else { - return SingleChildScrollView( - physics: BouncingScrollPhysics(), - controller: _scrollController, - child: body, - ); - } + return body; } // ignore: todo @@ -224,7 +213,8 @@ abstract class BasePeersView extends StatelessWidget { } class RecentPeersView extends BasePeersView { - RecentPeersView({Key? key, EdgeInsets? menuPadding}) + RecentPeersView( + {Key? key, EdgeInsets? menuPadding, ScrollController? scrollController}) : super( key: key, name: 'recent peer', @@ -246,7 +236,8 @@ class RecentPeersView extends BasePeersView { } class FavoritePeersView extends BasePeersView { - FavoritePeersView({Key? key, EdgeInsets? menuPadding}) + FavoritePeersView( + {Key? key, EdgeInsets? menuPadding, ScrollController? scrollController}) : super( key: key, name: 'favorite peer', @@ -268,7 +259,8 @@ class FavoritePeersView extends BasePeersView { } class DiscoveredPeersView extends BasePeersView { - DiscoveredPeersView({Key? key, EdgeInsets? menuPadding}) + DiscoveredPeersView( + {Key? key, EdgeInsets? menuPadding, ScrollController? scrollController}) : super( key: key, name: 'discovered peer', @@ -290,7 +282,8 @@ class DiscoveredPeersView extends BasePeersView { } class AddressBookPeersView extends BasePeersView { - AddressBookPeersView({Key? key, EdgeInsets? menuPadding}) + AddressBookPeersView( + {Key? key, EdgeInsets? menuPadding, ScrollController? scrollController}) : super( key: key, name: 'address book peer', diff --git a/flutter/lib/consts.dart b/flutter/lib/consts.dart index b9086bde9..41c0634a3 100644 --- a/flutter/lib/consts.dart +++ b/flutter/lib/consts.dart @@ -20,6 +20,9 @@ const int kDesktopDefaultDisplayWidth = 1080; const int kDesktopDefaultDisplayHeight = 720; const Size kConnectionManagerWindowSize = Size(300, 400); +// Tabbar transition duration, now we remove the duration +const Duration kTabTransitionDuration = Duration.zero; +const double kEmptyMarginTop = 50; /// [kDefaultScrollAmountMultiplier] indicates how many rows can be scrolled after a minimum scroll action of mouse const kDefaultScrollAmountMultiplier = 5.0; diff --git a/flutter/lib/desktop/pages/connection_page.dart b/flutter/lib/desktop/pages/connection_page.dart index 07246a916..2e6d79b2f 100644 --- a/flutter/lib/desktop/pages/connection_page.dart +++ b/flutter/lib/desktop/pages/connection_page.dart @@ -6,6 +6,7 @@ import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter_hbb/common/widgets/address_book.dart'; import 'package:flutter_hbb/consts.dart'; +import 'package:flutter_hbb/desktop/widgets/scroll_wrapper.dart'; import 'package:get/get.dart'; import 'package:url_launcher/url_launcher_string.dart'; @@ -25,10 +26,14 @@ class ConnectionPage extends StatefulWidget { } /// State for the connection page. -class _ConnectionPageState extends State { +class _ConnectionPageState extends State + with SingleTickerProviderStateMixin { /// Controller for the id input bar. final _idController = IDTextEditingController(); + /// Nested scroll controller + final _scrollController = ScrollController(); + Timer? _updateTimer; @override @@ -51,15 +56,16 @@ class _ConnectionPageState extends State { @override Widget build(BuildContext context) { - return Container( - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - mainAxisSize: MainAxisSize.max, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: Column( - children: [ + return Column( + children: [ + Expanded( + child: DesktopScrollWrapper( + scrollController: _scrollController, + child: CustomScrollView( + controller: _scrollController, + slivers: [ + SliverList( + delegate: SliverChildListDelegate([ Row( children: [ _buildRemoteIDTextField(context), @@ -67,8 +73,10 @@ class _ConnectionPageState extends State { ).marginOnly(top: 22), SizedBox(height: 12), Divider(), - Expanded( - child: PeerTabPage( + ])), + SliverFillRemaining( + hasScrollBody: false, + child: PeerTabPage( tabs: [ translate('Recent Sessions'), translate('Favorites'), @@ -89,14 +97,16 @@ class _ConnectionPageState extends State { menuPadding: EdgeInsets.only(left: 12.0, right: 3.0), ), ], - )), - ], - ).marginSymmetric(horizontal: 22), - ), - const Divider(), - SizedBox(child: Obx(() => buildStatus())) - .paddingOnly(bottom: 12, top: 6), - ]), + ), + ) + ], + ).marginSymmetric(horizontal: 12.0), + ), + ), + const Divider(), + SizedBox(child: Obx(() => buildStatus())) + .paddingOnly(bottom: 12, top: 6), + ], ); } diff --git a/flutter/lib/desktop/pages/desktop_home_page.dart b/flutter/lib/desktop/pages/desktop_home_page.dart index 1bf7feb14..f25e3263a 100644 --- a/flutter/lib/desktop/pages/desktop_home_page.dart +++ b/flutter/lib/desktop/pages/desktop_home_page.dart @@ -7,6 +7,7 @@ import 'package:flutter_hbb/common.dart'; import 'package:flutter_hbb/desktop/pages/connection_page.dart'; import 'package:flutter_hbb/desktop/pages/desktop_setting_page.dart'; import 'package:flutter_hbb/desktop/pages/desktop_tab_page.dart'; +import 'package:flutter_hbb/desktop/widgets/scroll_wrapper.dart'; import 'package:flutter_hbb/models/platform_model.dart'; import 'package:flutter_hbb/models/server_model.dart'; import 'package:flutter_hbb/utils/multi_window_manager.dart'; @@ -29,6 +30,8 @@ const borderColor = Color(0xFF2F65BA); class _DesktopHomePageState extends State with TrayListener, WindowListener, AutomaticKeepAliveClientMixin { + final _leftPaneScrollController = ScrollController(); + @override bool get wantKeepAlive => true; var updateUrl = ''; @@ -56,6 +59,7 @@ class _DesktopHomePageState extends State Widget build(BuildContext context) { super.build(context); return Row( + crossAxisAlignment: CrossAxisAlignment.start, children: [ buildLeftPane(context), const VerticalDivider( @@ -69,19 +73,25 @@ class _DesktopHomePageState extends State ); } - buildLeftPane(BuildContext context) { + Widget buildLeftPane(BuildContext context) { return ChangeNotifierProvider.value( value: gFFI.serverModel, child: Container( width: 200, color: Theme.of(context).backgroundColor, - child: Column( - children: [ - buildTip(context), - buildIDBoard(context), - buildPasswordBoard(context), - buildHelpCards(), - ], + child: DesktopScrollWrapper( + scrollController: _leftPaneScrollController, + child: SingleChildScrollView( + controller: _leftPaneScrollController, + child: Column( + children: [ + buildTip(context), + buildIDBoard(context), + buildPasswordBoard(context), + buildHelpCards(), + ], + ), + ), ), ), ); diff --git a/flutter/lib/main.dart b/flutter/lib/main.dart index 5ba55af4d..9ba69a476 100644 --- a/flutter/lib/main.dart +++ b/flutter/lib/main.dart @@ -194,10 +194,8 @@ void runConnectionManagerScreen() async { getHiddenTitleBarWindowOptions(size: kConnectionManagerWindowSize); // ensure initial window size to be changed await windowManager.setSize(kConnectionManagerWindowSize); - await Future.wait([ - windowManager.setAlignment(Alignment.topRight), - initEnv(kAppTypeMain) - ]); + await Future.wait( + [windowManager.setAlignment(Alignment.topRight), initEnv(kAppTypeMain)]); runApp(GetMaterialApp( debugShowCheckedModeBanner: false, theme: MyTheme.lightTheme,