diff --git a/packages/flutter/lib/material.dart b/packages/flutter/lib/material.dart index 525047ff44..d530490159 100644 --- a/packages/flutter/lib/material.dart +++ b/packages/flutter/lib/material.dart @@ -158,7 +158,6 @@ export 'src/material/toggle_buttons_theme.dart'; export 'src/material/toggleable.dart'; export 'src/material/tooltip.dart'; export 'src/material/tooltip_theme.dart'; -export 'src/material/tooltip_visibility.dart'; export 'src/material/typography.dart'; export 'src/material/user_accounts_drawer_header.dart'; export 'widgets.dart'; diff --git a/packages/flutter/lib/src/material/tooltip.dart b/packages/flutter/lib/src/material/tooltip.dart index cdfbceb607..40ee3e1104 100644 --- a/packages/flutter/lib/src/material/tooltip.dart +++ b/packages/flutter/lib/src/material/tooltip.dart @@ -14,7 +14,6 @@ import 'colors.dart'; import 'feedback.dart'; import 'theme.dart'; import 'tooltip_theme.dart'; -import 'tooltip_visibility.dart'; /// A material design tooltip. /// @@ -70,7 +69,6 @@ import 'tooltip_visibility.dart'; /// /// * /// * [TooltipTheme] or [ThemeData.tooltipTheme] -/// * [TooltipVisibility] class Tooltip extends StatefulWidget { /// Creates a tooltip. /// @@ -329,7 +327,6 @@ class _TooltipState extends State with SingleTickerProviderStateMixin { late bool enableFeedback; late bool _isConcealed; late bool _forceRemoval; - late bool _visible; /// The plain text message for this tooltip. /// @@ -355,12 +352,6 @@ class _TooltipState extends State with SingleTickerProviderStateMixin { GestureBinding.instance!.pointerRouter.addGlobalRoute(_handlePointerEvent); } - @override - void didChangeDependencies() { - super.didChangeDependencies(); - _visible = TooltipVisibility.of(context); - } - // https://material.io/components/tooltips#specs double _getDefaultTooltipHeight() { final ThemeData theme = Theme.of(context); @@ -492,11 +483,8 @@ class _TooltipState extends State with SingleTickerProviderStateMixin { /// Shows the tooltip if it is not already visible. /// - /// Returns `false` when the tooltip shouldn't be shown or when the tooltip - /// was already visible. + /// Returns `false` when the tooltip was already visible. bool ensureTooltipVisible() { - if (!_visible) - return false; _showTimer?.cancel(); _showTimer = null; _forceRemoval = false; @@ -683,31 +671,27 @@ class _TooltipState extends State with SingleTickerProviderStateMixin { triggerMode = widget.triggerMode ?? tooltipTheme.triggerMode ?? _defaultTriggerMode; enableFeedback = widget.enableFeedback ?? tooltipTheme.enableFeedback ?? _defaultEnableFeedback; - Widget result = Semantics( - label: excludeFromSemantics - ? null - : _tooltipMessage, - child: widget.child, + Widget result = GestureDetector( + behavior: HitTestBehavior.opaque, + onLongPress: (triggerMode == TooltipTriggerMode.longPress) ? + _handlePress : null, + onTap: (triggerMode == TooltipTriggerMode.tap) ? _handlePress : null, + excludeFromSemantics: true, + child: Semantics( + label: excludeFromSemantics + ? null + : _tooltipMessage, + child: widget.child, + ), ); - // Only check for gestures if tooltip should be visible. - if (_visible) { - result = GestureDetector( - behavior: HitTestBehavior.opaque, - onLongPress: (triggerMode == TooltipTriggerMode.longPress) ? - _handlePress : null, - onTap: (triggerMode == TooltipTriggerMode.tap) ? _handlePress : null, - excludeFromSemantics: true, + // Only check for hovering if there is a mouse connected. + if (_mouseIsConnected) { + result = MouseRegion( + onEnter: (_) => _handleMouseEnter(), + onExit: (_) => _handleMouseExit(), child: result, ); - // Only check for hovering if there is a mouse connected. - if (_mouseIsConnected) { - result = MouseRegion( - onEnter: (_) => _handleMouseEnter(), - onExit: (_) => _handleMouseExit(), - child: result, - ); - } } return result; diff --git a/packages/flutter/lib/src/material/tooltip_theme.dart b/packages/flutter/lib/src/material/tooltip_theme.dart index 1f43af227d..dfb5a61a8b 100644 --- a/packages/flutter/lib/src/material/tooltip_theme.dart +++ b/packages/flutter/lib/src/material/tooltip_theme.dart @@ -242,10 +242,6 @@ class TooltipThemeData with Diagnosticable { /// ) /// ``` /// {@end-tool} -/// -/// See also: -/// -/// * [TooltipVisibility], which can be used to visually disable descendant [Tooltip]s. class TooltipTheme extends InheritedTheme { /// Creates a tooltip theme that controls the configurations for /// [Tooltip]. diff --git a/packages/flutter/lib/src/material/tooltip_visibility.dart b/packages/flutter/lib/src/material/tooltip_visibility.dart deleted file mode 100644 index d242ad1f43..0000000000 --- a/packages/flutter/lib/src/material/tooltip_visibility.dart +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:flutter/widgets.dart'; - -class _TooltipVisibilityScope extends InheritedWidget { - const _TooltipVisibilityScope({ - Key? key, - required Widget child, - required this.visible, - }) : super(key: key, child: child); - - final bool visible; - - @override - bool updateShouldNotify(_TooltipVisibilityScope old) { - return old.visible != visible; - } -} - -/// Overrides the visibility of descendant [Tooltip] widgets. -/// -/// If disabled, the descendant [Tooltip] widgets will not display a tooltip -/// when tapped, long-pressed, hovered by the mouse, or when -/// `ensureTooltipVisible` is called. This only visually disables tooltips but -/// continues to provide any semantic information that is provided. -class TooltipVisibility extends StatelessWidget { - /// Creates a widget that configures the visibility of [Tooltip]. - /// - /// Both arguments must not be null. - const TooltipVisibility({ - Key? key, - required this.child, - required this.visible, - }) : super(key: key); - - /// The widget below this widget in the tree. - /// - /// The entire app can be wrapped in this widget to globally control [Tooltip] - /// visibility. - /// - /// {@macro flutter.widgets.ProxyWidget.child} - final Widget child; - - /// Determines the visibility of [Tooltip] widgets that inherit from this widget. - final bool visible; - - /// The [visible] of the closest instance of this class that encloses the - /// given context. Defaults to `true` if none are found. - static bool of(BuildContext context) { - final _TooltipVisibilityScope? visibility = context.dependOnInheritedWidgetOfExactType<_TooltipVisibilityScope>(); - return visibility?.visible ?? true; - } - - @override - Widget build(BuildContext context) { - return _TooltipVisibilityScope( - child: child, - visible: visible, - ); - } -} diff --git a/packages/flutter/test/material/tooltip_visibility_test.dart b/packages/flutter/test/material/tooltip_visibility_test.dart deleted file mode 100644 index febf9a0479..0000000000 --- a/packages/flutter/test/material/tooltip_visibility_test.dart +++ /dev/null @@ -1,223 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'dart:ui'; - -import 'package:flutter/gestures.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; -import 'package:flutter_test/flutter_test.dart'; - -void _ensureTooltipVisible(GlobalKey key) { - // This function uses "as dynamic" to defeat the static analysis. In general - // you want to avoid using this style in your code, as it will cause the - // analyzer to be unable to help you catch errors. - // - // In this case, we do it because we are trying to call internal methods of - // the tooltip code in order to test it. Normally, the state of a tooltip is a - // private class, but by using a GlobalKey we can get a handle to that object - // and by using "as dynamic" we can bypass the analyzer's type checks and call - // methods that we aren't supposed to be able to know about. - // - // It's ok to do this in tests, but you really don't want to do it in - // production code. - // ignore: avoid_dynamic_calls - (key.currentState as dynamic).ensureTooltipVisible(); -} - -const String tooltipText = 'TIP'; - -void main() { - testWidgets('Tooltip does not build MouseRegion when mouse is detected and in TooltipVisibility with visibility = false', (WidgetTester tester) async { - final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse); - addTearDown(() async { - if (gesture != null) - return gesture.removePointer(); - }); - await gesture.addPointer(); - await gesture.moveTo(const Offset(1.0, 1.0)); - await tester.pump(); - await gesture.moveTo(Offset.zero); - - await tester.pumpWidget( - const MaterialApp( - home: TooltipVisibility( - visible: false, - child: Tooltip( - message: tooltipText, - child: SizedBox( - width: 100.0, - height: 100.0, - ), - ), - ), - ), - ); - - expect(find.descendant(of: find.byType(Tooltip), matching: find.byType(MouseRegion)), findsNothing); - }); - - testWidgets('Tooltip does not show when hovered when in TooltipVisibility with visible = false', (WidgetTester tester) async { - const Duration waitDuration = Duration.zero; - final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse); - addTearDown(() async { - if (gesture != null) - return gesture.removePointer(); - }); - await gesture.addPointer(); - await gesture.moveTo(const Offset(1.0, 1.0)); - await tester.pump(); - await gesture.moveTo(Offset.zero); - - await tester.pumpWidget( - const MaterialApp( - home: Center( - child: TooltipVisibility( - visible: false, - child: Tooltip( - message: tooltipText, - waitDuration: waitDuration, - child: SizedBox( - width: 100.0, - height: 100.0, - ), - ), - ), - ), - ), - ); - - final Finder tooltip = find.byType(Tooltip); - await gesture.moveTo(Offset.zero); - await tester.pump(); - await gesture.moveTo(tester.getCenter(tooltip)); - await tester.pump(); - // Wait for it to appear. - await tester.pump(waitDuration); - expect(find.text(tooltipText), findsNothing); - }); - - testWidgets('Tooltip shows when hovered when in TooltipVisibility with visible = true', (WidgetTester tester) async { - const Duration waitDuration = Duration.zero; - TestGesture? gesture = await tester.createGesture(kind: PointerDeviceKind.mouse); - addTearDown(() async { - if (gesture != null) - return gesture.removePointer(); - }); - await gesture.addPointer(); - await gesture.moveTo(const Offset(1.0, 1.0)); - await tester.pump(); - await gesture.moveTo(Offset.zero); - - await tester.pumpWidget( - const MaterialApp( - home: Center( - child: TooltipVisibility( - visible: true, - child: Tooltip( - message: tooltipText, - waitDuration: waitDuration, - child: SizedBox( - width: 100.0, - height: 100.0, - ), - ), - ), - ), - ), - ); - - final Finder tooltip = find.byType(Tooltip); - await gesture.moveTo(Offset.zero); - await tester.pump(); - await gesture.moveTo(tester.getCenter(tooltip)); - await tester.pump(); - // Wait for it to appear. - await tester.pump(waitDuration); - expect(find.text(tooltipText), findsOneWidget); - - // Wait for it to disappear. - await gesture.moveTo(Offset.zero); - await tester.pumpAndSettle(); - await gesture.removePointer(); - gesture = null; - expect(find.text(tooltipText), findsNothing); - }); - - testWidgets('Tooltip does not build GestureDetector when in TooltipVisibility with visibility = false', (WidgetTester tester) async { - await setWidgetForTooltipMode(tester, TooltipTriggerMode.tap, false); - - expect(find.byType(GestureDetector), findsNothing); - }); - - testWidgets('Tooltip triggers on tap when trigger mode is tap and in TooltipVisibility with visible = true', (WidgetTester tester) async { - await setWidgetForTooltipMode(tester, TooltipTriggerMode.tap, true); - - final Finder tooltip = find.byType(Tooltip); - expect(find.text(tooltipText), findsNothing); - - await testGestureTap(tester, tooltip); - expect(find.text(tooltipText), findsOneWidget); - }); - - testWidgets('Tooltip does not trigger manually when in TooltipVisibility with visible = false', (WidgetTester tester) async { - final GlobalKey key = GlobalKey(); - await tester.pumpWidget( - MaterialApp( - home: TooltipVisibility( - visible: false, - child: Tooltip( - key: key, - message: tooltipText, - child: const SizedBox(width: 100.0, height: 100.0), - ), - ), - ), - ); - - _ensureTooltipVisible(key); - await tester.pump(); - expect(find.text(tooltipText), findsNothing); - }); - - testWidgets('Tooltip triggers manually when in TooltipVisibility with visible = true', (WidgetTester tester) async { - final GlobalKey key = GlobalKey(); - await tester.pumpWidget( - MaterialApp( - home: TooltipVisibility( - visible: true, - child: Tooltip( - key: key, - message: tooltipText, - child: const SizedBox(width: 100.0, height: 100.0), - ), - ), - ), - ); - - _ensureTooltipVisible(key); - await tester.pump(); - expect(find.text(tooltipText), findsOneWidget); - }); -} - -Future setWidgetForTooltipMode(WidgetTester tester, TooltipTriggerMode triggerMode, bool visibility) async { - await tester.pumpWidget( - MaterialApp( - home: TooltipVisibility( - visible: visibility, - child: Tooltip( - message: tooltipText, - triggerMode: triggerMode, - child: const SizedBox(width: 100.0, height: 100.0), - ), - ), - ), - ); -} - -Future testGestureTap(WidgetTester tester, Finder tooltip) async { - await tester.tap(tooltip); - await tester.pump(const Duration(milliseconds: 10)); -}