-
Notifications
You must be signed in to change notification settings - Fork 29.7k
Allow mixing route transitions in one app. #150031
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow mixing route transitions in one app. #150031
Conversation
157ee4d to
7818f6e
Compare
|
@justinmc this one has the refactor of route animation logic so that the prior route does not need to opt in to get it's transition overwritten, it will always happen. So |
justinmc
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's the review put together while @MitchellGoodwin walked me through this PR over GVC.
| Widget buildTransitions(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) { | ||
| final PageTransitionsTheme theme = Theme.of(context).pageTransitionsTheme; | ||
| return theme.buildTransitions<T>(this, context, animation, secondaryAnimation, child); | ||
| delegatedTransition = theme.delegatedTransition(context); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm curious how it works that delegatedTransition is on the PageTransitionsTheme.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I commented on this above in the example after discussing in person. The format of how the delegatedTransition will have to change. Ideally it will be provided alongside the transition itself, maybe part of the PageTransitionsBuilder.
| static const bool _kProfileForceDisableSnapshotting = bool.fromEnvironment('flutter.benchmarks.force_disable_snapshot'); | ||
|
|
||
| /// The delegated transition. | ||
| static Widget delegateTransition(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget? child) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm also confused why ZoomPageTransitionsBuilder needs to define a delegateTransition. Discussed in person, this is part of the new feature that ZoomPageTransitionBuilder also makes outgoing routes perform a zoom.
We also discussed that maybe some of this code could be deduplicated with _ZoomPageTransition if it makes sense.
| if (matchingBuilder == const ZoomPageTransitionsBuilder()) { | ||
| return ZoomPageTransitionsBuilder.delegateTransition; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Users would have to override this if they have their own PageTransitionBuilder with a delegateTransition? Discussed in another comment, the format of where the delegatedTransition is defined for a PageTransitionBuilder will probably change.
| final DelegatedTransitionBuilder? receivedTransitionBuilder; | ||
|
|
||
| /// The delegated transition. | ||
| static Widget delegateTransition(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget? child) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does CupertinoPageTransition now have a delegateTransition? It is making the outgoing route use this as its secondaryTransition? (If they are FlexibleTransitionRouteMixins?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Discussed in person: This means that now, CupertinoPageRoute will cause other routes to use this transition when outgoing. Previously the outgoing route would do nothing, so this is a good change, but we should watch out for it being breaking, by running the Google tests. If they fail, maybe this change should be its own separate PR first.
|
|
||
| @override | ||
| void didChangeNext(Route<dynamic>? nextRoute) { | ||
| if (nextRoute is FlexibleTransitionRouteMixin<T> && canTransitionTo(nextRoute)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Discussed in person: Talking about opt-out by default. The default implementations of TransitionRoute.canTransitionTo/From are both => true. This is good, because when they are true, we will use the delegatedTransition. If a user has previously set one/both of them to false, then they are saying that they don't want a transition to happen at all, and that's still the behavior they will get after this PR.
We should make sure we have a test(s) for these scenarios.
@MitchellGoodwin to check what happens when canTransitionTo and canTransitionFalse do not agree.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now talking about opt-out not as in do nothing, but as in do your existing custom transition and NOT the delegatedTransition. I'm guessing most users that want to opt out will want to do that.
With the current state of this PR it's not possible. We'll have to add a way for these users to make some code change to explicitly opt out. We were thinking something like a boolean flag on ModalRoute?
We think that users that are currently doing this setup (they have a custom transition and they want it to always do its secondaryTransition on the way out regardless of what the next route is) must have implemented a custom ModalRoute. It wouldn't be possible to do this if you only wrote a PageTransitionsBuilder. Therefore it's OK to do this as a flag on ModalRoute.
Probably another thing to test.
| } | ||
|
|
||
| @override | ||
| bool didPop(T? result) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Discussed in person: We have concerns about jumping from a delegatedTransition back to the original non-delegated transition while outgoing. So this is the case we should test:
- Push a non-MBS route and then an MBS route.
- Pop both of them quickly.
The non-MBS route will have its receivedTransition cleared (line 2534 here) in the middle of performing it, and will switch back to its normal non-delegated transition. It will probably look jumpy.
What can we do to avoid that and make it look smooth like the existing train hopping?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well removing the didPopNext method below seems like it would do it... But is that breaking anything else? @MitchellGoodwin said that it's done that way in the existing train hopping logic as well, so maybe it's necessary for something related to train hopping.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Screen.Recording.2024-07-16.at.2.15.10.PM.mov
What it currently looks like. It is pretty jumpy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Making a note that we were talking offline about solving this jumpiness by:
- Always keep all 3 transitions in the widget tree. Don't swap in/out the delegated/received transition tree.
- Create a new Animation that only drives the delegated transition. Or make a copy of secondaryAnimation somehow?
Not sure how feasible that is at this point though...
| bool didPop(T? result) { | ||
| final bool popResult = super.didPop(result); | ||
| if (popResult && receivedTransition != null) { | ||
| receivedTransition = null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Discussed in person why this was needed: The case is when pushing two routes and then popping them in succession. Call them Route1, 2 and 3.
When Route3 is popped, Route2 is using its delegatedTransition. When that transition finishes and Route3 is long gone, Route2 still has Route3's delegatedTransition in its widget tree! And not its own usual transitions provided by something like PageTransitionsBuilder.buildTransitions. When Route2 is then popped, this didPop method is called and its receivedTransition is set to null so that it can go back to using its own original transition. But, that also causes the problem given in my comment a few lines above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@MitchellGoodwin That makes me think of another possible bug here. Same setup as before: push Route2 and Route3, then pop Route3. Now instead of popping Route2, push a new Route4, which does not have a delegatedTransition. If I'm understanding correctly, Route2 will not animate out correctly.
We should add a test for that too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for the late response. That last scenario will actually currently work. If Route4 does not have a delegate transition, then Route2 will set its reveivedTransition to null, so it will have it's original transitions. Whether it plays that transition or not when Route4 is pushed on top is up to canTransitionTo and canTransitionFrom, which is current behavior before this PR.
| /// for this route. | ||
| /// * [MaterialPage], which is a [Page] of this class. | ||
| class MaterialPageRoute<T> extends PageRoute<T> with MaterialRouteTransitionMixin<T> { | ||
| class MaterialPageRoute<T> extends PageRoute<T> with MaterialRouteTransitionMixin<T>, FlexibleTransitionRouteMixin<T> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The use of FlexibleTransitionRouteMixin won't be necessary when that code is moved into ModalRoute, and any other people that extended ModalRoute will get the new functionality automatically 👍 .
7818f6e to
15a3570
Compare
|
Here's my example of a custom non-MBS delegated transition: Screen.Recording.2024-07-30.at.4.32.54.PM.movCodeimport 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Mixing Routes',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
pageTransitionsTheme: const PageTransitionsTheme(
builders: <TargetPlatform, PageTransitionsBuilder>{
TargetPlatform.iOS: ZoomPageTransitionsBuilder(),
},
),
useMaterial3: true,
),
home: const MyHomePage(title: 'Zoom Transition'),
);
}
}
class MyHomePage extends StatelessWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextButton(
onPressed: () {
Navigator.of(context).push(
VerticalTransitionPageRoute(
context: context,
builder: (BuildContext context) {
return const MyHomePage(title: 'Crazy Vertical Transition');
},
),
);
},
child: const Text('Crazy Vertical Transition'),
),
TextButton(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
return const MyHomePage(title: 'Zoom Transition');
},
),
);
},
child: const Text('Zoom Transition'),
),
TextButton(
onPressed: () {
CupertinoPageRoute route = CupertinoPageRoute(
builder: (BuildContext context) {
return const MyHomePage(title: 'Cupertino Transition');
}
);
Navigator.of(context).push(route);
},
child: const Text('Cupertino Transition'),
),
],
),
),
);
}
}
class VerticalTransitionPageRoute<T> extends PageRoute<T> with FlexibleTransitionRouteMixin<T> {
/// Creates a page route for use in an iOS designed app.
VerticalTransitionPageRoute({
required this.builder,
required BuildContext context,
});
final WidgetBuilder builder;
@override
DelegatedTransitionBuilder? get delegatedTransition => VerticalPageTransition._delegatedTransition;
@override
Color? get barrierColor => const Color(0x00000000);
@override
bool get barrierDismissible => false;
@override
String? get barrierLabel => 'Should be no visible barrier...';
@override
bool get maintainState => true;
@override
bool get opaque => false;
// Begin PageRoute.
@override
Duration get transitionDuration => const Duration(milliseconds: 2000);
@override
Widget buildPage(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
return builder(context);
}
static Widget buildPageTransitions<T>(
ModalRoute<T> route,
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child,
) {
return VerticalPageTransition(
primaryRouteAnimation: animation,
secondaryRouteAnimation: secondaryAnimation,
child: child,
);
}
// TODO(justinmc): No canTransitionTo needed? I want to be able to have
// back-to-back VerticalPageTransitions.
@override
Widget buildTransitions(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) {
return buildPageTransitions<T>(this, context, animation, secondaryAnimation, child);
}
// End PageRoute.
}
class VerticalPageTransition extends StatelessWidget {
VerticalPageTransition({
super.key,
required Animation<double> primaryRouteAnimation,
required this.secondaryRouteAnimation,
required this.child,
}) : _primaryPositionAnimation =
CurvedAnimation(
parent: primaryRouteAnimation,
curve: curve,
reverseCurve: curve,
).drive(_kBottomUpTween),
_secondaryPositionAnimation =
CurvedAnimation(
parent: secondaryRouteAnimation,
curve: curve,
reverseCurve: curve,
)
.drive(_kTopDownTween);
// When this page is coming in to cover another page.
final Animation<Offset> _primaryPositionAnimation;
// When this page is being coverd by another page.
final Animation<Offset> _secondaryPositionAnimation;
/// Animation
final Animation<double> secondaryRouteAnimation;
/// The widget below this widget in the tree.
final Widget child;
static const Curve curve = Curves.decelerate;
static final Animatable<Offset> _kBottomUpTween = Tween<Offset>(
begin: const Offset(0.0, 1.0),
end: Offset.zero,
);
static final Animatable<Offset> _kTopDownTween = Tween<Offset>(
begin: Offset.zero,
end: const Offset(0.0, -1.0),
);
static Widget _delegatedTransition(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget? child) {
final Animatable<Offset> tween = Tween<Offset>(
begin: Offset.zero,
end: const Offset(0.0, -1.0),
).chain(CurveTween(curve: curve));
return SlideTransition(
position: secondaryAnimation.drive(tween),
child: child,
);
}
@override
Widget build(BuildContext context) {
assert(debugCheckHasDirectionality(context));
final TextDirection textDirection = Directionality.of(context);
return SlideTransition(
position: _secondaryPositionAnimation,
textDirection: textDirection,
transformHitTests: false,
child: SlideTransition(
position: _primaryPositionAnimation,
textDirection: textDirection,
child: ClipRRect(
borderRadius: const BorderRadius.vertical(top: Radius.circular(12)),
child: child,
)
),
);
}
}
|
|
Also random thought: Any concerns about how the drag-to-close interaction will work with MBS? Seems like it should be fine with this API but I wanted to bring it up. |
As in dragging it to partially close the animation, like the Cupertino transition does? It should work fine. The Cupertino transition works correctly when dragging back to a non-Cupertino page with this PR. |
|
I mean when the MBS is open, dragging it down to close it and dismiss all of its routes. |
|
Yes, I believe that shouldn't be affected. |
5ee88b2 to
7a5974e
Compare
justinmc
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've been ignoring small things like incomplete docs in other reviews, but I decided to go all out on that nitpicky stuff in this one haha. Feel free to ignore if there's still anything major that might change.
Overall the architecture looks good as long as everything is working. The biggest API related question I had was just about buildFlexTransitions and nextRouteTransition, and needing help understanding them. I had an idea (below) about possibly simplifying them.
Otherwise just small stuff.
| ), | ||
| useMaterial3: true, | ||
| ), | ||
| home: const MyHomePage(title: 'Zoom Transition'), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: I would make it private: _MyHomePage.
| @override | ||
| Widget build(BuildContext context) { | ||
| return Scaffold( | ||
| appBar: AppBar( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indentation is wrong here.
| class VerticalTransitionPageRoute<T> extends PageRoute<T> { | ||
| /// Creates a page route for use in an iOS designed app. | ||
| VerticalTransitionPageRoute({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would make this private as well and then put the comment on the class:
// A PageRoute that applies VerticalPageTransition.
| // TODO(justinmc): No canTransitionTo needed? I want to be able to have | ||
| // back-to-back VerticalPageTransitions. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't forget to remove this. The question stands though. I guess it doesn't need canTransitionTo unless we want to demonstrate that somehow?
| // End PageRoute. | ||
| } | ||
|
|
||
| class VerticalPageTransition extends StatelessWidget { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd make it private and comment:
// A page transition that slides off the screen vertically, and uses
// delegatedTransition to ensure that the outgoing route slides with it.
| if (nextRouteTransition != null) { | ||
| return nextRouteTransition!(context, animation, secondaryAnimation, originalTransitions); | ||
| } else { | ||
| return originalTransitions; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If receivedTransition was an empty builder instead of null, could we get rid of all of this mechanism around including it or not including it? Just throwing that out there, not sure if it's a good idea or not yet...
| /// Convenience function for passing around a builder for a transiton's secondary animation. | ||
| typedef DelegatedTransitionBuilder = Widget Function(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget? child); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typedefs should mention at least one place where it is used: https://github.com/flutter/flutter/blob/master/docs/contributing/Style-guide-for-Flutter-repo.md#leave-breadcrumbs-in-the-comments
Typedef docs should usually start with "Signature for": https://github.com/flutter/flutter/blob/master/docs/contributing/Style-guide-for-Flutter-repo.md#canonical-terminology
"transiton" => "transition"
|
|
||
| await tester.pump(const Duration(milliseconds: 50)); | ||
| expect(tester.getTopLeft(find.byKey(secondPlaceholderKey)).dx, moreOrLessEquals(xLocationIntervalTwelve, epsilon: 0.1)); | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be possible to include a test that uses WidgetsApp.router too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Trying to think of other stuff to test... Maybe that all 3 transitions are in the widget tree at the same time?
Maybe a train hopping situation? Or at least a situation where a transition is interrupted while running.
Anything else from the edge cases we have talked about?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My first comment WidgetsApp.router is now covered by the second example 👍
The other ones are up to you. Maybe we should test the "interrupted" case, where a pop happens while a transition is still running?
| expect(materialPageRoute.receivedTransition, CupertinoPageTransition.delegateTransition); | ||
| }); | ||
|
|
||
| testWidgets('outgoing route does not receive a delegated transition from a route with the same transition', (WidgetTester tester) async { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This just makes me wonder: it's not that the routes are the same type, it's that the routes' delegatedTransition is the same as its usual outgoing transition? Or how does that work?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This makes sense now with the DelegatedTransition subclassing.
7a5974e to
bfd91ef
Compare
84ecf2e to
8e25d51
Compare
packages/flutter/test/material/page_transitions_theme_test.dart
Outdated
Show resolved
Hide resolved
justinmc
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the name string comparison is not doable because of the risk of collision. How about instead, for each of the places where you currently instantiate DelegatedTransition with a unique name string, create a subclass of DelegatedTransition with a hardcoded builder. E.g. ZoomPageDelegatedTransition or something like that. Ideally these subclasses would be const so you can just do a normal equality check, but if not you could do a type check.
| final bool linearTransition; | ||
|
|
||
| /// The delegated transition. | ||
| static Widget delegatedTransitionBuilder(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget? child) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it weird that now DelegatedTransition is a type, but delegatedTransitionBuilder returns a Widget?
| DelegatedTransition? _delegatedTransition; | ||
|
|
||
| @override | ||
| DelegatedTransition? get delegatedTransition => _delegatedTransition; | ||
|
|
||
| set delegatedTransition(DelegatedTransition? newTransition) { | ||
| _delegatedTransition = newTransition; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could this just be a plain variable instead of a getter and setter?
| final DelegatedTransitionBuilder builder; | ||
|
|
||
| /// Placeholder | ||
| final String? name; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I worry about the possibility for collisions due to this being just a plain string.
| } | ||
|
|
||
| /// Provide delegate transition for platform. | ||
| DelegatedTransition? delegatedTransition(TargetPlatform platform, bool allowSnapshotting) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Maybe rename to getDelegatedTransition to distinguish a getter from a value.
|
|
||
| /// Placeholder | ||
| @immutable | ||
| class DelegatedTransition { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This reminds me of PageTransitionsBuilder. I wonder if that class was created for a similar reason?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems like it. It looks like it was used for comparing equality of PageTransitionsTheme.
8d8e14c to
b63afc8
Compare
@justinmc I went with a type check, because with the Zoom transition snapshotting behavior we talked about offline, there are cases were the builder may be different, but you would want to not overwrite the previous pages transition. If you do want to make two or more delegates that do override the previous one, you would make a class type for each variation. |
Manual roll Flutter from 0975e61 to ec2e12b (54 revisions) Manual roll requested by [email protected] flutter/flutter@0975e61...ec2e12b 2024-10-03 [email protected] Roll Flutter Engine from bd44b58e3204 to 247bc68c578e (7 revisions) (flutter/flutter#156144) 2024-10-03 [email protected] Roll Flutter Engine from 70232fa124d0 to bd44b58e3204 (1 revision) (flutter/flutter#156124) 2024-10-03 [email protected] Roll Flutter Engine from 33ac1b30ab0a to 70232fa124d0 (2 revisions) (flutter/flutter#156122) 2024-10-02 [email protected] Update `ThemeData.dialogTheme` type to accept `DialogThemeData` (flutter/flutter#155129) 2024-10-02 [email protected] Roll Flutter Engine from 751ab9b3c5eb to 33ac1b30ab0a (4 revisions) (flutter/flutter#156118) 2024-10-02 [email protected] Add back main() methods to benchmark benches. (flutter/flutter#156083) 2024-10-02 [email protected] Roll pub packages (flutter/flutter#156117) 2024-10-02 [email protected] Add `mouseCursor` property to `CupertinoCheckbox` (flutter/flutter#151788) 2024-10-02 [email protected] Roll Flutter Engine from 3bdc1c0a30b6 to 751ab9b3c5eb (3 revisions) (flutter/flutter#156115) 2024-10-02 [email protected] Roll pub packages (flutter/flutter#156114) 2024-10-02 [email protected] [ Cocoon ] Wait for task results to be received by the task runner before shutting down the task process (flutter/flutter#156002) 2024-10-02 [email protected] Allow mixing route transitions in one app. (flutter/flutter#150031) 2024-10-02 [email protected] Roll Flutter Engine from f20681241753 to 3bdc1c0a30b6 (5 revisions) (flutter/flutter#156107) 2024-10-02 [email protected] Update Upgrading-Engine's-Android-API-version.md to reflect code move (flutter/flutter#156108) 2024-10-02 [email protected] Roll Packages from ebcc4f0 to 7c97c88 (5 revisions) (flutter/flutter#156106) 2024-10-02 [email protected] Roll pub packages (flutter/flutter#156105) 2024-10-02 [email protected] fix wrong test in "fixing `DropdownMenu` keyboard navigation" (flutter/flutter#156084) 2024-10-02 [email protected] fix ReorderableList not passing in item extent builder (flutter/flutter#155994) 2024-10-02 98614782+auto-submit[bot]@users.noreply.github.com Reverts "integration_test: migrate to build.gradle.kts (#154125)" (flutter/flutter#156087) 2024-10-02 [email protected] Add deprecation warning for "flutter create --ios-language" (flutter/flutter#155867) 2024-10-02 [email protected] update flutter create generated projects to use package:flutter_lints 5.0.0 (flutter/flutter#156011) 2024-10-02 [email protected] Roll Flutter Engine from d48c35d16814 to f20681241753 (1 revision) (flutter/flutter#156080) 2024-10-02 [email protected] [Docs] `CupertinoListTile` API Example (flutter/flutter#154548) 2024-10-02 [email protected] integration_test: migrate to build.gradle.kts (flutter/flutter#154125) 2024-10-02 [email protected] Marks Windows_mokey native_assets_android to be flaky (flutter/flutter#156064) 2024-10-02 [email protected] Fix DropdownMenu does not rematch initialSelection when entries have changed (flutter/flutter#155757) 2024-10-02 [email protected] Roll Flutter Engine from 9b224bd2f895 to d48c35d16814 (1 revision) (flutter/flutter#156074) 2024-10-02 [email protected] Roll Flutter Engine from 8774940b9ddc to 9b224bd2f895 (1 revision) (flutter/flutter#156065) 2024-10-02 [email protected] Roll Flutter Engine from 21ad04948457 to 8774940b9ddc (1 revision) (flutter/flutter#156055) 2024-10-02 [email protected] Roll Flutter Engine from 767bdc38cf51 to 21ad04948457 (1 revision) (flutter/flutter#156049) 2024-10-02 [email protected] Roll Flutter Engine from 055969512dc5 to 767bdc38cf51 (1 revision) (flutter/flutter#156043) 2024-10-02 [email protected] Roll Flutter Engine from e0f049d69240 to 055969512dc5 (2 revisions) (flutter/flutter#156042) 2024-10-02 [email protected] fix `DropdownMenu` keyboard navigation when entries are filtered empty (flutter/flutter#155252) 2024-10-02 [email protected] Roll Flutter Engine from a5bc2e2708c7 to e0f049d69240 (1 revision) (flutter/flutter#156039) 2024-10-02 [email protected] mark {Linux,Windows} tool_integration_tests_* non-bringup (flutter/flutter#155773) 2024-10-02 [email protected] Roll Flutter Engine from a7abf7a8163e to a5bc2e2708c7 (2 revisions) (flutter/flutter#156038) 2024-10-02 [email protected] Roll Flutter Engine from df1982dd4482 to a7abf7a8163e (1 revision) (flutter/flutter#156032) 2024-10-02 [email protected] Add `enableSplash` parameter to `CarouselView` (flutter/flutter#155214) 2024-10-02 [email protected] Roll pub packages (flutter/flutter#156030) 2024-10-01 [email protected] Roll Flutter Engine from ab48d6d8c167 to df1982dd4482 (1 revision) (flutter/flutter#156029) 2024-10-01 [email protected] Marks Mac_arm64_ios hot_mode_dev_cycle_ios__benchmark to be unflaky (flutter/flutter#147289) 2024-10-01 [email protected] Add WidgetStateMouseCursor example and tests for it. (flutter/flutter#155552) 2024-10-01 49699333+dependabot[bot]@users.noreply.github.com Bump codecov/codecov-action from 4.5.0 to 4.6.0 (flutter/flutter#156024) 2024-10-01 [email protected] Roll Flutter Engine from e7b3ce717006 to ab48d6d8c167 (1 revision) (flutter/flutter#156023) ...
|
Is there a quick and easy way to opt out of this change? It's breaking tests in our app where I'm trying to upgrade to the master branch to add WASM Support (I need master branch as it has a few important fixes for WASM). I'm already introducing so many changes to support the new js_interop/html and upgrading a bunch of our packages to support web 1.0, I'd really rather not refactor our routing stack to support this one change as well. I've pinpointed this commit as the failure point. |
|
For those who hit this same issue, I found overriding the |
|
@brian-superlist could you file an issue with more info on what got broken? This was intended to not be a breaking change. |
|
@MitchellGoodwin I'll try to boil it down -- our tests that failed are broad integration tests that cover many widgets together and I'm unsure how long it will take to create a minimal repro. I'll see if I can do so in a reasonable timeframe. |
|
@brian-superlist are these tests registered in flutter/tests? We run all of the tests registered there on every pull request before landing a change in flutter/flutter. |
|
@Piinks Nope, we have many of our open source projects on there, but this particular failure was against our closed source app. As far as I understand, that violates the first criterion:
|
|
I have an app where the transition is broken after this change. |
|
Please file an issue with a code sample that reproduces the problem. We cannot triage and address issues in closed PRs. Thanks! |
|
Done! |
…og (#159312) Fixes #159289 Cupertino and Material routes were looking to see if the next route was a full screen dialog route, and not transitioning accordingly. However with the updates to allow [mixed transitions in an app](#150031), any route will try and transition if a delegatedTransition is available. This PR makes it so that Cupertino and Material routes that are fullscreen dialogs will use `canTransitionFrom` to tell the previous route not to transition. Before: [388677067-d301238d-6615-42a7-b60a-611c61136d88.webm](https://github.com/user-attachments/assets/eea99ee9-0bc8-4981-a950-08f99a7fdb3e) After: https://github.com/user-attachments/assets/7deb5143-cd67-4696-95ec-9d7df329dfa4 ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [ ] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
…llscreenDialog CP issue: flutter#160420 Original PR: flutter#159312 Original description below: Fixes flutter#159289 Cupertino and Material routes were looking to see if the next route was a full screen dialog route, and not transitioning accordingly. However with the updates to allow [mixed transitions in an app](flutter#150031), any route will try and transition if a delegatedTransition is available. This PR makes it so that Cupertino and Material routes that are fullscreen dialogs will use `canTransitionFrom` to tell the previous route not to transition. Before: [388677067-d301238d-6615-42a7-b60a-611c61136d88.webm](https://github.com/user-attachments/assets/eea99ee9-0bc8-4981-a950-08f99a7fdb3e) After: https://github.com/user-attachments/assets/7deb5143-cd67-4696-95ec-9d7df329dfa4 - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [ ] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
…llscreenDialog (#161784) CP issue: #160420 Original PR: #159312 Original description below: Fixes #159289 Cupertino and Material routes were looking to see if the next route was a full screen dialog route, and not transitioning accordingly. However with the updates to allow [mixed transitions in an app](#150031), any route will try and transition if a delegatedTransition is available. This PR makes it so that Cupertino and Material routes that are fullscreen dialogs will use `canTransitionFrom` to tell the previous route not to transition. Before: [388677067-d301238d-6615-42a7-b60a-611c61136d88.webm](https://github.com/user-attachments/assets/eea99ee9-0bc8-4981-a950-08f99a7fdb3e) After: https://github.com/user-attachments/assets/7deb5143-cd67-4696-95ec-9d7df329dfa4 https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
Fixes #33799
Allows for a route to inform the route below it in the navigation stack how to animate when the topmost route enters are leaves the stack.
It does this by making a
DelegatedTransitionavailable for the previous route to look up and use. If available, the route lower in the stack will wrap it's transition builders with that delegated transition and use it instead of it's default secondary transition.This is what the sample code in this PR shows an app that is able to use both a Material zoom transition and a Cupertino slide transition in one app. It also includes a custom vertical transition. Every page animates off the screen in a way to match up with the incoming page's transition. When popped, the correct transitions play in reverse.
Screen.Recording.2024-09-04.at.10.18.45.AM.mov
The below video shows this logic making a pseudo iOS styled sheet transition.
Screen.Recording.2024-06-10.at.9.35.55.PM.mov
All existing page transitions in Flutter will be overwritten by the incoming route if a
delegatedTransitionis provided. This can be opted out of throughcanTransitionTofor a new route widget. Of Flutter's existing page transitions, this PR only adds aDelegatedTransitionfor the Zoom and Cupertino transitions. The other transitions possible in Material will get delegated transitions in a later PR.