diff --git a/packages/flutter/lib/src/material/page_transitions_theme.dart b/packages/flutter/lib/src/material/page_transitions_theme.dart index 9cc555c93e8..695fed95119 100644 --- a/packages/flutter/lib/src/material/page_transitions_theme.dart +++ b/packages/flutter/lib/src/material/page_transitions_theme.dart @@ -546,8 +546,9 @@ class CupertinoPageTransitionsBuilder extends PageTransitionsBuilder { /// current [PageTransitionsTheme] with `Theme.of(context).pageTransitionsTheme` /// and delegates to [buildTransitions]. /// -/// If a builder with a matching platform is not found, then the -/// [FadeUpwardsPageTransitionsBuilder] is used. +/// If a builder for the current [ThemeData.platform] is not found, then +/// no animated transition will occur. The new page will just be displayed +/// immediately. /// /// See also: /// @@ -563,16 +564,23 @@ class PageTransitionsTheme with Diagnosticable { /// Constructs an object that selects a transition based on the platform. /// /// By default the list of builders is: [FadeUpwardsPageTransitionsBuilder] - /// for [TargetPlatform.android], and [CupertinoPageTransitionsBuilder] for - /// [TargetPlatform.iOS] and [TargetPlatform.macOS]. - const PageTransitionsTheme({ Map builders = _defaultBuilders }) : _builders = builders; + /// for [TargetPlatform.android] and [TargetPlatform.fuchsia], + /// [CupertinoPageTransitionsBuilder] for [TargetPlatform.iOS], and no + /// animated transition for other platforms or if the app is running on the + /// web. + const PageTransitionsTheme({ + Map builders = kIsWeb ? _defaultWebBuilders : _defaultBuilders, + }) : _builders = builders; static const Map _defaultBuilders = { + // Only have default transitions for mobile platforms TargetPlatform.android: FadeUpwardsPageTransitionsBuilder(), TargetPlatform.iOS: CupertinoPageTransitionsBuilder(), - TargetPlatform.linux: FadeUpwardsPageTransitionsBuilder(), - TargetPlatform.macOS: CupertinoPageTransitionsBuilder(), - TargetPlatform.windows: FadeUpwardsPageTransitionsBuilder(), + TargetPlatform.fuchsia: FadeUpwardsPageTransitionsBuilder(), + }; + + static const Map _defaultWebBuilders = { + // By default no page transitions for web apps. }; /// The [PageTransitionsBuilder]s supported by this theme. @@ -595,9 +603,8 @@ class PageTransitionsTheme with Diagnosticable { if (CupertinoRouteTransitionMixin.isPopGestureInProgress(route)) platform = TargetPlatform.iOS; - final PageTransitionsBuilder matchingBuilder = - builders[platform] ?? const FadeUpwardsPageTransitionsBuilder(); - return matchingBuilder.buildTransitions(route, context, animation, secondaryAnimation, child); + final PageTransitionsBuilder? matchingBuilder = builders[platform]; + return matchingBuilder?.buildTransitions(route, context, animation, secondaryAnimation, child) ?? child; } // Just used to the builders Map to a list with one PageTransitionsBuilder per platform diff --git a/packages/flutter/test/material/page_test.dart b/packages/flutter/test/material/page_test.dart index 2b1a77b8881..2cded91e640 100644 --- a/packages/flutter/test/material/page_test.dart +++ b/packages/flutter/test/material/page_test.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. import 'package:flutter/cupertino.dart' show CupertinoPageRoute; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -65,7 +66,7 @@ void main() { expect(find.text('Page 1'), isOnstage); expect(find.text('Page 2'), findsNothing); - }, variant: TargetPlatformVariant.only(TargetPlatform.android)); + }, variant: TargetPlatformVariant.only(TargetPlatform.android), skip: kIsWeb); testWidgets('test page transition', (WidgetTester tester) async { final Key page2Key = UniqueKey(); @@ -146,7 +147,7 @@ void main() { // Page 1 is back where it started. expect(widget1InitialTopLeft == widget1TransientTopLeft, true); - }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); + }, variant: TargetPlatformVariant.only(TargetPlatform.iOS), skip: kIsWeb); testWidgets('test fullscreen dialog transition', (WidgetTester tester) async { await tester.pumpWidget( @@ -206,7 +207,7 @@ void main() { // Page 1 is back where it started. expect(widget1InitialTopLeft == widget1TransientTopLeft, true); - }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); + }, variant: TargetPlatformVariant.only(TargetPlatform.iOS), skip: kIsWeb); testWidgets('test no back gesture on Android', (WidgetTester tester) async { await tester.pumpWidget( @@ -236,7 +237,7 @@ void main() { // Page 2 didn't move expect(tester.getTopLeft(find.text('Page 2')), Offset.zero); - }, variant: TargetPlatformVariant.only(TargetPlatform.android)); + }, variant: TargetPlatformVariant.only(TargetPlatform.android), skip: kIsWeb); testWidgets('test back gesture', (WidgetTester tester) async { await tester.pumpWidget( @@ -277,7 +278,7 @@ void main() { await tester.pump(); expect(tester.getTopLeft(find.text('Page 2')), const Offset(100.0, 0.0)); - }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); + }, variant: TargetPlatformVariant.only(TargetPlatform.iOS), skip: kIsWeb); testWidgets('back gesture while OS changes', (WidgetTester tester) async { final Map routes = { @@ -362,13 +363,13 @@ void main() { expect(find.text('PUSH'), findsNothing); expect(find.text('HELLO'), findsOneWidget); await tester.pump(const Duration(milliseconds: 20)); - expect(find.text('PUSH'), findsOneWidget); + // As no transitions are specified for macOS the drag should do nothing + expect(find.text('PUSH'), findsNothing); expect(find.text('HELLO'), findsOneWidget); final Offset helloPosition6 = tester.getCenter(find.text('HELLO')); - expect(helloPosition5.dx, lessThan(helloPosition6.dx)); - expect(helloPosition5.dy, helloPosition6.dy); + expect(helloPosition5, helloPosition6); expect(Theme.of(tester.element(find.text('HELLO'))).platform, TargetPlatform.macOS); - }); + }, skip: kIsWeb); testWidgets('test no back gesture on fullscreen dialogs', (WidgetTester tester) async { await tester.pumpWidget( @@ -479,7 +480,7 @@ void main() { // Page 1 is back where it started. expect(widget1InitialTopLeft == widget1TransientTopLeft, true); - }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); + }, variant: TargetPlatformVariant.only(TargetPlatform.iOS), skip: kIsWeb); testWidgets('test edge swipe then drop back at starting point works', (WidgetTester tester) async { await tester.pumpWidget( @@ -547,7 +548,7 @@ void main() { expect(find.text('Page 1'), isOnstage); expect(find.text('Page 2'), findsNothing); - }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); + }, variant: TargetPlatformVariant.only(TargetPlatform.iOS), skip: kIsWeb); testWidgets('Back swipe dismiss interrupted by route push', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/28728 @@ -642,7 +643,7 @@ void main() { await tester.pumpAndSettle(); expect(find.text('route'), findsOneWidget); expect(find.text('push'), findsNothing); - }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); + }, variant: TargetPlatformVariant.only(TargetPlatform.iOS), skip: kIsWeb); testWidgets('During back swipe the route ignores input', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/39989 @@ -712,7 +713,7 @@ void main() { await tester.pumpAndSettle(); expect(tester.getTopLeft(find.byKey(pageScaffoldKey)), const Offset(400, 0)); expect(tester.getTopLeft(find.byKey(homeScaffoldKey)).dx, lessThan(0)); - }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); + }, variant: TargetPlatformVariant.only(TargetPlatform.iOS), skip: kIsWeb); testWidgets('After a pop caused by a back-swipe, input reaches the exposed route', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/41024 @@ -783,7 +784,7 @@ void main() { await tester.tap(find.byKey(homeScaffoldKey)); expect(homeTapCount, 2); expect(pageTapCount, 1); - }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); + }, variant: TargetPlatformVariant.only(TargetPlatform.iOS), skip: kIsWeb); testWidgets('A MaterialPageRoute should slide out with CupertinoPageTransition when a compatible PageRoute is pushed on top of it', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/44864. @@ -811,7 +812,7 @@ void main() { // Title of the first route slides to the left. expect(titleInitialTopLeft.dy, equals(titleTransientTopLeft.dy)); expect(titleInitialTopLeft.dx, greaterThan(titleTransientTopLeft.dx)); - }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); + }, variant: TargetPlatformVariant.only(TargetPlatform.iOS), skip: kIsWeb); testWidgets('MaterialPage works', (WidgetTester tester) async { final LocalKey pageKey = UniqueKey(); diff --git a/packages/flutter/test/material/page_transitions_theme_test.dart b/packages/flutter/test/material/page_transitions_theme_test.dart index 2db3f43e7c3..6856194f120 100644 --- a/packages/flutter/test/material/page_transitions_theme_test.dart +++ b/packages/flutter/test/material/page_transitions_theme_test.dart @@ -11,17 +11,33 @@ void main() { testWidgets('Default PageTransitionsTheme platform', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp(home: Text('home'))); final PageTransitionsTheme theme = Theme.of(tester.element(find.text('home'))).pageTransitionsTheme; + expect(theme.builders, isNotNull); - for (final TargetPlatform platform in TargetPlatform.values) { - if (platform == TargetPlatform.fuchsia) { - // No builder on Fuchsia. - continue; + if (kIsWeb) { + // There aren't any default transitions defined for web + expect(theme.builders, isEmpty); + } else { + // There should only be builders for the mobile platforms. + for (final TargetPlatform platform in TargetPlatform.values) { + switch (platform) { + case TargetPlatform.android: + case TargetPlatform.iOS: + case TargetPlatform.fuchsia: + expect(theme.builders[platform], isNotNull, + reason: 'theme builder for $platform is null'); + break; + case TargetPlatform.linux: + case TargetPlatform.macOS: + case TargetPlatform.windows: + expect(theme.builders[platform], isNull, + reason: 'theme builder for $platform is not null'); + break; + } } - expect(theme.builders[platform], isNotNull, reason: 'theme builder for $platform is null'); } }); - testWidgets('Default PageTransitionsTheme builds a CupertionPageTransition', (WidgetTester tester) async { + testWidgets('Default PageTransitionsTheme builds a CupertinoPageTransition', (WidgetTester tester) async { final Map routes = { '/': (BuildContext context) => Material( child: TextButton( @@ -45,7 +61,7 @@ void main() { await tester.pumpAndSettle(); expect(find.text('page b'), findsOneWidget); expect(find.byType(CupertinoPageTransition), findsOneWidget); - }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); + }, variant: TargetPlatformVariant.only(TargetPlatform.iOS), skip: kIsWeb); testWidgets('Default PageTransitionsTheme builds a _FadeUpwardsPageTransition for android', (WidgetTester tester) async { final Map routes = { @@ -78,7 +94,7 @@ void main() { await tester.pumpAndSettle(); expect(find.text('page b'), findsOneWidget); expect(findFadeUpwardsPageTransition(), findsOneWidget); - }, variant: TargetPlatformVariant.only(TargetPlatform.android)); + }, variant: TargetPlatformVariant.only(TargetPlatform.android), skip: kIsWeb); testWidgets('PageTransitionsTheme override builds a _OpenUpwardsPageTransition', (WidgetTester tester) async { final Map routes = { @@ -118,7 +134,7 @@ void main() { await tester.pumpAndSettle(); expect(find.text('page b'), findsOneWidget); expect(findOpenUpwardsPageTransition(), findsOneWidget); - }, variant: TargetPlatformVariant.only(TargetPlatform.android)); + }, variant: TargetPlatformVariant.only(TargetPlatform.android), skip: kIsWeb); testWidgets('PageTransitionsTheme override builds a _ZoomPageTransition', (WidgetTester tester) async { final Map routes = { @@ -158,7 +174,7 @@ void main() { await tester.pumpAndSettle(); expect(find.text('page b'), findsOneWidget); expect(findZoomPageTransition(), findsOneWidget); - }, variant: TargetPlatformVariant.only(TargetPlatform.android)); + }, variant: TargetPlatformVariant.only(TargetPlatform.android), skip: kIsWeb); testWidgets('_ZoomPageTransition only cause child widget built once', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/58345 @@ -204,5 +220,5 @@ void main() { await tester.tap(find.text('pop')); await tester.pumpAndSettle(); expect(builtCount, 1); - }, variant: TargetPlatformVariant.only(TargetPlatform.android)); + }, variant: TargetPlatformVariant.only(TargetPlatform.android), skip: kIsWeb); } diff --git a/packages/flutter/test/material/text_field_test.dart b/packages/flutter/test/material/text_field_test.dart index c7834e24997..34001707795 100644 --- a/packages/flutter/test/material/text_field_test.dart +++ b/packages/flutter/test/material/text_field_test.dart @@ -1448,13 +1448,13 @@ void main() { // Wait for context menu to be built. await tester.pumpAndSettle(); final RenderBox container = tester.renderObject(find.descendant( - of: find.byType(FadeTransition), + of: find.byType(Overlay), matching: find.byType(SizedBox), ).first); expect(container.size, Size.zero); }, variant: const TargetPlatformVariant({ TargetPlatform.android, TargetPlatform.fuchsia, TargetPlatform.linux, TargetPlatform.windows })); - testWidgets('Sawping controllers should update selection', (WidgetTester tester) async { + testWidgets('Swapping controllers should update selection', (WidgetTester tester) async { TextEditingController controller = TextEditingController(text: 'readonly'); final OverlayEntry entry = OverlayEntry( builder: (BuildContext context) { diff --git a/packages/flutter/test/widgets/heroes_test.dart b/packages/flutter/test/widgets/heroes_test.dart index c7a6638b4cf..00142a331be 100644 --- a/packages/flutter/test/widgets/heroes_test.dart +++ b/packages/flutter/test/widgets/heroes_test.dart @@ -1836,7 +1836,7 @@ Future main() async { expect(find.byKey(firstKey), isInCard); expect(find.byKey(secondKey), isOnstage); expect(find.byKey(secondKey), isInCard); - }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); + }, variant: TargetPlatformVariant.only(TargetPlatform.iOS), skip: kIsWeb); testWidgets('Heroes can transition on gesture in one frame', (WidgetTester tester) async { transitionFromUserGestures = true; @@ -1879,7 +1879,7 @@ Future main() async { expect(find.byKey(firstKey), isOnstage); expect(find.byKey(firstKey), isInCard); expect(find.byKey(secondKey), findsNothing); - }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); + }, variant: TargetPlatformVariant.only(TargetPlatform.iOS), skip: kIsWeb); testWidgets('Heroes animate should hide destination hero and display original hero in case of dismissed', (WidgetTester tester) async { transitionFromUserGestures = true; @@ -1915,7 +1915,7 @@ Future main() async { expect(find.byKey(firstKey), findsNothing); expect(find.byKey(secondKey), isOnstage); expect(find.byKey(secondKey), isInCard); - }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); + }, variant: TargetPlatformVariant.only(TargetPlatform.iOS), skip: kIsWeb); testWidgets('Handles transitions when a non-default initial route is set', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( diff --git a/packages/flutter/test/widgets/page_transitions_test.dart b/packages/flutter/test/widgets/page_transitions_test.dart index 5c777bcea3d..9a939a51bca 100644 --- a/packages/flutter/test/widgets/page_transitions_test.dart +++ b/packages/flutter/test/widgets/page_transitions_test.dart @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -196,7 +197,7 @@ void main() { settingsOffset = tester.getTopLeft(find.text('Settings')); expect(settingsOffset.dx, greaterThan(100.0)); expect(settingsOffset.dy, 100.0); - }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); + }, variant: TargetPlatformVariant.only(TargetPlatform.iOS), skip: kIsWeb); testWidgets("Check back gesture doesn't start during transitions", (WidgetTester tester) async { final GlobalKey containerKey1 = GlobalKey(); @@ -239,7 +240,7 @@ void main() { expect(find.text('Home'), isOnstage); expect(find.text('Settings'), findsNothing); - }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); + }, variant: TargetPlatformVariant.only(TargetPlatform.iOS), skip: kIsWeb); // Tests bug https://github.com/flutter/flutter/issues/6451 testWidgets('Check back gesture with a persistent bottom sheet showing', (WidgetTester tester) async { @@ -293,7 +294,7 @@ void main() { // Sheet did not call setState (since the gesture did nothing). expect(sheet.setStateCalled, isFalse); - }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); + }, variant: TargetPlatformVariant.only(TargetPlatform.iOS), skip: kIsWeb); testWidgets('Test completed future', (WidgetTester tester) async { final Map routes = {