Unverified Commit a2424602 authored by Taha Tesser's avatar Taha Tesser Committed by GitHub

Make `Tooltip` state class public (#100553)

parent 2e5ad37b
...@@ -223,15 +223,15 @@ class Tooltip extends StatefulWidget { ...@@ -223,15 +223,15 @@ class Tooltip extends StatefulWidget {
/// * [Feedback], for providing platform-specific feedback to certain actions. /// * [Feedback], for providing platform-specific feedback to certain actions.
final bool? enableFeedback; final bool? enableFeedback;
static final List<_TooltipState> _openedTooltips = <_TooltipState>[]; static final List<TooltipState> _openedTooltips = <TooltipState>[];
// Causes any current tooltips to be concealed. Only called for mouse hover enter // Causes any current tooltips to be concealed. Only called for mouse hover enter
// detections. Won't conceal the supplied tooltip. // detections. Won't conceal the supplied tooltip.
static void _concealOtherTooltips(_TooltipState current) { static void _concealOtherTooltips(TooltipState current) {
if (_openedTooltips.isNotEmpty) { if (_openedTooltips.isNotEmpty) {
// Avoid concurrent modification. // Avoid concurrent modification.
final List<_TooltipState> openedTooltips = _openedTooltips.toList(); final List<TooltipState> openedTooltips = _openedTooltips.toList();
for (final _TooltipState state in openedTooltips) { for (final TooltipState state in openedTooltips) {
if (state == current) { if (state == current) {
continue; continue;
} }
...@@ -255,8 +255,8 @@ class Tooltip extends StatefulWidget { ...@@ -255,8 +255,8 @@ class Tooltip extends StatefulWidget {
static bool dismissAllToolTips() { static bool dismissAllToolTips() {
if (_openedTooltips.isNotEmpty) { if (_openedTooltips.isNotEmpty) {
// Avoid concurrent modification. // Avoid concurrent modification.
final List<_TooltipState> openedTooltips = _openedTooltips.toList(); final List<TooltipState> openedTooltips = _openedTooltips.toList();
for (final _TooltipState state in openedTooltips) { for (final TooltipState state in openedTooltips) {
state._dismissTooltip(immediately: true); state._dismissTooltip(immediately: true);
} }
return true; return true;
...@@ -265,7 +265,7 @@ class Tooltip extends StatefulWidget { ...@@ -265,7 +265,7 @@ class Tooltip extends StatefulWidget {
} }
@override @override
State<Tooltip> createState() => _TooltipState(); State<Tooltip> createState() => TooltipState();
@override @override
void debugFillProperties(DiagnosticPropertiesBuilder properties) { void debugFillProperties(DiagnosticPropertiesBuilder properties) {
...@@ -295,7 +295,11 @@ class Tooltip extends StatefulWidget { ...@@ -295,7 +295,11 @@ class Tooltip extends StatefulWidget {
} }
} }
class _TooltipState extends State<Tooltip> with SingleTickerProviderStateMixin { /// Contains the state for a [Tooltip].
///
/// This class can be used to programmatically show the Tooltip, see the
/// [ensureTooltipVisible] method.
class TooltipState extends State<Tooltip> with SingleTickerProviderStateMixin {
static const double _defaultVerticalOffset = 24.0; static const double _defaultVerticalOffset = 24.0;
static const bool _defaultPreferBelow = true; static const bool _defaultPreferBelow = true;
static const EdgeInsetsGeometry _defaultMargin = EdgeInsets.zero; static const EdgeInsetsGeometry _defaultMargin = EdgeInsets.zero;
...@@ -308,25 +312,25 @@ class _TooltipState extends State<Tooltip> with SingleTickerProviderStateMixin { ...@@ -308,25 +312,25 @@ class _TooltipState extends State<Tooltip> with SingleTickerProviderStateMixin {
static const TooltipTriggerMode _defaultTriggerMode = TooltipTriggerMode.longPress; static const TooltipTriggerMode _defaultTriggerMode = TooltipTriggerMode.longPress;
static const bool _defaultEnableFeedback = true; static const bool _defaultEnableFeedback = true;
late double height; late double _height;
late EdgeInsetsGeometry padding; late EdgeInsetsGeometry _padding;
late EdgeInsetsGeometry margin; late EdgeInsetsGeometry _margin;
late Decoration decoration; late Decoration _decoration;
late TextStyle textStyle; late TextStyle _textStyle;
late double verticalOffset; late double _verticalOffset;
late bool preferBelow; late bool _preferBelow;
late bool excludeFromSemantics; late bool _excludeFromSemantics;
late AnimationController _controller; late AnimationController _controller;
OverlayEntry? _entry; OverlayEntry? _entry;
Timer? _dismissTimer; Timer? _dismissTimer;
Timer? _showTimer; Timer? _showTimer;
late Duration showDuration; late Duration _showDuration;
late Duration hoverShowDuration; late Duration _hoverShowDuration;
late Duration waitDuration; late Duration _waitDuration;
late bool _mouseIsConnected; late bool _mouseIsConnected;
bool _pressActivated = false; bool _pressActivated = false;
late TooltipTriggerMode triggerMode; late TooltipTriggerMode _triggerMode;
late bool enableFeedback; late bool _enableFeedback;
late bool _isConcealed; late bool _isConcealed;
late bool _forceRemoval; late bool _forceRemoval;
late bool _visible; late bool _visible;
...@@ -436,9 +440,9 @@ class _TooltipState extends State<Tooltip> with SingleTickerProviderStateMixin { ...@@ -436,9 +440,9 @@ class _TooltipState extends State<Tooltip> with SingleTickerProviderStateMixin {
// still concealed or not. // still concealed or not.
_forceRemoval = true; _forceRemoval = true;
if (_pressActivated) { if (_pressActivated) {
_dismissTimer ??= Timer(showDuration, _controller.reverse); _dismissTimer ??= Timer(_showDuration, _controller.reverse);
} else { } else {
_dismissTimer ??= Timer(hoverShowDuration, _controller.reverse); _dismissTimer ??= Timer(_hoverShowDuration, _controller.reverse);
} }
_pressActivated = false; _pressActivated = false;
} }
...@@ -450,7 +454,7 @@ class _TooltipState extends State<Tooltip> with SingleTickerProviderStateMixin { ...@@ -450,7 +454,7 @@ class _TooltipState extends State<Tooltip> with SingleTickerProviderStateMixin {
ensureTooltipVisible(); ensureTooltipVisible();
return; return;
} }
_showTimer ??= Timer(waitDuration, ensureTooltipVisible); _showTimer ??= Timer(_waitDuration, ensureTooltipVisible);
} }
void _concealTooltip() { void _concealTooltip() {
...@@ -519,7 +523,7 @@ class _TooltipState extends State<Tooltip> with SingleTickerProviderStateMixin { ...@@ -519,7 +523,7 @@ class _TooltipState extends State<Tooltip> with SingleTickerProviderStateMixin {
return true; return true;
} }
static final Set<_TooltipState> _mouseIn = <_TooltipState>{}; static final Set<TooltipState> _mouseIn = <TooltipState>{};
void _handleMouseEnter() { void _handleMouseEnter() {
if (mounted) { if (mounted) {
...@@ -553,20 +557,20 @@ class _TooltipState extends State<Tooltip> with SingleTickerProviderStateMixin { ...@@ -553,20 +557,20 @@ class _TooltipState extends State<Tooltip> with SingleTickerProviderStateMixin {
textDirection: Directionality.of(context), textDirection: Directionality.of(context),
child: _TooltipOverlay( child: _TooltipOverlay(
richMessage: widget.richMessage ?? TextSpan(text: widget.message), richMessage: widget.richMessage ?? TextSpan(text: widget.message),
height: height, height: _height,
padding: padding, padding: _padding,
margin: margin, margin: _margin,
onEnter: _mouseIsConnected ? (_) => _handleMouseEnter() : null, onEnter: _mouseIsConnected ? (_) => _handleMouseEnter() : null,
onExit: _mouseIsConnected ? (_) => _handleMouseExit() : null, onExit: _mouseIsConnected ? (_) => _handleMouseExit() : null,
decoration: decoration, decoration: _decoration,
textStyle: textStyle, textStyle: _textStyle,
animation: CurvedAnimation( animation: CurvedAnimation(
parent: _controller, parent: _controller,
curve: Curves.fastOutSlowIn, curve: Curves.fastOutSlowIn,
), ),
target: target, target: target,
verticalOffset: verticalOffset, verticalOffset: _verticalOffset,
preferBelow: preferBelow, preferBelow: _preferBelow,
), ),
); );
_entry = OverlayEntry(builder: (BuildContext context) => overlay); _entry = OverlayEntry(builder: (BuildContext context) => overlay);
...@@ -632,8 +636,8 @@ class _TooltipState extends State<Tooltip> with SingleTickerProviderStateMixin { ...@@ -632,8 +636,8 @@ class _TooltipState extends State<Tooltip> with SingleTickerProviderStateMixin {
void _handlePress() { void _handlePress() {
_pressActivated = true; _pressActivated = true;
final bool tooltipCreated = ensureTooltipVisible(); final bool tooltipCreated = ensureTooltipVisible();
if (tooltipCreated && enableFeedback) { if (tooltipCreated && _enableFeedback) {
if (triggerMode == TooltipTriggerMode.longPress) if (_triggerMode == TooltipTriggerMode.longPress)
Feedback.forLongPress(context); Feedback.forLongPress(context);
else else
Feedback.forTap(context); Feedback.forTap(context);
...@@ -673,22 +677,22 @@ class _TooltipState extends State<Tooltip> with SingleTickerProviderStateMixin { ...@@ -673,22 +677,22 @@ class _TooltipState extends State<Tooltip> with SingleTickerProviderStateMixin {
); );
} }
height = widget.height ?? tooltipTheme.height ?? _getDefaultTooltipHeight(); _height = widget.height ?? tooltipTheme.height ?? _getDefaultTooltipHeight();
padding = widget.padding ?? tooltipTheme.padding ?? _getDefaultPadding(); _padding = widget.padding ?? tooltipTheme.padding ?? _getDefaultPadding();
margin = widget.margin ?? tooltipTheme.margin ?? _defaultMargin; _margin = widget.margin ?? tooltipTheme.margin ?? _defaultMargin;
verticalOffset = widget.verticalOffset ?? tooltipTheme.verticalOffset ?? _defaultVerticalOffset; _verticalOffset = widget.verticalOffset ?? tooltipTheme.verticalOffset ?? _defaultVerticalOffset;
preferBelow = widget.preferBelow ?? tooltipTheme.preferBelow ?? _defaultPreferBelow; _preferBelow = widget.preferBelow ?? tooltipTheme.preferBelow ?? _defaultPreferBelow;
excludeFromSemantics = widget.excludeFromSemantics ?? tooltipTheme.excludeFromSemantics ?? _defaultExcludeFromSemantics; _excludeFromSemantics = widget.excludeFromSemantics ?? tooltipTheme.excludeFromSemantics ?? _defaultExcludeFromSemantics;
decoration = widget.decoration ?? tooltipTheme.decoration ?? defaultDecoration; _decoration = widget.decoration ?? tooltipTheme.decoration ?? defaultDecoration;
textStyle = widget.textStyle ?? tooltipTheme.textStyle ?? defaultTextStyle; _textStyle = widget.textStyle ?? tooltipTheme.textStyle ?? defaultTextStyle;
waitDuration = widget.waitDuration ?? tooltipTheme.waitDuration ?? _defaultWaitDuration; _waitDuration = widget.waitDuration ?? tooltipTheme.waitDuration ?? _defaultWaitDuration;
showDuration = widget.showDuration ?? tooltipTheme.showDuration ?? _defaultShowDuration; _showDuration = widget.showDuration ?? tooltipTheme.showDuration ?? _defaultShowDuration;
hoverShowDuration = widget.showDuration ?? tooltipTheme.showDuration ?? _defaultHoverShowDuration; _hoverShowDuration = widget.showDuration ?? tooltipTheme.showDuration ?? _defaultHoverShowDuration;
triggerMode = widget.triggerMode ?? tooltipTheme.triggerMode ?? _defaultTriggerMode; _triggerMode = widget.triggerMode ?? tooltipTheme.triggerMode ?? _defaultTriggerMode;
enableFeedback = widget.enableFeedback ?? tooltipTheme.enableFeedback ?? _defaultEnableFeedback; _enableFeedback = widget.enableFeedback ?? tooltipTheme.enableFeedback ?? _defaultEnableFeedback;
Widget result = Semantics( Widget result = Semantics(
label: excludeFromSemantics label: _excludeFromSemantics
? null ? null
: _tooltipMessage, : _tooltipMessage,
child: widget.child, child: widget.child,
...@@ -698,9 +702,9 @@ class _TooltipState extends State<Tooltip> with SingleTickerProviderStateMixin { ...@@ -698,9 +702,9 @@ class _TooltipState extends State<Tooltip> with SingleTickerProviderStateMixin {
if (_visible) { if (_visible) {
result = GestureDetector( result = GestureDetector(
behavior: HitTestBehavior.opaque, behavior: HitTestBehavior.opaque,
onLongPress: (triggerMode == TooltipTriggerMode.longPress) ? onLongPress: (_triggerMode == TooltipTriggerMode.longPress) ?
_handlePress : null, _handlePress : null,
onTap: (triggerMode == TooltipTriggerMode.tap) ? _handlePress : null, onTap: (_triggerMode == TooltipTriggerMode.tap) ? _handlePress : null,
excludeFromSemantics: true, excludeFromSemantics: true,
child: result, child: result,
); );
......
...@@ -14,23 +14,6 @@ import '../rendering/mock_canvas.dart'; ...@@ -14,23 +14,6 @@ import '../rendering/mock_canvas.dart';
import '../widgets/semantics_tester.dart'; import '../widgets/semantics_tester.dart';
import 'feedback_tester.dart'; import 'feedback_tester.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'; const String tooltipText = 'TIP';
Finder _findTooltipContainer(String tooltipText) { Finder _findTooltipContainer(String tooltipText) {
...@@ -42,7 +25,7 @@ Finder _findTooltipContainer(String tooltipText) { ...@@ -42,7 +25,7 @@ Finder _findTooltipContainer(String tooltipText) {
void main() { void main() {
testWidgets('Does tooltip end up in the right place - center', (WidgetTester tester) async { testWidgets('Does tooltip end up in the right place - center', (WidgetTester tester) async {
final GlobalKey key = GlobalKey(); final GlobalKey<TooltipState> tooltipKey = GlobalKey<TooltipState>();
await tester.pumpWidget( await tester.pumpWidget(
Directionality( Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
...@@ -56,7 +39,7 @@ void main() { ...@@ -56,7 +39,7 @@ void main() {
left: 300.0, left: 300.0,
top: 0.0, top: 0.0,
child: Tooltip( child: Tooltip(
key: key, key: tooltipKey,
message: tooltipText, message: tooltipText,
height: 20.0, height: 20.0,
padding: const EdgeInsets.all(5.0), padding: const EdgeInsets.all(5.0),
...@@ -76,7 +59,7 @@ void main() { ...@@ -76,7 +59,7 @@ void main() {
), ),
), ),
); );
_ensureTooltipVisible(key); tooltipKey.currentState?.ensureTooltipVisible();
await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0) await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0)
/********************* 800x600 screen /********************* 800x600 screen
...@@ -99,7 +82,7 @@ void main() { ...@@ -99,7 +82,7 @@ void main() {
}); });
testWidgets('Does tooltip end up in the right place - center with padding outside overlay', (WidgetTester tester) async { testWidgets('Does tooltip end up in the right place - center with padding outside overlay', (WidgetTester tester) async {
final GlobalKey key = GlobalKey(); final GlobalKey<TooltipState> tooltipKey = GlobalKey<TooltipState>();
await tester.pumpWidget( await tester.pumpWidget(
Directionality( Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
...@@ -115,7 +98,7 @@ void main() { ...@@ -115,7 +98,7 @@ void main() {
left: 300.0, left: 300.0,
top: 0.0, top: 0.0,
child: Tooltip( child: Tooltip(
key: key, key: tooltipKey,
message: tooltipText, message: tooltipText,
height: 20.0, height: 20.0,
padding: const EdgeInsets.all(5.0), padding: const EdgeInsets.all(5.0),
...@@ -136,7 +119,7 @@ void main() { ...@@ -136,7 +119,7 @@ void main() {
), ),
), ),
); );
_ensureTooltipVisible(key); tooltipKey.currentState?.ensureTooltipVisible();
await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0) await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0)
/************************ 800x600 screen /************************ 800x600 screen
...@@ -161,7 +144,7 @@ void main() { ...@@ -161,7 +144,7 @@ void main() {
}); });
testWidgets('Does tooltip end up in the right place - top left', (WidgetTester tester) async { testWidgets('Does tooltip end up in the right place - top left', (WidgetTester tester) async {
final GlobalKey key = GlobalKey(); final GlobalKey<TooltipState> tooltipKey = GlobalKey<TooltipState>();
await tester.pumpWidget( await tester.pumpWidget(
Directionality( Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
...@@ -175,7 +158,7 @@ void main() { ...@@ -175,7 +158,7 @@ void main() {
left: 0.0, left: 0.0,
top: 0.0, top: 0.0,
child: Tooltip( child: Tooltip(
key: key, key: tooltipKey,
message: tooltipText, message: tooltipText,
height: 20.0, height: 20.0,
padding: const EdgeInsets.all(5.0), padding: const EdgeInsets.all(5.0),
...@@ -195,7 +178,7 @@ void main() { ...@@ -195,7 +178,7 @@ void main() {
), ),
), ),
); );
_ensureTooltipVisible(key); tooltipKey.currentState?.ensureTooltipVisible();
await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0) await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0)
/********************* 800x600 screen /********************* 800x600 screen
...@@ -215,7 +198,7 @@ void main() { ...@@ -215,7 +198,7 @@ void main() {
}); });
testWidgets('Does tooltip end up in the right place - center prefer above fits', (WidgetTester tester) async { testWidgets('Does tooltip end up in the right place - center prefer above fits', (WidgetTester tester) async {
final GlobalKey key = GlobalKey(); final GlobalKey<TooltipState> tooltipKey = GlobalKey<TooltipState>();
await tester.pumpWidget( await tester.pumpWidget(
Directionality( Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
...@@ -229,7 +212,7 @@ void main() { ...@@ -229,7 +212,7 @@ void main() {
left: 400.0, left: 400.0,
top: 300.0, top: 300.0,
child: Tooltip( child: Tooltip(
key: key, key: tooltipKey,
message: tooltipText, message: tooltipText,
height: 100.0, height: 100.0,
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
...@@ -249,7 +232,7 @@ void main() { ...@@ -249,7 +232,7 @@ void main() {
), ),
), ),
); );
_ensureTooltipVisible(key); tooltipKey.currentState?.ensureTooltipVisible();
await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0) await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0)
/********************* 800x600 screen /********************* 800x600 screen
...@@ -271,7 +254,7 @@ void main() { ...@@ -271,7 +254,7 @@ void main() {
}); });
testWidgets('Does tooltip end up in the right place - center prefer above does not fit', (WidgetTester tester) async { testWidgets('Does tooltip end up in the right place - center prefer above does not fit', (WidgetTester tester) async {
final GlobalKey key = GlobalKey(); final GlobalKey<TooltipState> tooltipKey = GlobalKey<TooltipState>();
await tester.pumpWidget( await tester.pumpWidget(
Directionality( Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
...@@ -285,7 +268,7 @@ void main() { ...@@ -285,7 +268,7 @@ void main() {
left: 400.0, left: 400.0,
top: 299.0, top: 299.0,
child: Tooltip( child: Tooltip(
key: key, key: tooltipKey,
message: tooltipText, message: tooltipText,
height: 190.0, height: 190.0,
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
...@@ -305,7 +288,7 @@ void main() { ...@@ -305,7 +288,7 @@ void main() {
), ),
), ),
); );
_ensureTooltipVisible(key); tooltipKey.currentState?.ensureTooltipVisible();
await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0) await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0)
// we try to put it here but it doesn't fit: // we try to put it here but it doesn't fit:
...@@ -338,7 +321,7 @@ void main() { ...@@ -338,7 +321,7 @@ void main() {
}); });
testWidgets('Does tooltip end up in the right place - center prefer below fits', (WidgetTester tester) async { testWidgets('Does tooltip end up in the right place - center prefer below fits', (WidgetTester tester) async {
final GlobalKey key = GlobalKey(); final GlobalKey<TooltipState> tooltipKey = GlobalKey<TooltipState>();
await tester.pumpWidget( await tester.pumpWidget(
Directionality( Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
...@@ -352,7 +335,7 @@ void main() { ...@@ -352,7 +335,7 @@ void main() {
left: 400.0, left: 400.0,
top: 300.0, top: 300.0,
child: Tooltip( child: Tooltip(
key: key, key: tooltipKey,
message: tooltipText, message: tooltipText,
height: 190.0, height: 190.0,
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
...@@ -372,7 +355,7 @@ void main() { ...@@ -372,7 +355,7 @@ void main() {
), ),
), ),
); );
_ensureTooltipVisible(key); tooltipKey.currentState?.ensureTooltipVisible();
await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0) await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0)
/********************* 800x600 screen /********************* 800x600 screen
...@@ -393,7 +376,7 @@ void main() { ...@@ -393,7 +376,7 @@ void main() {
}); });
testWidgets('Does tooltip end up in the right place - way off to the right', (WidgetTester tester) async { testWidgets('Does tooltip end up in the right place - way off to the right', (WidgetTester tester) async {
final GlobalKey key = GlobalKey(); final GlobalKey<TooltipState> tooltipKey = GlobalKey<TooltipState>();
await tester.pumpWidget( await tester.pumpWidget(
Directionality( Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
...@@ -407,7 +390,7 @@ void main() { ...@@ -407,7 +390,7 @@ void main() {
left: 1600.0, left: 1600.0,
top: 300.0, top: 300.0,
child: Tooltip( child: Tooltip(
key: key, key: tooltipKey,
message: tooltipText, message: tooltipText,
height: 10.0, height: 10.0,
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
...@@ -427,7 +410,7 @@ void main() { ...@@ -427,7 +410,7 @@ void main() {
), ),
), ),
); );
_ensureTooltipVisible(key); tooltipKey.currentState?.ensureTooltipVisible();
await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0) await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0)
/********************* 800x600 screen /********************* 800x600 screen
...@@ -450,7 +433,7 @@ void main() { ...@@ -450,7 +433,7 @@ void main() {
}); });
testWidgets('Does tooltip end up in the right place - near the edge', (WidgetTester tester) async { testWidgets('Does tooltip end up in the right place - near the edge', (WidgetTester tester) async {
final GlobalKey key = GlobalKey(); final GlobalKey<TooltipState> tooltipKey = GlobalKey<TooltipState>();
await tester.pumpWidget( await tester.pumpWidget(
Directionality( Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
...@@ -464,7 +447,7 @@ void main() { ...@@ -464,7 +447,7 @@ void main() {
left: 780.0, left: 780.0,
top: 300.0, top: 300.0,
child: Tooltip( child: Tooltip(
key: key, key: tooltipKey,
message: tooltipText, message: tooltipText,
height: 10.0, height: 10.0,
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
...@@ -484,7 +467,7 @@ void main() { ...@@ -484,7 +467,7 @@ void main() {
), ),
), ),
); );
_ensureTooltipVisible(key); tooltipKey.currentState?.ensureTooltipVisible();
await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0) await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0)
/********************* 800x600 screen /********************* 800x600 screen
...@@ -508,7 +491,7 @@ void main() { ...@@ -508,7 +491,7 @@ void main() {
testWidgets('Custom tooltip margin', (WidgetTester tester) async { testWidgets('Custom tooltip margin', (WidgetTester tester) async {
const double customMarginValue = 10.0; const double customMarginValue = 10.0;
final GlobalKey key = GlobalKey(); final GlobalKey<TooltipState> tooltipKey = GlobalKey<TooltipState>();
await tester.pumpWidget( await tester.pumpWidget(
Directionality( Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
...@@ -517,7 +500,7 @@ void main() { ...@@ -517,7 +500,7 @@ void main() {
OverlayEntry( OverlayEntry(
builder: (BuildContext context) { builder: (BuildContext context) {
return Tooltip( return Tooltip(
key: key, key: tooltipKey,
message: tooltipText, message: tooltipText,
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
margin: const EdgeInsets.all(customMarginValue), margin: const EdgeInsets.all(customMarginValue),
...@@ -532,7 +515,7 @@ void main() { ...@@ -532,7 +515,7 @@ void main() {
), ),
), ),
); );
_ensureTooltipVisible(key); tooltipKey.currentState?.ensureTooltipVisible();
await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0) await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0)
final Offset topLeftTipInGlobal = tester.getTopLeft( final Offset topLeftTipInGlobal = tester.getTopLeft(
...@@ -565,10 +548,10 @@ void main() { ...@@ -565,10 +548,10 @@ void main() {
}); });
testWidgets('Default tooltip message textStyle - light', (WidgetTester tester) async { testWidgets('Default tooltip message textStyle - light', (WidgetTester tester) async {
final GlobalKey key = GlobalKey(); final GlobalKey<TooltipState> tooltipKey = GlobalKey<TooltipState>();
await tester.pumpWidget(MaterialApp( await tester.pumpWidget(MaterialApp(
home: Tooltip( home: Tooltip(
key: key, key: tooltipKey,
message: tooltipText, message: tooltipText,
child: Container( child: Container(
width: 100.0, width: 100.0,
...@@ -577,7 +560,7 @@ void main() { ...@@ -577,7 +560,7 @@ void main() {
), ),
), ),
)); ));
_ensureTooltipVisible(key); tooltipKey.currentState?.ensureTooltipVisible();
await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0) await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0)
final TextStyle textStyle = tester.widget<Text>(find.text(tooltipText)).style!; final TextStyle textStyle = tester.widget<Text>(find.text(tooltipText)).style!;
...@@ -588,13 +571,13 @@ void main() { ...@@ -588,13 +571,13 @@ void main() {
}); });
testWidgets('Default tooltip message textStyle - dark', (WidgetTester tester) async { testWidgets('Default tooltip message textStyle - dark', (WidgetTester tester) async {
final GlobalKey key = GlobalKey(); final GlobalKey<TooltipState> tooltipKey = GlobalKey<TooltipState>();
await tester.pumpWidget(MaterialApp( await tester.pumpWidget(MaterialApp(
theme: ThemeData( theme: ThemeData(
brightness: Brightness.dark, brightness: Brightness.dark,
), ),
home: Tooltip( home: Tooltip(
key: key, key: tooltipKey,
message: tooltipText, message: tooltipText,
child: Container( child: Container(
width: 100.0, width: 100.0,
...@@ -603,7 +586,7 @@ void main() { ...@@ -603,7 +586,7 @@ void main() {
), ),
), ),
)); ));
_ensureTooltipVisible(key); tooltipKey.currentState?.ensureTooltipVisible();
await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0) await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0)
final TextStyle textStyle = tester.widget<Text>(find.text(tooltipText)).style!; final TextStyle textStyle = tester.widget<Text>(find.text(tooltipText)).style!;
...@@ -614,10 +597,10 @@ void main() { ...@@ -614,10 +597,10 @@ void main() {
}); });
testWidgets('Custom tooltip message textStyle', (WidgetTester tester) async { testWidgets('Custom tooltip message textStyle', (WidgetTester tester) async {
final GlobalKey key = GlobalKey(); final GlobalKey<TooltipState> tooltipKey = GlobalKey<TooltipState>();
await tester.pumpWidget(MaterialApp( await tester.pumpWidget(MaterialApp(
home: Tooltip( home: Tooltip(
key: key, key: tooltipKey,
textStyle: const TextStyle( textStyle: const TextStyle(
color: Colors.orange, color: Colors.orange,
decoration: TextDecoration.underline, decoration: TextDecoration.underline,
...@@ -630,7 +613,7 @@ void main() { ...@@ -630,7 +613,7 @@ void main() {
), ),
), ),
)); ));
_ensureTooltipVisible(key); tooltipKey.currentState?.ensureTooltipVisible();
await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0) await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0)
final TextStyle textStyle = tester.widget<Text>(find.text(tooltipText)).style!; final TextStyle textStyle = tester.widget<Text>(find.text(tooltipText)).style!;
...@@ -676,10 +659,10 @@ void main() { ...@@ -676,10 +659,10 @@ void main() {
// A Material widget is needed as an ancestor of the Text widget. // A Material widget is needed as an ancestor of the Text widget.
// It is invalid to have text in a Material application that // It is invalid to have text in a Material application that
// does not have a Material ancestor. // does not have a Material ancestor.
final GlobalKey key = GlobalKey(); final GlobalKey<TooltipState> tooltipKey = GlobalKey<TooltipState>();
await tester.pumpWidget(MaterialApp( await tester.pumpWidget(MaterialApp(
home: Tooltip( home: Tooltip(
key: key, key: tooltipKey,
message: tooltipText, message: tooltipText,
child: Container( child: Container(
width: 100.0, width: 100.0,
...@@ -688,7 +671,7 @@ void main() { ...@@ -688,7 +671,7 @@ void main() {
), ),
), ),
)); ));
_ensureTooltipVisible(key); tooltipKey.currentState?.ensureTooltipVisible();
await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0) await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0)
final TextStyle textStyle = tester.widget<DefaultTextStyle>( final TextStyle textStyle = tester.widget<DefaultTextStyle>(
...@@ -706,7 +689,7 @@ void main() { ...@@ -706,7 +689,7 @@ void main() {
}); });
testWidgets('Does tooltip end up with the right default size, shape, and color', (WidgetTester tester) async { testWidgets('Does tooltip end up with the right default size, shape, and color', (WidgetTester tester) async {
final GlobalKey key = GlobalKey(); final GlobalKey<TooltipState> tooltipKey = GlobalKey<TooltipState>();
await tester.pumpWidget( await tester.pumpWidget(
Directionality( Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
...@@ -715,7 +698,7 @@ void main() { ...@@ -715,7 +698,7 @@ void main() {
OverlayEntry( OverlayEntry(
builder: (BuildContext context) { builder: (BuildContext context) {
return Tooltip( return Tooltip(
key: key, key: tooltipKey,
message: tooltipText, message: tooltipText,
child: const SizedBox( child: const SizedBox(
width: 0.0, width: 0.0,
...@@ -728,7 +711,7 @@ void main() { ...@@ -728,7 +711,7 @@ void main() {
), ),
), ),
); );
_ensureTooltipVisible(key); tooltipKey.currentState?.ensureTooltipVisible();
await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0) await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0)
final RenderBox tip = tester.renderObject( final RenderBox tip = tester.renderObject(
...@@ -744,11 +727,11 @@ void main() { ...@@ -744,11 +727,11 @@ void main() {
testWidgets('Tooltip default size, shape, and color test for Desktop', (WidgetTester tester) async { testWidgets('Tooltip default size, shape, and color test for Desktop', (WidgetTester tester) async {
// Regressing test for https://github.com/flutter/flutter/issues/68601 // Regressing test for https://github.com/flutter/flutter/issues/68601
final GlobalKey key = GlobalKey(); final GlobalKey<TooltipState> tooltipKey = GlobalKey<TooltipState>();
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
home: Tooltip( home: Tooltip(
key: key, key: tooltipKey,
message: tooltipText, message: tooltipText,
child: const SizedBox( child: const SizedBox(
width: 0.0, width: 0.0,
...@@ -757,8 +740,7 @@ void main() { ...@@ -757,8 +740,7 @@ void main() {
), ),
), ),
); );
// ignore: avoid_dynamic_calls tooltipKey.currentState?.ensureTooltipVisible();
(key.currentState as dynamic).ensureTooltipVisible();
await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0) await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0)
final RenderParagraph tooltipRenderParagraph = tester.renderObject<RenderParagraph>(find.text(tooltipText)); final RenderParagraph tooltipRenderParagraph = tester.renderObject<RenderParagraph>(find.text(tooltipText));
...@@ -776,7 +758,7 @@ void main() { ...@@ -776,7 +758,7 @@ void main() {
}, variant: const TargetPlatformVariant(<TargetPlatform>{TargetPlatform.macOS, TargetPlatform.linux, TargetPlatform.windows})); }, variant: const TargetPlatformVariant(<TargetPlatform>{TargetPlatform.macOS, TargetPlatform.linux, TargetPlatform.windows}));
testWidgets('Can tooltip decoration be customized', (WidgetTester tester) async { testWidgets('Can tooltip decoration be customized', (WidgetTester tester) async {
final GlobalKey key = GlobalKey(); final GlobalKey<TooltipState> tooltipKey = GlobalKey<TooltipState>();
const Decoration customDecoration = ShapeDecoration( const Decoration customDecoration = ShapeDecoration(
shape: StadiumBorder(), shape: StadiumBorder(),
color: Color(0x80800000), color: Color(0x80800000),
...@@ -789,7 +771,7 @@ void main() { ...@@ -789,7 +771,7 @@ void main() {
OverlayEntry( OverlayEntry(
builder: (BuildContext context) { builder: (BuildContext context) {
return Tooltip( return Tooltip(
key: key, key: tooltipKey,
decoration: customDecoration, decoration: customDecoration,
message: tooltipText, message: tooltipText,
child: const SizedBox( child: const SizedBox(
...@@ -803,7 +785,7 @@ void main() { ...@@ -803,7 +785,7 @@ void main() {
), ),
), ),
); );
_ensureTooltipVisible(key); tooltipKey.currentState?.ensureTooltipVisible();
await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0) await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0)
final RenderBox tip = tester.renderObject( final RenderBox tip = tester.renderObject(
...@@ -1248,8 +1230,8 @@ void main() { ...@@ -1248,8 +1230,8 @@ void main() {
testWidgets('Does tooltip contribute semantics', (WidgetTester tester) async { testWidgets('Does tooltip contribute semantics', (WidgetTester tester) async {
final SemanticsTester semantics = SemanticsTester(tester); final SemanticsTester semantics = SemanticsTester(tester);
final GlobalKey<TooltipState> tooltipKey = GlobalKey<TooltipState>();
final GlobalKey key = GlobalKey();
await tester.pumpWidget( await tester.pumpWidget(
Directionality( Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
...@@ -1263,7 +1245,7 @@ void main() { ...@@ -1263,7 +1245,7 @@ void main() {
left: 780.0, left: 780.0,
top: 300.0, top: 300.0,
child: Tooltip( child: Tooltip(
key: key, key: tooltipKey,
message: tooltipText, message: tooltipText,
child: const SizedBox(width: 10.0, height: 10.0), child: const SizedBox(width: 10.0, height: 10.0),
), ),
...@@ -1290,7 +1272,7 @@ void main() { ...@@ -1290,7 +1272,7 @@ void main() {
expect(semantics, hasSemantics(expected, ignoreTransform: true, ignoreRect: true)); expect(semantics, hasSemantics(expected, ignoreTransform: true, ignoreRect: true));
// This triggers a rebuild of the semantics because the tree changes. // This triggers a rebuild of the semantics because the tree changes.
_ensureTooltipVisible(key); tooltipKey.currentState?.ensureTooltipVisible();
await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0) await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0)
...@@ -1376,13 +1358,13 @@ void main() { ...@@ -1376,13 +1358,13 @@ void main() {
}); });
testWidgets('Tooltip text displays with richMessage', (WidgetTester tester) async { testWidgets('Tooltip text displays with richMessage', (WidgetTester tester) async {
final GlobalKey key = GlobalKey(); final GlobalKey<TooltipState> tooltipKey = GlobalKey<TooltipState>();
const String textSpan1Text = 'I am a rich tooltip message. '; const String textSpan1Text = 'I am a rich tooltip message. ';
const String textSpan2Text = 'I am another span of a rich tooltip message'; const String textSpan2Text = 'I am another span of a rich tooltip message';
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
home: Tooltip( home: Tooltip(
key: key, key: tooltipKey,
richMessage: const TextSpan( richMessage: const TextSpan(
text: textSpan1Text, text: textSpan1Text,
children: <InlineSpan>[ children: <InlineSpan>[
...@@ -1399,7 +1381,7 @@ void main() { ...@@ -1399,7 +1381,7 @@ void main() {
), ),
), ),
); );
_ensureTooltipVisible(key); tooltipKey.currentState?.ensureTooltipVisible();
await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0) await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0)
final RichText richText = tester.widget<RichText>(find.byType(RichText)); final RichText richText = tester.widget<RichText>(find.byType(RichText));
......
...@@ -9,23 +9,6 @@ import 'package:flutter/material.dart'; ...@@ -9,23 +9,6 @@ import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter_test/flutter_test.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'; const String tooltipText = 'TIP';
void main() { void main() {
...@@ -162,13 +145,13 @@ void main() { ...@@ -162,13 +145,13 @@ void main() {
}); });
testWidgets('Tooltip does not trigger manually when in TooltipVisibility with visible = false', (WidgetTester tester) async { testWidgets('Tooltip does not trigger manually when in TooltipVisibility with visible = false', (WidgetTester tester) async {
final GlobalKey key = GlobalKey(); final GlobalKey<TooltipState> tooltipKey = GlobalKey<TooltipState>();
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
home: TooltipVisibility( home: TooltipVisibility(
visible: false, visible: false,
child: Tooltip( child: Tooltip(
key: key, key: tooltipKey,
message: tooltipText, message: tooltipText,
child: const SizedBox(width: 100.0, height: 100.0), child: const SizedBox(width: 100.0, height: 100.0),
), ),
...@@ -176,19 +159,19 @@ void main() { ...@@ -176,19 +159,19 @@ void main() {
), ),
); );
_ensureTooltipVisible(key); tooltipKey.currentState?.ensureTooltipVisible();
await tester.pump(); await tester.pump();
expect(find.text(tooltipText), findsNothing); expect(find.text(tooltipText), findsNothing);
}); });
testWidgets('Tooltip triggers manually when in TooltipVisibility with visible = true', (WidgetTester tester) async { testWidgets('Tooltip triggers manually when in TooltipVisibility with visible = true', (WidgetTester tester) async {
final GlobalKey key = GlobalKey(); final GlobalKey<TooltipState> tooltipKey = GlobalKey<TooltipState>();
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
home: TooltipVisibility( home: TooltipVisibility(
visible: true, visible: true,
child: Tooltip( child: Tooltip(
key: key, key: tooltipKey,
message: tooltipText, message: tooltipText,
child: const SizedBox(width: 100.0, height: 100.0), child: const SizedBox(width: 100.0, height: 100.0),
), ),
...@@ -196,7 +179,7 @@ void main() { ...@@ -196,7 +179,7 @@ void main() {
), ),
); );
_ensureTooltipVisible(key); tooltipKey.currentState?.ensureTooltipVisible();
await tester.pump(); await tester.pump();
expect(find.text(tooltipText), findsOneWidget); expect(find.text(tooltipText), findsOneWidget);
}); });
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment