✨ Drawer navigation
This commit is contained in:
parent
a6d8e2e311
commit
3b1b6ec8d6
@ -19,6 +19,7 @@ import 'package:solian/providers/content/realm.dart';
|
|||||||
import 'package:solian/providers/friend.dart';
|
import 'package:solian/providers/friend.dart';
|
||||||
import 'package:solian/providers/account_status.dart';
|
import 'package:solian/providers/account_status.dart';
|
||||||
import 'package:solian/router.dart';
|
import 'package:solian/router.dart';
|
||||||
|
import 'package:solian/shells/root_shell.dart';
|
||||||
import 'package:solian/shells/system_shell.dart';
|
import 'package:solian/shells/system_shell.dart';
|
||||||
import 'package:solian/theme.dart';
|
import 'package:solian/theme.dart';
|
||||||
import 'package:solian/translations.dart';
|
import 'package:solian/translations.dart';
|
||||||
@ -87,9 +88,11 @@ class SolianApp extends StatelessWidget {
|
|||||||
onInit: () => _initializeProviders(context),
|
onInit: () => _initializeProviders(context),
|
||||||
builder: (context, child) {
|
builder: (context, child) {
|
||||||
return SystemShell(
|
return SystemShell(
|
||||||
|
child: RootShell(
|
||||||
child: ScaffoldMessenger(
|
child: ScaffoldMessenger(
|
||||||
child: child ?? const SizedBox(),
|
child: child ?? const SizedBox(),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -20,27 +20,18 @@ import 'package:solian/screens/realms/realm_view.dart';
|
|||||||
import 'package:solian/screens/feed.dart';
|
import 'package:solian/screens/feed.dart';
|
||||||
import 'package:solian/screens/posts/post_editor.dart';
|
import 'package:solian/screens/posts/post_editor.dart';
|
||||||
import 'package:solian/shells/basic_shell.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/shells/title_shell.dart';
|
||||||
import 'package:solian/theme.dart';
|
import 'package:solian/theme.dart';
|
||||||
import 'package:solian/widgets/sidebar/empty_placeholder.dart';
|
import 'package:solian/widgets/sidebar/empty_placeholder.dart';
|
||||||
|
|
||||||
abstract class AppRouter {
|
abstract class AppRouter {
|
||||||
static GoRouter instance = GoRouter(
|
static GoRouter instance = GoRouter(
|
||||||
routes: [
|
|
||||||
ShellRoute(
|
|
||||||
builder: (context, state, child) => RootShell(
|
|
||||||
state: state,
|
|
||||||
child: child,
|
|
||||||
),
|
|
||||||
routes: [
|
routes: [
|
||||||
_feedRoute,
|
_feedRoute,
|
||||||
_chatRoute,
|
_chatRoute,
|
||||||
_realmRoute,
|
_realmRoute,
|
||||||
_accountRoute,
|
_accountRoute,
|
||||||
],
|
],
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
|
|
||||||
static final ShellRoute _feedRoute = ShellRoute(
|
static final ShellRoute _feedRoute = ShellRoute(
|
||||||
@ -232,7 +223,7 @@ abstract class AppRouter {
|
|||||||
name: 'account',
|
name: 'account',
|
||||||
builder: (context, state) => SolianTheme.isExtraLargeScreen(context)
|
builder: (context, state) => SolianTheme.isExtraLargeScreen(context)
|
||||||
? const EmptyPagePlaceholder()
|
? const EmptyPagePlaceholder()
|
||||||
: const AccountScreen(),
|
: TitleShell(state: state, child: const AccountScreen()),
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: '/account/friend',
|
path: '/account/friend',
|
||||||
|
@ -87,7 +87,7 @@ class _AccountScreenState extends State<AccountScreen> {
|
|||||||
|
|
||||||
return ListView(
|
return ListView(
|
||||||
children: [
|
children: [
|
||||||
const AccountHeading().paddingOnly(bottom: 8, top: 16),
|
const AccountHeading().paddingOnly(bottom: 8, top: 8),
|
||||||
...(actionItems.map(
|
...(actionItems.map(
|
||||||
(x) => ListTile(
|
(x) => ListTile(
|
||||||
contentPadding: const EdgeInsets.symmetric(horizontal: 34),
|
contentPadding: const EdgeInsets.symmetric(horizontal: 34),
|
||||||
|
@ -12,6 +12,7 @@ import 'package:solian/widgets/app_bar_title.dart';
|
|||||||
import 'package:solian/widgets/channel/channel_list.dart';
|
import 'package:solian/widgets/channel/channel_list.dart';
|
||||||
import 'package:solian/widgets/chat/call/chat_call_indicator.dart';
|
import 'package:solian/widgets/chat/call/chat_call_indicator.dart';
|
||||||
import 'package:solian/widgets/current_state_action.dart';
|
import 'package:solian/widgets/current_state_action.dart';
|
||||||
|
import 'package:solian/widgets/drawer_button.dart' as drawer;
|
||||||
|
|
||||||
class ChatScreen extends StatefulWidget {
|
class ChatScreen extends StatefulWidget {
|
||||||
const ChatScreen({super.key});
|
const ChatScreen({super.key});
|
||||||
@ -94,7 +95,7 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||||||
title: AppBarTitle('chat'.tr),
|
title: AppBarTitle('chat'.tr),
|
||||||
centerTitle: false,
|
centerTitle: false,
|
||||||
floating: true,
|
floating: true,
|
||||||
titleSpacing: SolianTheme.titleSpacing(context),
|
leading: const drawer.DrawerButton(),
|
||||||
toolbarHeight: SolianTheme.toolbarHeight(context),
|
toolbarHeight: SolianTheme.toolbarHeight(context),
|
||||||
actions: [
|
actions: [
|
||||||
const BackgroundStateWidget(),
|
const BackgroundStateWidget(),
|
||||||
@ -191,7 +192,8 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||||||
child: RefreshIndicator(
|
child: RefreshIndicator(
|
||||||
onRefresh: () => getChannels(),
|
onRefresh: () => getChannels(),
|
||||||
child: ChannelListWidget(
|
child: ChannelListWidget(
|
||||||
channels: _channels.where((x) => x.type == 1).toList(),
|
channels:
|
||||||
|
_channels.where((x) => x.type == 1).toList(),
|
||||||
selfId: _accountId ?? 0,
|
selfId: _accountId ?? 0,
|
||||||
noCategory: true,
|
noCategory: true,
|
||||||
),
|
),
|
||||||
|
@ -11,6 +11,7 @@ import 'package:solian/theme.dart';
|
|||||||
import 'package:solian/widgets/app_bar_title.dart';
|
import 'package:solian/widgets/app_bar_title.dart';
|
||||||
import 'package:solian/widgets/current_state_action.dart';
|
import 'package:solian/widgets/current_state_action.dart';
|
||||||
import 'package:solian/widgets/feed/feed_list.dart';
|
import 'package:solian/widgets/feed/feed_list.dart';
|
||||||
|
import 'package:solian/widgets/drawer_button.dart' as drawer;
|
||||||
|
|
||||||
class FeedScreen extends StatefulWidget {
|
class FeedScreen extends StatefulWidget {
|
||||||
const FeedScreen({super.key});
|
const FeedScreen({super.key});
|
||||||
@ -62,8 +63,8 @@ class _FeedScreenState extends State<FeedScreen> {
|
|||||||
title: AppBarTitle('feed'.tr),
|
title: AppBarTitle('feed'.tr),
|
||||||
centerTitle: false,
|
centerTitle: false,
|
||||||
floating: true,
|
floating: true,
|
||||||
titleSpacing: SolianTheme.titleSpacing(context),
|
|
||||||
toolbarHeight: SolianTheme.toolbarHeight(context),
|
toolbarHeight: SolianTheme.toolbarHeight(context),
|
||||||
|
leading: const drawer.DrawerButton(),
|
||||||
actions: [
|
actions: [
|
||||||
const BackgroundStateWidget(),
|
const BackgroundStateWidget(),
|
||||||
const NotificationButton(),
|
const NotificationButton(),
|
||||||
|
@ -11,6 +11,7 @@ import 'package:solian/theme.dart';
|
|||||||
import 'package:solian/widgets/account/signin_required_overlay.dart';
|
import 'package:solian/widgets/account/signin_required_overlay.dart';
|
||||||
import 'package:solian/widgets/app_bar_title.dart';
|
import 'package:solian/widgets/app_bar_title.dart';
|
||||||
import 'package:solian/widgets/current_state_action.dart';
|
import 'package:solian/widgets/current_state_action.dart';
|
||||||
|
import 'package:solian/widgets/drawer_button.dart' as drawer;
|
||||||
|
|
||||||
class RealmListScreen extends StatefulWidget {
|
class RealmListScreen extends StatefulWidget {
|
||||||
const RealmListScreen({super.key});
|
const RealmListScreen({super.key});
|
||||||
@ -79,7 +80,7 @@ class _RealmListScreenState extends State<RealmListScreen> {
|
|||||||
title: AppBarTitle('realm'.tr),
|
title: AppBarTitle('realm'.tr),
|
||||||
centerTitle: false,
|
centerTitle: false,
|
||||||
floating: true,
|
floating: true,
|
||||||
titleSpacing: SolianTheme.titleSpacing(context),
|
leading: const drawer.DrawerButton(),
|
||||||
toolbarHeight: SolianTheme.toolbarHeight(context),
|
toolbarHeight: SolianTheme.toolbarHeight(context),
|
||||||
actions: [
|
actions: [
|
||||||
const BackgroundStateWidget(),
|
const BackgroundStateWidget(),
|
||||||
|
@ -1,36 +1,33 @@
|
|||||||
import 'package:flutter/material.dart';
|
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/theme.dart';
|
||||||
import 'package:solian/widgets/navigation/app_navigation.dart';
|
import 'package:solian/widgets/navigation/app_navigation_drawer.dart';
|
||||||
import 'package:solian/widgets/navigation/app_navigation_bottom_bar.dart';
|
|
||||||
import 'package:solian/widgets/navigation/app_navigation_rail.dart';
|
import 'package:solian/widgets/navigation/app_navigation_rail.dart';
|
||||||
|
|
||||||
|
final GlobalKey<ScaffoldState> rootScaffoldKey = GlobalKey<ScaffoldState>();
|
||||||
|
|
||||||
class RootShell extends StatelessWidget {
|
class RootShell extends StatelessWidget {
|
||||||
final bool showSidebar;
|
final bool showSidebar;
|
||||||
final bool showNavigation;
|
final bool showNavigation;
|
||||||
final bool? showBottomNavigation;
|
final bool? showBottomNavigation;
|
||||||
final GoRouterState state;
|
|
||||||
final Widget child;
|
final Widget child;
|
||||||
|
|
||||||
const RootShell({
|
const RootShell({
|
||||||
super.key,
|
super.key,
|
||||||
required this.state,
|
|
||||||
required this.child,
|
required this.child,
|
||||||
this.showSidebar = true,
|
this.showSidebar = true,
|
||||||
this.showNavigation = true,
|
this.showNavigation = true,
|
||||||
this.showBottomNavigation,
|
this.showBottomNavigation,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
void closeDrawer() {
|
||||||
|
rootScaffoldKey.currentState!.closeDrawer();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final routeName = AppRouter
|
|
||||||
.instance.routerDelegate.currentConfiguration.lastOrNull?.route.name;
|
|
||||||
final showBottom = showBottomNavigation ??
|
|
||||||
AppNavigation.destinationPages.contains(routeName);
|
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
|
key: rootScaffoldKey,
|
||||||
|
drawer: const AppNavigationDrawer(),
|
||||||
body: SolianTheme.isLargeScreen(context)
|
body: SolianTheme.isLargeScreen(context)
|
||||||
? Row(
|
? Row(
|
||||||
children: [
|
children: [
|
||||||
@ -40,24 +37,7 @@ class RootShell extends StatelessWidget {
|
|||||||
Expanded(child: child),
|
Expanded(child: child),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
: Stack(
|
: child,
|
||||||
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,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,8 @@ import 'package:go_router/go_router.dart';
|
|||||||
import 'package:solian/router.dart';
|
import 'package:solian/router.dart';
|
||||||
import 'package:solian/theme.dart';
|
import 'package:solian/theme.dart';
|
||||||
import 'package:solian/widgets/app_bar_title.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 {
|
class TitleShell extends StatelessWidget {
|
||||||
final bool showAppBar;
|
final bool showAppBar;
|
||||||
@ -28,7 +29,9 @@ class TitleShell extends StatelessWidget {
|
|||||||
title: AppBarTitle(state.topRoute?.name?.tr ?? 'page'.tr),
|
title: AppBarTitle(state.topRoute?.name?.tr ?? 'page'.tr),
|
||||||
centerTitle: false,
|
centerTitle: false,
|
||||||
toolbarHeight: SolianTheme.toolbarHeight(context),
|
toolbarHeight: SolianTheme.toolbarHeight(context),
|
||||||
leading: canPop ? const PrevPageButton() : null,
|
leading: canPop
|
||||||
|
? const prev.PrevPageButton()
|
||||||
|
: const drawer.DrawerButton(),
|
||||||
automaticallyImplyLeading: false,
|
automaticallyImplyLeading: false,
|
||||||
)
|
)
|
||||||
: null,
|
: null,
|
||||||
|
19
lib/widgets/drawer_button.dart
Normal file
19
lib/widgets/drawer_button.dart
Normal file
@ -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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
35
lib/widgets/navigation/app_navigation_drawer.dart
Normal file
35
lib/widgets/navigation/app_navigation_drawer.dart
Normal file
@ -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<AppNavigationDrawer> createState() => _AppNavigationDrawerState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _AppNavigationDrawerState extends State<AppNavigationDrawer> {
|
||||||
|
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),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user