From ee2cb0c989d2236573c0584829ca4f7c0ee8e436 Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Fri, 15 Nov 2024 23:08:29 +0800 Subject: [PATCH] :dizzy: Optimize nav transition --- lib/main.dart | 4 - lib/providers/navigation.dart | 8 ++ lib/router.dart | 91 +++++++++++++-------- lib/widgets/navigation/app_background.dart | 93 +++++++++++++++------- lib/widgets/navigation/app_scaffold.dart | 32 +++++--- 5 files changed, 150 insertions(+), 78 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index a8952e0..4201c0b 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -13,7 +13,6 @@ import 'package:surface/providers/theme.dart'; import 'package:surface/providers/userinfo.dart'; import 'package:surface/providers/websocket.dart'; import 'package:surface/router.dart'; -import 'package:surface/widgets/navigation/app_scaffold.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); @@ -84,9 +83,6 @@ class AppMainContent extends StatelessWidget { ...context.localizationDelegates, ], routerConfig: appRouter, - builder: (context, child) { - return AppRootScaffold(body: child ?? const SizedBox.shrink()); - }, ); } } diff --git a/lib/providers/navigation.dart b/lib/providers/navigation.dart index 3fb101e..027dea5 100644 --- a/lib/providers/navigation.dart +++ b/lib/providers/navigation.dart @@ -24,6 +24,14 @@ class NavigationProvider extends ChangeNotifier { int? get currentIndex => _currentIndex; + static const List kShowBottomNavScreen = [ + 'home', + 'explore', + 'account', + 'album', + 'chat', + ]; + static const List kAllDestination = [ AppNavDestination( icon: Icon(Symbols.home, weight: 400, opticalSize: 20), diff --git a/lib/router.dart b/lib/router.dart index 82c6bb0..c9ecd95 100644 --- a/lib/router.dart +++ b/lib/router.dart @@ -1,3 +1,4 @@ +import 'package:animations/animations.dart'; import 'package:go_router/go_router.dart'; import 'package:surface/screens/account.dart'; import 'package:surface/screens/account/profile_edit.dart'; @@ -14,13 +15,13 @@ import 'package:surface/screens/post/post_detail.dart'; import 'package:surface/screens/post/post_editor.dart'; import 'package:surface/screens/settings.dart'; import 'package:surface/types/post.dart'; +import 'package:surface/widgets/navigation/app_background.dart'; import 'package:surface/widgets/navigation/app_scaffold.dart'; final _appRoutes = [ ShellRoute( - builder: (context, state, child) => AppScaffold( + builder: (context, state, child) => AppPageScaffold( body: child, - showBottomNavigation: true, showAppBar: false, ), routes: [ @@ -37,6 +38,52 @@ final _appRoutes = [ pageBuilder: (context, state) => NoTransitionPage( child: const ExploreScreen(), ), + routes: [ + GoRoute( + path: '/post/write/:mode', + name: 'postEditor', + pageBuilder: (context, state) => CustomTransitionPage( + child: PostEditorScreen( + mode: state.pathParameters['mode']!, + postEditId: int.tryParse( + state.uri.queryParameters['editing'] ?? '', + ), + postReplyId: int.tryParse( + state.uri.queryParameters['replying'] ?? '', + ), + postRepostId: int.tryParse( + state.uri.queryParameters['reposting'] ?? '', + ), + ), + transitionsBuilder: + (context, animation, secondaryAnimation, child) { + return FadeThroughTransition( + animation: animation, + secondaryAnimation: secondaryAnimation, + child: AppBackground(isLessOptimization: true, child: child), + ); + }, + ), + ), + GoRoute( + path: '/post/:slug', + name: 'postDetail', + pageBuilder: (context, state) => CustomTransitionPage( + child: PostDetailScreen( + slug: state.pathParameters['slug']!, + preload: state.extra as SnPost?, + ), + transitionsBuilder: + (context, animation, secondaryAnimation, child) { + return FadeThroughTransition( + animation: animation, + secondaryAnimation: secondaryAnimation, + child: AppBackground(isLessOptimization: true, child: child), + ); + }, + ), + ), + ], ), GoRoute( path: '/account', @@ -62,36 +109,7 @@ final _appRoutes = [ ], ), ShellRoute( - builder: (context, state, child) => child, - routes: [ - GoRoute( - path: '/post/write/:mode', - name: 'postEditor', - builder: (context, state) => PostEditorScreen( - mode: state.pathParameters['mode']!, - postEditId: int.tryParse( - state.uri.queryParameters['editing'] ?? '', - ), - postReplyId: int.tryParse( - state.uri.queryParameters['replying'] ?? '', - ), - postRepostId: int.tryParse( - state.uri.queryParameters['reposting'] ?? '', - ), - ), - ), - GoRoute( - path: '/post/:slug', - name: 'postDetail', - builder: (context, state) => PostDetailScreen( - slug: state.pathParameters['slug']!, - preload: state.extra as SnPost?, - ), - ) - ], - ), - ShellRoute( - builder: (context, state, child) => AppScaffold(body: child), + builder: (context, state, child) => AppPageScaffold(body: child), routes: [ GoRoute( path: '/auth/login', @@ -128,7 +146,7 @@ final _appRoutes = [ ], ), ShellRoute( - builder: (context, state, child) => AppScaffold(body: child), + builder: (context, state, child) => AppPageScaffold(body: child), routes: [ GoRoute( path: '/settings', @@ -140,5 +158,10 @@ final _appRoutes = [ ]; final appRouter = GoRouter( - routes: _appRoutes, + routes: [ + ShellRoute( + routes: _appRoutes, + builder: (context, state, child) => AppRootScaffold(body: child), + ), + ], ); diff --git a/lib/widgets/navigation/app_background.dart b/lib/widgets/navigation/app_background.dart index 2b2bbc0..2980ea1 100644 --- a/lib/widgets/navigation/app_background.dart +++ b/lib/widgets/navigation/app_background.dart @@ -6,12 +6,72 @@ import 'package:path_provider/path_provider.dart'; class AppBackground extends StatelessWidget { final Widget child; - const AppBackground({super.key, required this.child}); + final bool isLessOptimization; + const AppBackground({ + super.key, + required this.child, + this.isLessOptimization = false, + }); + + Widget _buildWithBackgroundImage( + BuildContext context, + File imageFile, + Widget child, + ) { + final devicePixelRatio = MediaQuery.of(context).devicePixelRatio; + + if (isLessOptimization) { + final size = MediaQuery.of(context).size; + return Container( + color: Theme.of(context).colorScheme.surface, + child: Container( + decoration: BoxDecoration( + backgroundBlendMode: BlendMode.darken, + color: Theme.of(context).colorScheme.surface, + image: DecorationImage( + opacity: 0.2, + image: ResizeImage( + FileImage(imageFile), + width: (size.width * devicePixelRatio).round(), + height: (size.height * devicePixelRatio).round(), + policy: ResizeImagePolicy.fit, + ), + fit: BoxFit.cover, + ), + ), + child: child, + ), + ); + } + + return Container( + color: Theme.of(context).colorScheme.surface, + child: LayoutBuilder( + builder: (context, constraints) { + return Container( + decoration: BoxDecoration( + backgroundBlendMode: BlendMode.darken, + color: Theme.of(context).colorScheme.surface, + image: DecorationImage( + opacity: 0.2, + image: ResizeImage( + FileImage(imageFile), + width: (constraints.maxWidth * devicePixelRatio).round(), + height: (constraints.maxHeight * devicePixelRatio).round(), + policy: ResizeImagePolicy.fit, + ), + fit: BoxFit.cover, + ), + ), + child: child, + ); + }, + ), + ); + } @override Widget build(BuildContext context) { - final devicePixelRatio = MediaQuery.of(context).devicePixelRatio; - return ScaffoldMessenger( child: FutureBuilder( future: @@ -21,32 +81,7 @@ class AppBackground extends StatelessWidget { final path = '${snapshot.data!.path}/app_background_image'; final file = File(path); if (file.existsSync()) { - return Container( - color: Theme.of(context).colorScheme.surface, - child: LayoutBuilder( - builder: (context, constraints) { - return Container( - decoration: BoxDecoration( - backgroundBlendMode: BlendMode.darken, - color: Theme.of(context).colorScheme.surface, - image: DecorationImage( - opacity: 0.2, - image: ResizeImage( - FileImage(file), - width: (constraints.maxWidth * devicePixelRatio) - .round(), - height: (constraints.maxHeight * devicePixelRatio) - .round(), - policy: ResizeImagePolicy.fit, - ), - fit: BoxFit.cover, - ), - ), - child: child, - ); - }, - ), - ); + return _buildWithBackgroundImage(context, file, child); } } diff --git a/lib/widgets/navigation/app_scaffold.dart b/lib/widgets/navigation/app_scaffold.dart index 2a238ff..267516b 100644 --- a/lib/widgets/navigation/app_scaffold.dart +++ b/lib/widgets/navigation/app_scaffold.dart @@ -2,6 +2,7 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:responsive_framework/responsive_framework.dart'; +import 'package:surface/providers/navigation.dart'; import 'package:surface/widgets/connection_indicator.dart'; import 'package:surface/widgets/dialog.dart'; import 'package:surface/widgets/navigation/app_background.dart'; @@ -9,12 +10,12 @@ import 'package:surface/widgets/navigation/app_bottom_navigation.dart'; import 'package:surface/widgets/navigation/app_drawer_navigation.dart'; import 'package:surface/widgets/navigation/app_rail_navigation.dart'; -class AppScaffold extends StatelessWidget { +class AppPageScaffold extends StatelessWidget { final String? title; final Widget? body; final bool showAppBar; final bool showBottomNavigation; - const AppScaffold({ + const AppPageScaffold({ super.key, this.title, this.body, @@ -24,14 +25,12 @@ class AppScaffold extends StatelessWidget { @override Widget build(BuildContext context) { - final isShowBottomNavigation = (showBottomNavigation) - ? ResponsiveBreakpoints.of(context).smallerOrEqualTo(MOBILE) - : false; - final state = GoRouter.maybeOf(context); - final autoTitle = state != null - ? 'screen${state.routerDelegate.currentConfiguration.last.route.name?.capitalize()}' - : 'screen'; + final routeName = + state?.routerDelegate.currentConfiguration.last.route.name; + + final autoTitle = + state != null ? 'screen${routeName?.capitalize()}' : 'screen'; return Scaffold( appBar: showAppBar @@ -40,8 +39,6 @@ class AppScaffold extends StatelessWidget { ) : null, body: body, - bottomNavigationBar: - isShowBottomNavigation ? AppBottomNavigationBar() : null, ); } } @@ -58,6 +55,17 @@ class AppRootScaffold extends StatelessWidget { ResponsiveBreakpoints.of(context).smallerOrEqualTo(MOBILE); final isExpandDrawer = ResponsiveBreakpoints.of(context).largerThan(TABLET); + final routeName = GoRouter.of(context) + .routerDelegate + .currentConfiguration + .last + .route + .name; + final isShowBottomNavigation = + NavigationProvider.kShowBottomNavScreen.contains(routeName) + ? ResponsiveBreakpoints.of(context).smallerOrEqualTo(MOBILE) + : false; + final innerWidget = isCollapseDrawer ? body : Row( @@ -88,6 +96,8 @@ class AppRootScaffold extends StatelessWidget { ], ), drawer: !isExpandDrawer ? AppNavigationDrawer() : null, + bottomNavigationBar: + isShowBottomNavigation ? AppBottomNavigationBar() : null, ), ); }