-
Notifications
You must be signed in to change notification settings - Fork 29.7k
Fix tooltip crash when route has secondary animation #172678
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
Conversation
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.
LGTM with nits 👍 .
| void _handlePointerDown(PointerDownEvent event) { | ||
| assert(mounted); | ||
| if (!(ModalRoute.isCurrentOf(context) ?? true)) { | ||
| if (!(_route?.isCurrent ?? true) || (_route?.secondaryAnimation?.isAnimating ?? false)) { |
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 secondaryAnimation is animating, meaning that the route is on its way out, so the tooltip shouldn't be interactive? Maybe consider leaving a comment explaining this if you think it's worth it. I guess you'd have to do that in all 3 places here.
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 to understand this too.
I think pulling this logic out as a small private helper method would be helpful in any case; and that'd make a good home for the 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.
(In particular, I think even just writing down a name for that helper function will be helpful for clarifying what this logic is meant to do.)
| final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse); | ||
| await gesture.addPointer(); | ||
| await tester.tap(find.byType(BackButton)); | ||
| await tester.pump(const Duration(milliseconds: 250)); |
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 is supposed to be a fraction of the page transition right? Use PageTransitionObserver.transitionDuration. That way if the transition changes to be shorter than 250ms, this test will still work.
It's unlikely to be a problem but I was just dealing with this so I'm eager to use PageTransitionObserver :)
| await tester.tap(find.text('Go to Second Page')); | ||
| await tester.pumpAndSettle(); | ||
| await tester.tap(find.text('Go to Third Page')); | ||
| await tester.pumpAndSettle(); |
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.
Usually pumpAndSettle is not enough to pump through a page transition, though it appears to be working here. Maybe add expects for text that's present on each page so you verify which page(s) are visible at any time.
gnprice
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.
Thanks for fixing this!
| // If the route's secondary animation is animating, the route is on its way | ||
| // out. So, the tooltip should be non-interactive. | ||
| final bool routeIsAnimating = _route?.secondaryAnimation?.isAnimating ?? false; |
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.
Very helpful, thanks!
| bool _isTooltipInteractive() { | ||
| final bool routeIsCurrent = _route?.isCurrent ?? false; | ||
| // If the route's secondary animation is animating, the route is on its way | ||
| // out. So, the tooltip should be non-interactive. | ||
| final bool routeIsAnimating = _route?.secondaryAnimation?.isAnimating ?? false; | ||
| return routeIsCurrent && !routeIsAnimating; |
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 _route is null, then both branches of this fall back, but they end up doing so in opposite directions.
I think it'll probably be easiest to think through the logic if there's an if (_route == null) condition at the top that returns the desired result for that case. Then the rest can say _route! and not think about the null case.
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.
In particular it looks like this PR currently flips the answer that's used when the route is null. I'm not sure what the right answer for that is — but I'm also not sure if if that change was intended, because this logic is a bit hard to read for that case 🙂
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.
(With your update, I believe it no longer flips the answer for when the route is null — instead that continues to be treated as meaning the tooltip should be interactive, as if all this logic weren't here. Which I think is the right answer.)
gnprice
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.
Thanks! LGTM.
| } | ||
| } | ||
|
|
||
| bool _isTooltipInteractive() { |
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 this the right fix? Tooltip ideally should not know about route. This feels too specific and the problem may come up again in a different set up.
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.
Good question! I agree Tooltip ideally shouldn't know about Route. There's probably a cleaner solution by using some other abstraction.
The same comment applies already to the previous fix #168546, which this PR fixes a bug in.
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 is the core issue: #167359 (comment). Basically the tooltip shouldn't be displayed mid-transition.
Tooltip uses OverlayPortal behind the scenes:
| return OverlayPortal( |
So maybe the deeper solution is to have OverlayPortal not show its overlaychild in the middle of a route transition? But is that always desired behavior? Or can we hide it behind a flag?
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 used the workaround in this PR previously in another PR for the CupertinoContextMenu overlay entry.
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 root issue is that RenderObject.getTransformTo should not be called during build, it's unsafe even if in a LayoutBuilder.
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.
Good point that Tooltip ideally shouldn't know about the route. Catching up here:
- Is that the getTransformTo in OverlayPortal that you're referring to @LongCatIsLooong? Maybe this?
- What is a better solution here?
- Outgoing routes shouldn't be interactive at all? Maybe that's a bad user experience, not sure. Incoming routes definitely should be interactive. Does this bug happen on incoming routes too?
- The getTransformTo in question should somehow wait until after layout is done?
- This isn't something that OverlayPortal.overlayChildLayoutBuilder would help with is it?
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.
Confirmed, OverlayPortal.overlayChildLayoutBuilder fixes the issue. Thanks @LongCatIsLooong.
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 did a quick grep through the codebase, RawMenuAnchor also uses OverlayPortal and localToGlobal in its buildOverlay method, so this problem might occur there too. Maybe I can add a TODO to migrate to OverlayPortal.overlayChildLayoutBuilder.
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.
Yes good call, can you create an issue 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.
Filed #173440
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.
LGTM, this is a really simple fix now 👍
| assert(mounted); | ||
| if (!(ModalRoute.isCurrentOf(context) ?? true)) { | ||
| return; | ||
| } |
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.
Nice that we don't need these anymore!
| } | ||
| } | ||
|
|
||
| bool _isTooltipInteractive() { |
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.
Yes good call, can you create an issue too?
flutter/flutter@3821790...1590543 2025-08-09 [email protected] Make device debuggable if useDwdsWebSocketConnection is true and added simple test case (flutter/flutter#171648) 2025-08-09 [email protected] Roll Dart SDK from 91cbf6d7563a to 6a7ae1ffd1c9 (1 revision) (flutter/flutter#173487) 2025-08-09 [email protected] add `--variance host_debug_unopt_arm64` for apple chip simulator (flutter/flutter#173475) 2025-08-08 [email protected] [WebParagraph] Fix a property name on newer Chrome versions (flutter/flutter#173477) 2025-08-08 [email protected] Make sure that a Checkbox doesn't crash in 0x0 environment (flutter/flutter#173178) 2025-08-08 [email protected] Make sure that a RawChip doesn't crash in 0x0 environment (flutter/flutter#173265) 2025-08-08 [email protected] Fix tooltip crash when route has secondary animation (flutter/flutter#172678) 2025-08-08 [email protected] Roll Skia from 86824ed582be to 44bb9d908ee4 (3 revisions) (flutter/flutter#173476) 2025-08-08 [email protected] Fix null value reference in `flutter logs` path (flutter/flutter#173437) 2025-08-08 [email protected] Remove jetifier usages from framework and engine (flutter/flutter#173459) 2025-08-08 [email protected] [a11y] Textfield has flag `isFocusable` set to true (flutter/flutter#173235) 2025-08-08 [email protected] Roll Dart SDK from 4b7b565eb468 to 91cbf6d7563a (1 revision) (flutter/flutter#173469) 2025-08-08 [email protected] Roll Packages from 6efb759 to 34948d1 (4 revisions) (flutter/flutter#173470) 2025-08-08 [email protected] Roll Skia from a6ccfeafbfba to 86824ed582be (20 revisions) (flutter/flutter#173468) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages Please CC [email protected],[email protected] on the revert to ensure that a human is aware of the problem. To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
Makes the tooltip interactive if the route is the current route and the route is not animating out. Added `_route` to cache `ModalRoute.of(context)`. Consolidates [Fix the issue with Tooltip](flutter#168546) and [Delay showing tooltip during page transition](flutter#167614) Fix [[Desktop] [Web] [Regression] [3.32] AppBar back - RenderBox was not laid out - TooltipState._buildTooltipOverlay](flutter#169741)
Makes the tooltip interactive if the route is the current route and the route is not animating out. Added `_route` to cache `ModalRoute.of(context)`. Consolidates [Fix the issue with Tooltip](flutter#168546) and [Delay showing tooltip during page transition](flutter#167614) Fix [[Desktop] [Web] [Regression] [3.32] AppBar back - RenderBox was not laid out - TooltipState._buildTooltipOverlay](flutter#169741)
Makes the tooltip interactive if the route is the current route and the route is not animating out. Added `_route` to cache `ModalRoute.of(context)`. Consolidates [Fix the issue with Tooltip](flutter#168546) and [Delay showing tooltip during page transition](flutter#167614) Fix [[Desktop] [Web] [Regression] [3.32] AppBar back - RenderBox was not laid out - TooltipState._buildTooltipOverlay](flutter#169741)
Makes the tooltip interactive if the route is the current route and the route is not animating out. Added `_route` to cache `ModalRoute.of(context)`. Consolidates [Fix the issue with Tooltip](flutter#168546) and [Delay showing tooltip during page transition](flutter#167614) Fix [[Desktop] [Web] [Regression] [3.32] AppBar back - RenderBox was not laid out - TooltipState._buildTooltipOverlay](flutter#169741)
Makes the tooltip interactive if the route is the current route and the route is not animating out. Added `_route` to cache `ModalRoute.of(context)`. Consolidates [Fix the issue with Tooltip](flutter#168546) and [Delay showing tooltip during page transition](flutter#167614) Fix [[Desktop] [Web] [Regression] [3.32] AppBar back - RenderBox was not laid out - TooltipState._buildTooltipOverlay](flutter#169741)
Consolidates Fix the issue with Tooltip and Delay showing tooltip during page transition
Fix [Desktop] [Web] [Regression] [3.32] AppBar back - RenderBox was not laid out - TooltipState._buildTooltipOverlay