Skip to content

Conversation

@victorsanni
Copy link
Contributor

@victorsanni victorsanni commented Jul 24, 2025

@github-actions github-actions bot added framework flutter/packages/flutter repository. See also f: labels. f: material design flutter/packages/flutter/material repository. labels Jul 24, 2025
@victorsanni victorsanni marked this pull request as ready for review July 24, 2025 18:19
@victorsanni victorsanni changed the title Fix tooltip crash Fix tooltip crash when route has secondary animation Jul 24, 2025
Copy link
Contributor

@justinmc justinmc left a 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)) {
Copy link
Contributor

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.

Copy link
Member

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.

Copy link
Member

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));
Copy link
Contributor

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 :)

Comment on lines 3554 to 3557
await tester.tap(find.text('Go to Second Page'));
await tester.pumpAndSettle();
await tester.tap(find.text('Go to Third Page'));
await tester.pumpAndSettle();
Copy link
Contributor

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.

Copy link
Member

@gnprice gnprice left a 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!

@victorsanni victorsanni requested a review from gnprice July 24, 2025 19:47
Comment on lines 611 to 613
// 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;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very helpful, thanks!

Comment on lines 609 to 614
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;
Copy link
Member

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.

Copy link
Member

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 🙂

Copy link
Member

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.)

@victorsanni victorsanni requested a review from gnprice July 24, 2025 19:58
Copy link
Member

@gnprice gnprice left a 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() {
Copy link
Contributor

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.

Copy link
Member

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.

Copy link
Contributor Author

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:

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?

Copy link
Contributor Author

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.

Copy link
Contributor

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.

Copy link
Contributor

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?

Copy link
Contributor Author

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.

Copy link
Contributor Author

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.

Copy link
Contributor

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?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Filed #173440

Copy link
Contributor

@justinmc justinmc left a 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 👍

Comment on lines -609 to -612
assert(mounted);
if (!(ModalRoute.isCurrentOf(context) ?? true)) {
return;
}
Copy link
Contributor

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() {
Copy link
Contributor

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?

@victorsanni victorsanni added the autosubmit Merge PR when tree becomes green via auto submit App label Aug 8, 2025
@auto-submit auto-submit bot added this pull request to the merge queue Aug 8, 2025
Merged via the queue into flutter:master with commit f1abbe2 Aug 8, 2025
75 checks passed
@flutter-dashboard flutter-dashboard bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Aug 8, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Aug 9, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Aug 9, 2025
auto-submit bot pushed a commit to flutter/packages that referenced this pull request Aug 9, 2025
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
SydneyBao pushed a commit to SydneyBao/flutter that referenced this pull request Aug 11, 2025
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)
ksokolovskyi pushed a commit to ksokolovskyi/flutter that referenced this pull request Aug 19, 2025
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)
mboetger pushed a commit to mboetger/flutter that referenced this pull request Sep 18, 2025
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)
korca0220 pushed a commit to korca0220/flutter that referenced this pull request Sep 22, 2025
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)
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Nov 12, 2025
lucaantonelli pushed a commit to lucaantonelli/flutter that referenced this pull request Nov 21, 2025
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)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

f: material design flutter/packages/flutter/material repository. framework flutter/packages/flutter repository. See also f: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Desktop] [Web] [Regression] [3.32] AppBar back - RenderBox was not laid out - TooltipState._buildTooltipOverlay

4 participants