From 3b1b6ec8d6cb1d6fb012480642af281dfbfb1bff Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Fri, 12 Jul 2024 11:39:44 +0800 Subject: [PATCH] :sparkles: Drawer navigation --- lib/main.dart | 7 +++- lib/router.dart | 19 +++------ lib/screens/account.dart | 2 +- lib/screens/chat.dart | 6 ++- lib/screens/feed.dart | 3 +- lib/screens/realms.dart | 3 +- lib/shells/root_shell.dart | 40 +++++-------------- lib/shells/title_shell.dart | 17 ++++---- lib/widgets/drawer_button.dart | 19 +++++++++ .../navigation/app_navigation_drawer.dart | 35 ++++++++++++++++ 10 files changed, 93 insertions(+), 58 deletions(-) create mode 100644 lib/widgets/drawer_button.dart create mode 100644 lib/widgets/navigation/app_navigation_drawer.dart diff --git a/lib/main.dart b/lib/main.dart index e9eaa35..391e5a7 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -19,6 +19,7 @@ import 'package:solian/providers/content/realm.dart'; import 'package:solian/providers/friend.dart'; import 'package:solian/providers/account_status.dart'; import 'package:solian/router.dart'; +import 'package:solian/shells/root_shell.dart'; import 'package:solian/shells/system_shell.dart'; import 'package:solian/theme.dart'; import 'package:solian/translations.dart'; @@ -87,8 +88,10 @@ class SolianApp extends StatelessWidget { onInit: () => _initializeProviders(context), builder: (context, child) { return SystemShell( - child: ScaffoldMessenger( - child: child ?? const SizedBox(), + child: RootShell( + child: ScaffoldMessenger( + child: child ?? const SizedBox(), + ), ), ); }, diff --git a/lib/router.dart b/lib/router.dart index 020007f..2a48dd8 100644 --- a/lib/router.dart +++ b/lib/router.dart @@ -20,7 +20,6 @@ import 'package:solian/screens/realms/realm_view.dart'; import 'package:solian/screens/feed.dart'; import 'package:solian/screens/posts/post_editor.dart'; import 'package:solian/shells/basic_shell.dart'; -import 'package:solian/shells/root_shell.dart'; import 'package:solian/shells/title_shell.dart'; import 'package:solian/theme.dart'; import 'package:solian/widgets/sidebar/empty_placeholder.dart'; @@ -28,18 +27,10 @@ import 'package:solian/widgets/sidebar/empty_placeholder.dart'; abstract class AppRouter { static GoRouter instance = GoRouter( routes: [ - ShellRoute( - builder: (context, state, child) => RootShell( - state: state, - child: child, - ), - routes: [ - _feedRoute, - _chatRoute, - _realmRoute, - _accountRoute, - ], - ), + _feedRoute, + _chatRoute, + _realmRoute, + _accountRoute, ], ); @@ -232,7 +223,7 @@ abstract class AppRouter { name: 'account', builder: (context, state) => SolianTheme.isExtraLargeScreen(context) ? const EmptyPagePlaceholder() - : const AccountScreen(), + : TitleShell(state: state, child: const AccountScreen()), ), GoRoute( path: '/account/friend', diff --git a/lib/screens/account.dart b/lib/screens/account.dart index 0fdabab..845e54e 100644 --- a/lib/screens/account.dart +++ b/lib/screens/account.dart @@ -87,7 +87,7 @@ class _AccountScreenState extends State { return ListView( children: [ - const AccountHeading().paddingOnly(bottom: 8, top: 16), + const AccountHeading().paddingOnly(bottom: 8, top: 8), ...(actionItems.map( (x) => ListTile( contentPadding: const EdgeInsets.symmetric(horizontal: 34), diff --git a/lib/screens/chat.dart b/lib/screens/chat.dart index d9340cc..16e9380 100644 --- a/lib/screens/chat.dart +++ b/lib/screens/chat.dart @@ -12,6 +12,7 @@ import 'package:solian/widgets/app_bar_title.dart'; import 'package:solian/widgets/channel/channel_list.dart'; import 'package:solian/widgets/chat/call/chat_call_indicator.dart'; import 'package:solian/widgets/current_state_action.dart'; +import 'package:solian/widgets/drawer_button.dart' as drawer; class ChatScreen extends StatefulWidget { const ChatScreen({super.key}); @@ -94,7 +95,7 @@ class _ChatScreenState extends State { title: AppBarTitle('chat'.tr), centerTitle: false, floating: true, - titleSpacing: SolianTheme.titleSpacing(context), + leading: const drawer.DrawerButton(), toolbarHeight: SolianTheme.toolbarHeight(context), actions: [ const BackgroundStateWidget(), @@ -191,7 +192,8 @@ class _ChatScreenState extends State { child: RefreshIndicator( onRefresh: () => getChannels(), child: ChannelListWidget( - channels: _channels.where((x) => x.type == 1).toList(), + channels: + _channels.where((x) => x.type == 1).toList(), selfId: _accountId ?? 0, noCategory: true, ), diff --git a/lib/screens/feed.dart b/lib/screens/feed.dart index ff76099..102298f 100644 --- a/lib/screens/feed.dart +++ b/lib/screens/feed.dart @@ -11,6 +11,7 @@ import 'package:solian/theme.dart'; import 'package:solian/widgets/app_bar_title.dart'; import 'package:solian/widgets/current_state_action.dart'; import 'package:solian/widgets/feed/feed_list.dart'; +import 'package:solian/widgets/drawer_button.dart' as drawer; class FeedScreen extends StatefulWidget { const FeedScreen({super.key}); @@ -62,8 +63,8 @@ class _FeedScreenState extends State { title: AppBarTitle('feed'.tr), centerTitle: false, floating: true, - titleSpacing: SolianTheme.titleSpacing(context), toolbarHeight: SolianTheme.toolbarHeight(context), + leading: const drawer.DrawerButton(), actions: [ const BackgroundStateWidget(), const NotificationButton(), diff --git a/lib/screens/realms.dart b/lib/screens/realms.dart index e9659a2..0ea9c4e 100644 --- a/lib/screens/realms.dart +++ b/lib/screens/realms.dart @@ -11,6 +11,7 @@ import 'package:solian/theme.dart'; import 'package:solian/widgets/account/signin_required_overlay.dart'; import 'package:solian/widgets/app_bar_title.dart'; import 'package:solian/widgets/current_state_action.dart'; +import 'package:solian/widgets/drawer_button.dart' as drawer; class RealmListScreen extends StatefulWidget { const RealmListScreen({super.key}); @@ -79,7 +80,7 @@ class _RealmListScreenState extends State { title: AppBarTitle('realm'.tr), centerTitle: false, floating: true, - titleSpacing: SolianTheme.titleSpacing(context), + leading: const drawer.DrawerButton(), toolbarHeight: SolianTheme.toolbarHeight(context), actions: [ const BackgroundStateWidget(), diff --git a/lib/shells/root_shell.dart b/lib/shells/root_shell.dart index f5f9c94..2d497d9 100644 --- a/lib/shells/root_shell.dart +++ b/lib/shells/root_shell.dart @@ -1,36 +1,33 @@ import 'package:flutter/material.dart'; -import 'package:flutter_animate/flutter_animate.dart'; -import 'package:go_router/go_router.dart'; -import 'package:solian/router.dart'; import 'package:solian/theme.dart'; -import 'package:solian/widgets/navigation/app_navigation.dart'; -import 'package:solian/widgets/navigation/app_navigation_bottom_bar.dart'; +import 'package:solian/widgets/navigation/app_navigation_drawer.dart'; import 'package:solian/widgets/navigation/app_navigation_rail.dart'; +final GlobalKey rootScaffoldKey = GlobalKey(); + class RootShell extends StatelessWidget { final bool showSidebar; final bool showNavigation; final bool? showBottomNavigation; - final GoRouterState state; final Widget child; const RootShell({ super.key, - required this.state, required this.child, this.showSidebar = true, this.showNavigation = true, this.showBottomNavigation, }); + void closeDrawer() { + rootScaffoldKey.currentState!.closeDrawer(); + } + @override Widget build(BuildContext context) { - final routeName = AppRouter - .instance.routerDelegate.currentConfiguration.lastOrNull?.route.name; - final showBottom = showBottomNavigation ?? - AppNavigation.destinationPages.contains(routeName); - return Scaffold( + key: rootScaffoldKey, + drawer: const AppNavigationDrawer(), body: SolianTheme.isLargeScreen(context) ? Row( children: [ @@ -40,24 +37,7 @@ class RootShell extends StatelessWidget { Expanded(child: child), ], ) - : Stack( - children: [ - child, - Positioned( - bottom: 0, - left: 0, - right: 0, - child: const AppNavigationBottomBar() - .animate(target: showBottom ? 0 : 1) - .slideY( - duration: 250.ms, - begin: 0, - end: 1, - curve: Curves.easeInToLinear, - ), - ), - ], - ), + : child, ); } } diff --git a/lib/shells/title_shell.dart b/lib/shells/title_shell.dart index 8dd8205..331335c 100644 --- a/lib/shells/title_shell.dart +++ b/lib/shells/title_shell.dart @@ -4,7 +4,8 @@ import 'package:go_router/go_router.dart'; import 'package:solian/router.dart'; import 'package:solian/theme.dart'; import 'package:solian/widgets/app_bar_title.dart'; -import 'package:solian/widgets/prev_page.dart'; +import 'package:solian/widgets/prev_page.dart' as prev; +import 'package:solian/widgets/drawer_button.dart' as drawer; class TitleShell extends StatelessWidget { final bool showAppBar; @@ -25,12 +26,14 @@ class TitleShell extends StatelessWidget { return Scaffold( appBar: showAppBar ? AppBar( - title: AppBarTitle(state.topRoute?.name?.tr ?? 'page'.tr), - centerTitle: false, - toolbarHeight: SolianTheme.toolbarHeight(context), - leading: canPop ? const PrevPageButton() : null, - automaticallyImplyLeading: false, - ) + title: AppBarTitle(state.topRoute?.name?.tr ?? 'page'.tr), + centerTitle: false, + toolbarHeight: SolianTheme.toolbarHeight(context), + leading: canPop + ? const prev.PrevPageButton() + : const drawer.DrawerButton(), + automaticallyImplyLeading: false, + ) : null, body: child, ); diff --git a/lib/widgets/drawer_button.dart b/lib/widgets/drawer_button.dart new file mode 100644 index 0000000..45e3e74 --- /dev/null +++ b/lib/widgets/drawer_button.dart @@ -0,0 +1,19 @@ +import 'package:flutter/material.dart'; +import 'package:solian/shells/root_shell.dart'; + +class DrawerButton extends StatelessWidget { + const DrawerButton({super.key}); + + void openDrawer() { + rootScaffoldKey.currentState!.openDrawer(); + } + + @override + Widget build(BuildContext context) { + return IconButton( + icon: const Icon(Icons.menu), + tooltip: MaterialLocalizations.of(context).openAppDrawerTooltip, + onPressed: openDrawer, + ); + } +} diff --git a/lib/widgets/navigation/app_navigation_drawer.dart b/lib/widgets/navigation/app_navigation_drawer.dart new file mode 100644 index 0000000..b8e2ffc --- /dev/null +++ b/lib/widgets/navigation/app_navigation_drawer.dart @@ -0,0 +1,35 @@ +import 'package:flutter/material.dart'; +import 'package:solian/router.dart'; +import 'package:solian/shells/root_shell.dart'; +import 'package:solian/widgets/navigation/app_navigation.dart'; + +class AppNavigationDrawer extends StatefulWidget { + const AppNavigationDrawer({super.key}); + + @override + State createState() => _AppNavigationDrawerState(); +} + +class _AppNavigationDrawerState extends State { + int _selectedIndex = 0; + + @override + Widget build(BuildContext context) { + return NavigationDrawer( + selectedIndex: _selectedIndex, + onDestinationSelected: (idx) { + setState(() => _selectedIndex = idx); + AppRouter.instance.goNamed(AppNavigation.destinations[idx].page); + rootScaffoldKey.currentState!.closeDrawer(); + }, + children: [ + ...AppNavigation.destinations.map( + (e) => NavigationDrawerDestination( + icon: e.icon, + label: Text(e.label), + ), + ) + ], + ); + } +}