diff --git a/lib/ui/favourites/favourites_screen.dart b/lib/ui/favourites/favourites_screen.dart index 45e8771..be40137 100644 --- a/lib/ui/favourites/favourites_screen.dart +++ b/lib/ui/favourites/favourites_screen.dart @@ -7,6 +7,7 @@ import '../../data/recipes/recipe_service.dart'; import '../../data/recipes/models/recipe_model.dart'; import '../add_recipe/add_recipe_screen.dart'; import '../photo_gallery/photo_gallery_screen.dart'; +import '../navigation/material3_page_route.dart'; /// Favourites screen displaying user's favorite recipes. class FavouritesScreen extends StatefulWidget { @@ -165,8 +166,9 @@ class _FavouritesScreenState extends State { void _viewRecipe(RecipeModel recipe) async { await Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => AddRecipeScreen(recipe: recipe, viewMode: true), + Material3PageRoute( + child: AddRecipeScreen(recipe: recipe, viewMode: true), + useEmphasized: true, // Use emphasized easing for more fluid feel ), ); // Reload favourites after viewing (in case favorite was toggled) @@ -177,8 +179,9 @@ class _FavouritesScreenState extends State { void _editRecipe(RecipeModel recipe) async { final result = await Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => AddRecipeScreen(recipe: recipe), + Material3PageRoute( + child: AddRecipeScreen(recipe: recipe), + useEmphasized: true, // Use emphasized easing for more fluid feel ), ); if (result == true || mounted) { diff --git a/lib/ui/home/home_screen.dart b/lib/ui/home/home_screen.dart index 0ad7934..5d16fd1 100644 --- a/lib/ui/home/home_screen.dart +++ b/lib/ui/home/home_screen.dart @@ -6,6 +6,7 @@ import '../../data/recipes/models/recipe_model.dart'; import '../shared/primary_app_bar.dart'; import '../add_recipe/add_recipe_screen.dart'; import '../navigation/main_navigation_scaffold.dart'; +import '../navigation/material3_page_route.dart'; import 'package:video_player/video_player.dart'; /// Home screen showing recipes overview, stats, tags, and favorites. @@ -90,8 +91,9 @@ class _HomeScreenState extends State { void _navigateToRecipe(RecipeModel recipe) async { final result = await Navigator.push( context, - MaterialPageRoute( - builder: (context) => AddRecipeScreen(recipe: recipe, viewMode: true), + Material3PageRoute( + child: AddRecipeScreen(recipe: recipe, viewMode: true), + useEmphasized: true, // Use emphasized easing for more fluid feel ), ); // Reload data if recipe was edited diff --git a/lib/ui/navigation/material3_page_route.dart b/lib/ui/navigation/material3_page_route.dart new file mode 100644 index 0000000..d05c581 --- /dev/null +++ b/lib/ui/navigation/material3_page_route.dart @@ -0,0 +1,74 @@ +import 'package:flutter/material.dart'; + +/// Material Design 3 easing curves +/// Reference: https://m3.material.io/styles/motion/easing-and-duration/applying-easing-and-duration +class Material3Easing { + /// Standard easing curve for entering animations + /// Cubic(0.2, 0, 0, 1) + static const Curve standardEnter = Cubic(0.2, 0, 0, 1); + + /// Standard easing curve for exiting animations + /// Cubic(0, 0, 0.2, 1) + static const Curve standardExit = Cubic(0, 0, 0.2, 1); + + /// Emphasized easing curve for entering animations + /// Cubic(0.2, 0, 0, 1) + static const Curve emphasizedEnter = Cubic(0.2, 0, 0, 1); + + /// Emphasized easing curve for exiting animations + /// Cubic(0.05, 0.7, 0.1, 1) + static const Curve emphasizedExit = Cubic(0.05, 0.7, 0.1, 1); +} + +/// Material Design 3 page route with custom easing animations. +/// +/// Uses Material Design 3 motion guidelines for smooth, fluid transitions. +/// Reference: https://m3.material.io/styles/motion/easing-and-duration/applying-easing-and-duration +class Material3PageRoute extends PageRouteBuilder { + final Widget child; + final bool useEmphasized; + + Material3PageRoute({ + required this.child, + this.useEmphasized = false, + RouteSettings? settings, + }) : super( + pageBuilder: (context, animation, secondaryAnimation) => child, + transitionDuration: useEmphasized + ? const Duration(milliseconds: 400) + : const Duration(milliseconds: 300), + reverseTransitionDuration: useEmphasized + ? const Duration(milliseconds: 400) + : const Duration(milliseconds: 300), + settings: settings, + transitionsBuilder: (context, animation, secondaryAnimation, child) { + // Use Material Design 3 easing curves + final enterCurve = useEmphasized + ? Material3Easing.emphasizedEnter + : Material3Easing.standardEnter; + final exitCurve = useEmphasized + ? Material3Easing.emphasizedExit + : Material3Easing.standardExit; + + // Apply easing curves to animations + final curvedAnimation = CurvedAnimation( + parent: animation, + curve: enterCurve, + reverseCurve: exitCurve, + ); + + // Slide transition with fade + return SlideTransition( + position: Tween( + begin: const Offset(0.0, 0.05), // Slight upward slide + end: Offset.zero, + ).animate(curvedAnimation), + child: FadeTransition( + opacity: curvedAnimation, + child: child, + ), + ); + }, + ); +} + diff --git a/lib/ui/recipes/recipes_screen.dart b/lib/ui/recipes/recipes_screen.dart index 7ef725c..126b2c7 100644 --- a/lib/ui/recipes/recipes_screen.dart +++ b/lib/ui/recipes/recipes_screen.dart @@ -9,6 +9,7 @@ import '../../data/local/models/item.dart'; import '../add_recipe/add_recipe_screen.dart'; import '../photo_gallery/photo_gallery_screen.dart'; import '../navigation/main_navigation_scaffold.dart'; +import '../navigation/material3_page_route.dart'; import 'bookmark_dialog.dart'; import '../../data/recipes/models/bookmark_category_model.dart'; @@ -382,8 +383,9 @@ class _RecipesScreenState extends State with WidgetsBindingObserv void _viewRecipe(RecipeModel recipe) async { await Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => AddRecipeScreen(recipe: recipe, viewMode: true), + Material3PageRoute( + child: AddRecipeScreen(recipe: recipe, viewMode: true), + useEmphasized: true, // Use emphasized easing for more fluid feel ), ); // Always reload recipes after viewing/editing to ensure UI is up-to-date