💫 Optimize nav transition
This commit is contained in:
parent
37c61a0406
commit
ee2cb0c989
@ -13,7 +13,6 @@ import 'package:surface/providers/theme.dart';
|
|||||||
import 'package:surface/providers/userinfo.dart';
|
import 'package:surface/providers/userinfo.dart';
|
||||||
import 'package:surface/providers/websocket.dart';
|
import 'package:surface/providers/websocket.dart';
|
||||||
import 'package:surface/router.dart';
|
import 'package:surface/router.dart';
|
||||||
import 'package:surface/widgets/navigation/app_scaffold.dart';
|
|
||||||
|
|
||||||
void main() async {
|
void main() async {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
@ -84,9 +83,6 @@ class AppMainContent extends StatelessWidget {
|
|||||||
...context.localizationDelegates,
|
...context.localizationDelegates,
|
||||||
],
|
],
|
||||||
routerConfig: appRouter,
|
routerConfig: appRouter,
|
||||||
builder: (context, child) {
|
|
||||||
return AppRootScaffold(body: child ?? const SizedBox.shrink());
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,14 @@ class NavigationProvider extends ChangeNotifier {
|
|||||||
|
|
||||||
int? get currentIndex => _currentIndex;
|
int? get currentIndex => _currentIndex;
|
||||||
|
|
||||||
|
static const List<String> kShowBottomNavScreen = [
|
||||||
|
'home',
|
||||||
|
'explore',
|
||||||
|
'account',
|
||||||
|
'album',
|
||||||
|
'chat',
|
||||||
|
];
|
||||||
|
|
||||||
static const List<AppNavDestination> kAllDestination = [
|
static const List<AppNavDestination> kAllDestination = [
|
||||||
AppNavDestination(
|
AppNavDestination(
|
||||||
icon: Icon(Symbols.home, weight: 400, opticalSize: 20),
|
icon: Icon(Symbols.home, weight: 400, opticalSize: 20),
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import 'package:animations/animations.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:surface/screens/account.dart';
|
import 'package:surface/screens/account.dart';
|
||||||
import 'package:surface/screens/account/profile_edit.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/post/post_editor.dart';
|
||||||
import 'package:surface/screens/settings.dart';
|
import 'package:surface/screens/settings.dart';
|
||||||
import 'package:surface/types/post.dart';
|
import 'package:surface/types/post.dart';
|
||||||
|
import 'package:surface/widgets/navigation/app_background.dart';
|
||||||
import 'package:surface/widgets/navigation/app_scaffold.dart';
|
import 'package:surface/widgets/navigation/app_scaffold.dart';
|
||||||
|
|
||||||
final _appRoutes = [
|
final _appRoutes = [
|
||||||
ShellRoute(
|
ShellRoute(
|
||||||
builder: (context, state, child) => AppScaffold(
|
builder: (context, state, child) => AppPageScaffold(
|
||||||
body: child,
|
body: child,
|
||||||
showBottomNavigation: true,
|
|
||||||
showAppBar: false,
|
showAppBar: false,
|
||||||
),
|
),
|
||||||
routes: [
|
routes: [
|
||||||
@ -37,6 +38,52 @@ final _appRoutes = [
|
|||||||
pageBuilder: (context, state) => NoTransitionPage(
|
pageBuilder: (context, state) => NoTransitionPage(
|
||||||
child: const ExploreScreen(),
|
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(
|
GoRoute(
|
||||||
path: '/account',
|
path: '/account',
|
||||||
@ -62,36 +109,7 @@ final _appRoutes = [
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
ShellRoute(
|
ShellRoute(
|
||||||
builder: (context, state, child) => child,
|
builder: (context, state, child) => AppPageScaffold(body: 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),
|
|
||||||
routes: [
|
routes: [
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: '/auth/login',
|
path: '/auth/login',
|
||||||
@ -128,7 +146,7 @@ final _appRoutes = [
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
ShellRoute(
|
ShellRoute(
|
||||||
builder: (context, state, child) => AppScaffold(body: child),
|
builder: (context, state, child) => AppPageScaffold(body: child),
|
||||||
routes: [
|
routes: [
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: '/settings',
|
path: '/settings',
|
||||||
@ -140,5 +158,10 @@ final _appRoutes = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
final appRouter = GoRouter(
|
final appRouter = GoRouter(
|
||||||
|
routes: [
|
||||||
|
ShellRoute(
|
||||||
routes: _appRoutes,
|
routes: _appRoutes,
|
||||||
|
builder: (context, state, child) => AppRootScaffold(body: child),
|
||||||
|
),
|
||||||
|
],
|
||||||
);
|
);
|
||||||
|
@ -6,21 +6,44 @@ import 'package:path_provider/path_provider.dart';
|
|||||||
|
|
||||||
class AppBackground extends StatelessWidget {
|
class AppBackground extends StatelessWidget {
|
||||||
final Widget child;
|
final Widget child;
|
||||||
const AppBackground({super.key, required this.child});
|
final bool isLessOptimization;
|
||||||
|
const AppBackground({
|
||||||
|
super.key,
|
||||||
|
required this.child,
|
||||||
|
this.isLessOptimization = false,
|
||||||
|
});
|
||||||
|
|
||||||
@override
|
Widget _buildWithBackgroundImage(
|
||||||
Widget build(BuildContext context) {
|
BuildContext context,
|
||||||
|
File imageFile,
|
||||||
|
Widget child,
|
||||||
|
) {
|
||||||
final devicePixelRatio = MediaQuery.of(context).devicePixelRatio;
|
final devicePixelRatio = MediaQuery.of(context).devicePixelRatio;
|
||||||
|
|
||||||
return ScaffoldMessenger(
|
if (isLessOptimization) {
|
||||||
child: FutureBuilder(
|
final size = MediaQuery.of(context).size;
|
||||||
future:
|
return Container(
|
||||||
kIsWeb ? Future.value(null) : getApplicationDocumentsDirectory(),
|
color: Theme.of(context).colorScheme.surface,
|
||||||
builder: (context, snapshot) {
|
child: Container(
|
||||||
if (snapshot.hasData) {
|
decoration: BoxDecoration(
|
||||||
final path = '${snapshot.data!.path}/app_background_image';
|
backgroundBlendMode: BlendMode.darken,
|
||||||
final file = File(path);
|
color: Theme.of(context).colorScheme.surface,
|
||||||
if (file.existsSync()) {
|
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(
|
return Container(
|
||||||
color: Theme.of(context).colorScheme.surface,
|
color: Theme.of(context).colorScheme.surface,
|
||||||
child: LayoutBuilder(
|
child: LayoutBuilder(
|
||||||
@ -32,11 +55,9 @@ class AppBackground extends StatelessWidget {
|
|||||||
image: DecorationImage(
|
image: DecorationImage(
|
||||||
opacity: 0.2,
|
opacity: 0.2,
|
||||||
image: ResizeImage(
|
image: ResizeImage(
|
||||||
FileImage(file),
|
FileImage(imageFile),
|
||||||
width: (constraints.maxWidth * devicePixelRatio)
|
width: (constraints.maxWidth * devicePixelRatio).round(),
|
||||||
.round(),
|
height: (constraints.maxHeight * devicePixelRatio).round(),
|
||||||
height: (constraints.maxHeight * devicePixelRatio)
|
|
||||||
.round(),
|
|
||||||
policy: ResizeImagePolicy.fit,
|
policy: ResizeImagePolicy.fit,
|
||||||
),
|
),
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
@ -48,6 +69,20 @@ class AppBackground extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ScaffoldMessenger(
|
||||||
|
child: FutureBuilder(
|
||||||
|
future:
|
||||||
|
kIsWeb ? Future.value(null) : getApplicationDocumentsDirectory(),
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (snapshot.hasData) {
|
||||||
|
final path = '${snapshot.data!.path}/app_background_image';
|
||||||
|
final file = File(path);
|
||||||
|
if (file.existsSync()) {
|
||||||
|
return _buildWithBackgroundImage(context, file, child);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Material(
|
return Material(
|
||||||
|
@ -2,6 +2,7 @@ import 'package:easy_localization/easy_localization.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:responsive_framework/responsive_framework.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/connection_indicator.dart';
|
||||||
import 'package:surface/widgets/dialog.dart';
|
import 'package:surface/widgets/dialog.dart';
|
||||||
import 'package:surface/widgets/navigation/app_background.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_drawer_navigation.dart';
|
||||||
import 'package:surface/widgets/navigation/app_rail_navigation.dart';
|
import 'package:surface/widgets/navigation/app_rail_navigation.dart';
|
||||||
|
|
||||||
class AppScaffold extends StatelessWidget {
|
class AppPageScaffold extends StatelessWidget {
|
||||||
final String? title;
|
final String? title;
|
||||||
final Widget? body;
|
final Widget? body;
|
||||||
final bool showAppBar;
|
final bool showAppBar;
|
||||||
final bool showBottomNavigation;
|
final bool showBottomNavigation;
|
||||||
const AppScaffold({
|
const AppPageScaffold({
|
||||||
super.key,
|
super.key,
|
||||||
this.title,
|
this.title,
|
||||||
this.body,
|
this.body,
|
||||||
@ -24,14 +25,12 @@ class AppScaffold extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final isShowBottomNavigation = (showBottomNavigation)
|
|
||||||
? ResponsiveBreakpoints.of(context).smallerOrEqualTo(MOBILE)
|
|
||||||
: false;
|
|
||||||
|
|
||||||
final state = GoRouter.maybeOf(context);
|
final state = GoRouter.maybeOf(context);
|
||||||
final autoTitle = state != null
|
final routeName =
|
||||||
? 'screen${state.routerDelegate.currentConfiguration.last.route.name?.capitalize()}'
|
state?.routerDelegate.currentConfiguration.last.route.name;
|
||||||
: 'screen';
|
|
||||||
|
final autoTitle =
|
||||||
|
state != null ? 'screen${routeName?.capitalize()}' : 'screen';
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: showAppBar
|
appBar: showAppBar
|
||||||
@ -40,8 +39,6 @@ class AppScaffold extends StatelessWidget {
|
|||||||
)
|
)
|
||||||
: null,
|
: null,
|
||||||
body: body,
|
body: body,
|
||||||
bottomNavigationBar:
|
|
||||||
isShowBottomNavigation ? AppBottomNavigationBar() : null,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -58,6 +55,17 @@ class AppRootScaffold extends StatelessWidget {
|
|||||||
ResponsiveBreakpoints.of(context).smallerOrEqualTo(MOBILE);
|
ResponsiveBreakpoints.of(context).smallerOrEqualTo(MOBILE);
|
||||||
final isExpandDrawer = ResponsiveBreakpoints.of(context).largerThan(TABLET);
|
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
|
final innerWidget = isCollapseDrawer
|
||||||
? body
|
? body
|
||||||
: Row(
|
: Row(
|
||||||
@ -88,6 +96,8 @@ class AppRootScaffold extends StatelessWidget {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
drawer: !isExpandDrawer ? AppNavigationDrawer() : null,
|
drawer: !isExpandDrawer ? AppNavigationDrawer() : null,
|
||||||
|
bottomNavigationBar:
|
||||||
|
isShowBottomNavigation ? AppBottomNavigationBar() : null,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user