From 85d0b8ef56199557e191854706cabe7ede921699 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Thu, 15 Sep 2022 22:53:04 +0200 Subject: [PATCH] Page transitions (#206) Close: #184 --- lib/src/themes/common_themes.dart | 15 +-- lib/src/themes/page_transitions.dart | 151 +++++++++++++++++++++++++++ lib/yaru.dart | 1 + 3 files changed, 155 insertions(+), 12 deletions(-) create mode 100644 lib/src/themes/page_transitions.dart diff --git a/lib/src/themes/common_themes.dart b/lib/src/themes/common_themes.dart index d334d1bb7..1f53a7839 100644 --- a/lib/src/themes/common_themes.dart +++ b/lib/src/themes/common_themes.dart @@ -3,6 +3,7 @@ import 'package:flutter/services.dart'; import 'package:yaru_colors/yaru_colors.dart'; import 'package:yaru/src/text/text_theme.dart'; import 'package:yaru/src/themes/constants.dart'; +import 'package:yaru/src/themes/page_transitions.dart'; // AppBar @@ -241,16 +242,6 @@ RadioThemeData _getRadioThemeData(Color primaryColor, Brightness brightness) { ); } -const _desktopPageTransitionsBuilder = CupertinoPageTransitionsBuilder(); - -const _pageTransitionTheme = PageTransitionsTheme( - builders: { - TargetPlatform.linux: _desktopPageTransitionsBuilder, - TargetPlatform.macOS: _desktopPageTransitionsBuilder, - TargetPlatform.windows: _desktopPageTransitionsBuilder, - }, -); - /// Helper function to create a new Yaru light theme ThemeData createYaruLightTheme({ required ColorScheme colorScheme, @@ -259,7 +250,7 @@ ThemeData createYaruLightTheme({ bool? useMaterial3 = true, }) { return ThemeData( - pageTransitionsTheme: _pageTransitionTheme, + pageTransitionsTheme: YaruPageTransitionsTheme.horizontal, useMaterial3: useMaterial3, tabBarTheme: TabBarTheme(labelColor: colorScheme.onSurface), dialogTheme: _dialogThemeLight, @@ -307,7 +298,7 @@ ThemeData createYaruDarkTheme({ bool? useMaterial3 = true, }) { return ThemeData( - pageTransitionsTheme: _pageTransitionTheme, + pageTransitionsTheme: YaruPageTransitionsTheme.horizontal, useMaterial3: useMaterial3, tabBarTheme: TabBarTheme(labelColor: Colors.white.withOpacity(0.8)), dialogTheme: _dialogThemeDark, diff --git a/lib/src/themes/page_transitions.dart b/lib/src/themes/page_transitions.dart new file mode 100644 index 000000000..3a77616a8 --- /dev/null +++ b/lib/src/themes/page_transitions.dart @@ -0,0 +1,151 @@ +import 'package:flutter/material.dart'; + +class YaruPageTransitionsTheme extends PageTransitionsTheme { + const YaruPageTransitionsTheme._({required super.builders}); + + /// Horizontal slide and fade page transitions. + /// + /// This page transitions theme is best suited for applications using a + /// horizontal navigation pattern, such as classic desktop wizards or master- + /// detail applications in portrait mode. + static const horizontal = YaruPageTransitionsTheme._( + builders: { + TargetPlatform.linux: _horizontalBuilder, + TargetPlatform.macOS: _horizontalBuilder, + TargetPlatform.windows: _horizontalBuilder, + }, + ); + + /// Vertical slide and fade page transitions. + /// + /// This page transitions theme is best suited for applications using a + /// vertical navigation pattern, such as master-detail applications in + /// landscape mode. + static const vertical = YaruPageTransitionsTheme._( + builders: { + TargetPlatform.linux: _verticalBuilder, + TargetPlatform.macOS: _verticalBuilder, + TargetPlatform.windows: _verticalBuilder, + }, + ); + + static const _horizontalBuilder = _YaruHorizontalPageTransitionsBuilder(); + static const _verticalBuilder = _YaruVerticalPageTransitionsBuilder(); +} + +class _YaruHorizontalPageTransitionsBuilder extends PageTransitionsBuilder { + const _YaruHorizontalPageTransitionsBuilder(); + + @override + Widget buildTransitions( + PageRoute? route, + BuildContext? context, + Animation animation, + Animation secondaryAnimation, + Widget child, + ) { + return _YaruHorizontalPageTransitions( + animation: animation, + secondaryAnimation: secondaryAnimation, + child: child, + ); + } +} + +class _YaruHorizontalPageTransitions extends StatelessWidget { + _YaruHorizontalPageTransitions({ + required Animation animation, + required Animation secondaryAnimation, + required this.child, + }) : _position = animation.drive(_tween.chain(_fastOutSlowInTween)), + _secondaryPosition = secondaryAnimation + .drive(_secondaryTween.chain(_fastOutSlowInTween)), + _opacity = animation.drive(_easeInTween), + _secondaryOpacity = secondaryAnimation.drive(_easeInTween); + + static final _tween = Tween(begin: const Offset(0.2, 0.0), end: Offset.zero); + static final _secondaryTween = + Tween(begin: Offset.zero, end: const Offset(-0.2, 0.0)); + static final _fastOutSlowInTween = CurveTween(curve: Curves.fastOutSlowIn); + static final _easeInTween = CurveTween(curve: Curves.easeIn); + + final Animation _position, _secondaryPosition; + final Animation _opacity, _secondaryOpacity; + final Widget child; + + @override + Widget build(BuildContext context) { + final textDirection = Directionality.of(context); + return SlideTransition( + position: _secondaryPosition, + textDirection: textDirection, + child: FadeTransition( + opacity: ReverseAnimation(_secondaryOpacity), + child: SlideTransition( + position: _position, + textDirection: textDirection, + child: FadeTransition(opacity: _opacity, child: child), + ), + ), + ); + } +} + +class _YaruVerticalPageTransitionsBuilder extends PageTransitionsBuilder { + const _YaruVerticalPageTransitionsBuilder(); + + @override + Widget buildTransitions( + PageRoute? route, + BuildContext? context, + Animation animation, + Animation secondaryAnimation, + Widget child, + ) { + return _YaruVerticalPageTransitions( + animation: animation, + secondaryAnimation: secondaryAnimation, + child: child, + ); + } +} + +class _YaruVerticalPageTransitions extends StatelessWidget { + _YaruVerticalPageTransitions({ + required Animation animation, + required Animation secondaryAnimation, + required this.child, + }) : _position = animation.drive(_tween.chain(_fastOutSlowInTween)), + _secondaryPosition = secondaryAnimation + .drive(_secondaryTween.chain(_fastOutSlowInTween)), + _opacity = animation.drive(_easeInTween), + _secondaryOpacity = secondaryAnimation.drive(_easeOutTween); + + static final _tween = Tween(begin: const Offset(0.0, 0.1), end: Offset.zero); + static final _secondaryTween = + Tween(begin: Offset.zero, end: const Offset(0.0, 0.0)); + static final _fastOutSlowInTween = CurveTween(curve: Curves.fastOutSlowIn); + static final _easeInTween = CurveTween(curve: Curves.easeIn); + static final _easeOutTween = CurveTween(curve: Curves.easeOutExpo); + + final Animation _position, _secondaryPosition; + final Animation _opacity, _secondaryOpacity; + final Widget child; + + @override + Widget build(BuildContext context) { + final textDirection = Directionality.of(context); + return SlideTransition( + position: _secondaryPosition, + textDirection: textDirection, + child: FadeTransition( + opacity: ReverseAnimation(_secondaryOpacity), + child: SlideTransition( + position: _position, + textDirection: textDirection, + child: FadeTransition(opacity: _opacity, child: child), + ), + ), + ); + } +} diff --git a/lib/yaru.dart b/lib/yaru.dart index 73563bbe6..224a8d773 100644 --- a/lib/yaru.dart +++ b/lib/yaru.dart @@ -5,6 +5,7 @@ export 'package:yaru/src/themes/extensions.dart'; export 'package:yaru/src/themes/high_contrast.dart'; export 'package:yaru/src/themes/kubuntu.dart'; export 'package:yaru/src/themes/lubuntu.dart'; +export 'package:yaru/src/themes/page_transitions.dart'; export 'package:yaru/src/themes/ubuntu_budgie.dart'; export 'package:yaru/src/themes/ubuntu_mate.dart'; export 'package:yaru/src/themes/ubuntu_studio.dart';