Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
93de096e
Unverified
Commit
93de096e
authored
Jul 27, 2021
by
Matan Shukry
Committed by
GitHub
Jul 27, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add TooltipTriggerMode and provideTriggerFeedback to allow users to c… (#84434)
parent
cc03623c
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
226 additions
and
9 deletions
+226
-9
tooltip.dart
packages/flutter/lib/src/material/tooltip.dart
+43
-8
tooltip_theme.dart
packages/flutter/lib/src/material/tooltip_theme.dart
+52
-1
tooltip_test.dart
packages/flutter/test/material/tooltip_test.dart
+75
-0
tooltip_theme_test.dart
packages/flutter/test/material/tooltip_theme_test.dart
+56
-0
No files found.
packages/flutter/lib/src/material/tooltip.dart
View file @
93de096e
...
...
@@ -112,6 +112,8 @@ class Tooltip extends StatefulWidget {
this
.
waitDuration
,
this
.
showDuration
,
this
.
child
,
this
.
triggerMode
,
this
.
enableFeedback
,
})
:
assert
(
message
!=
null
),
super
(
key:
key
);
...
...
@@ -201,6 +203,25 @@ class Tooltip extends StatefulWidget {
/// pointer exits the widget.
final
Duration
?
showDuration
;
/// The [TooltipTriggerMode] that will show the tooltip.
///
/// If this property is null, then [TooltipThemeData.triggerMode] is used.
/// If [TooltipThemeData.triggerMode] is also null, the default mode is
/// [TooltipTriggerMode.longPress].
final
TooltipTriggerMode
?
triggerMode
;
/// Whether the tooltip should provide acoustic and/or haptic feedback.
///
/// For example, on Android a tap will produce a clicking sound and a
/// long-press will produce a short vibration, when feedback is enabled.
///
/// When null, the default value is true.
///
/// See also:
///
/// * [Feedback], for providing platform-specific feedback to certain actions.
final
bool
?
enableFeedback
;
static
final
Set
<
_TooltipState
>
_openedToolTips
=
<
_TooltipState
>{};
/// Dismiss all of the tooltips that are currently shown on the screen.
...
...
@@ -234,6 +255,8 @@ class Tooltip extends StatefulWidget {
properties
.
add
(
FlagProperty
(
'semantics'
,
value:
excludeFromSemantics
,
ifTrue:
'excluded'
,
showName:
true
,
defaultValue:
null
));
properties
.
add
(
DiagnosticsProperty
<
Duration
>(
'wait duration'
,
waitDuration
,
defaultValue:
null
));
properties
.
add
(
DiagnosticsProperty
<
Duration
>(
'show duration'
,
showDuration
,
defaultValue:
null
));
properties
.
add
(
DiagnosticsProperty
<
TooltipTriggerMode
>(
'triggerMode'
,
triggerMode
,
defaultValue:
null
));
properties
.
add
(
FlagProperty
(
'enableFeedback'
,
value:
enableFeedback
,
ifTrue:
'true'
,
showName:
true
,
defaultValue:
null
));
}
}
...
...
@@ -247,6 +270,8 @@ class _TooltipState extends State<Tooltip> with SingleTickerProviderStateMixin {
static
const
Duration
_defaultHoverShowDuration
=
Duration
(
milliseconds:
100
);
static
const
Duration
_defaultWaitDuration
=
Duration
.
zero
;
static
const
bool
_defaultExcludeFromSemantics
=
false
;
static
const
TooltipTriggerMode
_defaultTriggerMode
=
TooltipTriggerMode
.
longPress
;
static
const
bool
_defaultEnableFeedback
=
true
;
late
double
height
;
late
EdgeInsetsGeometry
padding
;
...
...
@@ -264,7 +289,9 @@ class _TooltipState extends State<Tooltip> with SingleTickerProviderStateMixin {
late
Duration
hoverShowDuration
;
late
Duration
waitDuration
;
late
bool
_mouseIsConnected
;
bool
_longPressActivated
=
false
;
bool
_pressActivated
=
false
;
late
TooltipTriggerMode
triggerMode
;
late
bool
enableFeedback
;
@override
void
initState
()
{
...
...
@@ -346,12 +373,12 @@ class _TooltipState extends State<Tooltip> with SingleTickerProviderStateMixin {
_removeEntry
();
return
;
}
if
(
_
longP
ressActivated
)
{
if
(
_
p
ressActivated
)
{
_hideTimer
??=
Timer
(
showDuration
,
_controller
.
reverse
);
}
else
{
_hideTimer
??=
Timer
(
hoverShowDuration
,
_controller
.
reverse
);
}
_
longP
ressActivated
=
false
;
_
p
ressActivated
=
false
;
}
void
_showTooltip
({
bool
immediately
=
false
})
{
...
...
@@ -463,11 +490,15 @@ class _TooltipState extends State<Tooltip> with SingleTickerProviderStateMixin {
super
.
dispose
();
}
void
_handle
Long
Press
()
{
_
longP
ressActivated
=
true
;
void
_handlePress
()
{
_
p
ressActivated
=
true
;
final
bool
tooltipCreated
=
ensureTooltipVisible
();
if
(
tooltipCreated
)
Feedback
.
forLongPress
(
context
);
if
(
tooltipCreated
&&
enableFeedback
)
{
if
(
triggerMode
==
TooltipTriggerMode
.
longPress
)
Feedback
.
forLongPress
(
context
);
else
Feedback
.
forTap
(
context
);
}
}
@override
...
...
@@ -508,10 +539,14 @@ class _TooltipState extends State<Tooltip> with SingleTickerProviderStateMixin {
waitDuration
=
widget
.
waitDuration
??
tooltipTheme
.
waitDuration
??
_defaultWaitDuration
;
showDuration
=
widget
.
showDuration
??
tooltipTheme
.
showDuration
??
_defaultShowDuration
;
hoverShowDuration
=
widget
.
showDuration
??
tooltipTheme
.
showDuration
??
_defaultHoverShowDuration
;
triggerMode
=
widget
.
triggerMode
??
tooltipTheme
.
triggerMode
??
_defaultTriggerMode
;
enableFeedback
=
widget
.
enableFeedback
??
tooltipTheme
.
enableFeedback
??
_defaultEnableFeedback
;
Widget
result
=
GestureDetector
(
behavior:
HitTestBehavior
.
opaque
,
onLongPress:
_handleLongPress
,
onLongPress:
(
triggerMode
==
TooltipTriggerMode
.
longPress
)
?
_handlePress
:
null
,
onTap:
(
triggerMode
==
TooltipTriggerMode
.
tap
)
?
_handlePress
:
null
,
excludeFromSemantics:
true
,
child:
Semantics
(
label:
excludeFromSemantics
?
null
:
widget
.
message
,
...
...
packages/flutter/lib/src/material/tooltip_theme.dart
View file @
93de096e
...
...
@@ -37,6 +37,8 @@ class TooltipThemeData with Diagnosticable {
this
.
textStyle
,
this
.
waitDuration
,
this
.
showDuration
,
this
.
triggerMode
,
this
.
enableFeedback
,
});
/// The height of [Tooltip.child].
...
...
@@ -84,6 +86,22 @@ class TooltipThemeData with Diagnosticable {
/// The length of time that the tooltip will be shown once it has appeared.
final
Duration
?
showDuration
;
/// The [TooltipTriggerMode] that will show the tooltip.
final
TooltipTriggerMode
?
triggerMode
;
/// Whether the tooltip should provide acoustic and/or haptic feedback.
///
/// For example, on Android a tap will produce a clicking sound and a
/// long-press will produce a short vibration, when feedback is enabled.
///
/// This value is used if [Tooltip.enableFeedback] is null.
/// If this value is null, the default is true.
///
/// See also:
///
/// * [Feedback], for providing platform-specific feedback to certain actions.
final
bool
?
enableFeedback
;
/// Creates a copy of this object but with the given fields replaced with the
/// new values.
TooltipThemeData
copyWith
({
...
...
@@ -97,6 +115,8 @@ class TooltipThemeData with Diagnosticable {
TextStyle
?
textStyle
,
Duration
?
waitDuration
,
Duration
?
showDuration
,
TooltipTriggerMode
?
triggerMode
,
bool
?
enableFeedback
,
})
{
return
TooltipThemeData
(
height:
height
??
this
.
height
,
...
...
@@ -109,6 +129,8 @@ class TooltipThemeData with Diagnosticable {
textStyle:
textStyle
??
this
.
textStyle
,
waitDuration:
waitDuration
??
this
.
waitDuration
,
showDuration:
showDuration
??
this
.
showDuration
,
triggerMode:
triggerMode
??
this
.
triggerMode
,
enableFeedback:
enableFeedback
??
this
.
enableFeedback
,
);
}
...
...
@@ -146,6 +168,8 @@ class TooltipThemeData with Diagnosticable {
textStyle
,
waitDuration
,
showDuration
,
triggerMode
,
enableFeedback
);
}
...
...
@@ -165,7 +189,9 @@ class TooltipThemeData with Diagnosticable {
&&
other
.
decoration
==
decoration
&&
other
.
textStyle
==
textStyle
&&
other
.
waitDuration
==
waitDuration
&&
other
.
showDuration
==
showDuration
;
&&
other
.
showDuration
==
showDuration
&&
other
.
triggerMode
==
triggerMode
&&
other
.
enableFeedback
==
enableFeedback
;
}
@override
...
...
@@ -181,6 +207,8 @@ class TooltipThemeData with Diagnosticable {
properties
.
add
(
DiagnosticsProperty
<
TextStyle
>(
'textStyle'
,
textStyle
,
defaultValue:
null
));
properties
.
add
(
DiagnosticsProperty
<
Duration
>(
'wait duration'
,
waitDuration
,
defaultValue:
null
));
properties
.
add
(
DiagnosticsProperty
<
Duration
>(
'show duration'
,
showDuration
,
defaultValue:
null
));
properties
.
add
(
DiagnosticsProperty
<
TooltipTriggerMode
>(
'triggerMode'
,
triggerMode
,
defaultValue:
null
));
properties
.
add
(
FlagProperty
(
'enableFeedback'
,
value:
enableFeedback
,
ifTrue:
'true'
,
showName:
true
,
defaultValue:
null
));
}
}
...
...
@@ -250,3 +278,26 @@ class TooltipTheme extends InheritedTheme {
@override
bool
updateShouldNotify
(
TooltipTheme
oldWidget
)
=>
data
!=
oldWidget
.
data
;
}
/// The method of interaction that will trigger a tooltip.
/// Used in [Tooltip.triggerMode] and [TooltipThemeData.triggerMode].
enum
TooltipTriggerMode
{
/// Tooltip will only be shown by calling `ensureTooltipVisible`.
manual
,
/// Tooltip will be shown after a long press.
///
/// See also:
///
/// * [GestureDetector.onLongPress], the event that is used for trigger.
/// * [Feedback.forLongPress], the feedback method called when feedback is enabled.
longPress
,
/// Tooltip will be shown after a single tap.
///
/// See also:
///
/// * [GestureDetector.onTap], the event that is used for trigger.
/// * [Feedback.forTap], the feedback method called when feedback is enabled.
tap
,
}
packages/flutter/test/material/tooltip_test.dart
View file @
93de096e
...
...
@@ -1429,6 +1429,8 @@ void main() {
excludeFromSemantics:
true
,
preferBelow:
false
,
verticalOffset:
50.0
,
triggerMode:
TooltipTriggerMode
.
manual
,
enableFeedback:
true
,
).
debugFillProperties
(
builder
);
final
List
<
String
>
description
=
builder
.
properties
...
...
@@ -1445,8 +1447,81 @@ void main() {
'semantics: excluded'
,
'wait duration: 0:00:01.000000'
,
'show duration: 0:00:02.000000'
,
'triggerMode: TooltipTriggerMode.manual'
,
'enableFeedback: true'
,
]);
});
testWidgets
(
'Tooltip triggers on tap when trigger mode is tap'
,
(
WidgetTester
tester
)
async
{
await
setWidgetForTooltipMode
(
tester
,
TooltipTriggerMode
.
tap
);
final
Finder
tooltip
=
find
.
byType
(
Tooltip
);
expect
(
find
.
text
(
tooltipText
),
findsNothing
);
await
testGestureTap
(
tester
,
tooltip
);
expect
(
find
.
text
(
tooltipText
),
findsOneWidget
);
});
testWidgets
(
'Tooltip triggers on long press when mode is long press'
,
(
WidgetTester
tester
)
async
{
await
setWidgetForTooltipMode
(
tester
,
TooltipTriggerMode
.
longPress
);
final
Finder
tooltip
=
find
.
byType
(
Tooltip
);
expect
(
find
.
text
(
tooltipText
),
findsNothing
);
await
testGestureTap
(
tester
,
tooltip
);
expect
(
find
.
text
(
tooltipText
),
findsNothing
);
await
testGestureLongPress
(
tester
,
tooltip
);
expect
(
find
.
text
(
tooltipText
),
findsOneWidget
);
});
testWidgets
(
'Tooltip does not trigger on tap when trigger mode is longPress'
,
(
WidgetTester
tester
)
async
{
await
setWidgetForTooltipMode
(
tester
,
TooltipTriggerMode
.
longPress
);
final
Finder
tooltip
=
find
.
byType
(
Tooltip
);
expect
(
find
.
text
(
tooltipText
),
findsNothing
);
await
testGestureTap
(
tester
,
tooltip
);
expect
(
find
.
text
(
tooltipText
),
findsNothing
);
});
testWidgets
(
'Tooltip does not trigger when trigger mode is manual'
,
(
WidgetTester
tester
)
async
{
await
setWidgetForTooltipMode
(
tester
,
TooltipTriggerMode
.
manual
);
final
Finder
tooltip
=
find
.
byType
(
Tooltip
);
expect
(
find
.
text
(
tooltipText
),
findsNothing
);
await
testGestureTap
(
tester
,
tooltip
);
expect
(
find
.
text
(
tooltipText
),
findsNothing
);
await
testGestureLongPress
(
tester
,
tooltip
);
expect
(
find
.
text
(
tooltipText
),
findsNothing
);
});
}
Future
<
void
>
setWidgetForTooltipMode
(
WidgetTester
tester
,
TooltipTriggerMode
triggerMode
)
async
{
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Tooltip
(
message:
tooltipText
,
triggerMode:
triggerMode
,
child:
const
SizedBox
(
width:
100.0
,
height:
100.0
),
),
),
);
}
Future
<
void
>
testGestureLongPress
(
WidgetTester
tester
,
Finder
tooltip
)
async
{
final
TestGesture
gestureLongPress
=
await
tester
.
startGesture
(
tester
.
getCenter
(
tooltip
));
await
tester
.
pump
();
await
tester
.
pump
(
kLongPressTimeout
);
await
gestureLongPress
.
up
();
await
tester
.
pump
();
}
Future
<
void
>
testGestureTap
(
WidgetTester
tester
,
Finder
tooltip
)
async
{
await
tester
.
tap
(
tooltip
);
await
tester
.
pump
(
const
Duration
(
milliseconds:
10
));
}
SemanticsNode
findDebugSemantics
(
RenderObject
object
)
{
...
...
packages/flutter/test/material/tooltip_theme_test.dart
View file @
93de096e
...
...
@@ -48,6 +48,8 @@ void main() {
expect
(
theme
.
textStyle
,
null
);
expect
(
theme
.
waitDuration
,
null
);
expect
(
theme
.
showDuration
,
null
);
expect
(
theme
.
triggerMode
,
null
);
expect
(
theme
.
enableFeedback
,
null
);
});
testWidgets
(
'Default TooltipThemeData debugFillProperties'
,
(
WidgetTester
tester
)
async
{
...
...
@@ -66,6 +68,8 @@ void main() {
final
DiagnosticPropertiesBuilder
builder
=
DiagnosticPropertiesBuilder
();
const
Duration
wait
=
Duration
(
milliseconds:
100
);
const
Duration
show
=
Duration
(
milliseconds:
200
);
const
TooltipTriggerMode
triggerMode
=
TooltipTriggerMode
.
longPress
;
const
bool
enableFeedback
=
true
;
const
TooltipThemeData
(
height:
15.0
,
padding:
EdgeInsets
.
all
(
20.0
),
...
...
@@ -76,6 +80,8 @@ void main() {
textStyle:
TextStyle
(
decoration:
TextDecoration
.
underline
),
waitDuration:
wait
,
showDuration:
show
,
triggerMode:
triggerMode
,
enableFeedback:
enableFeedback
,
).
debugFillProperties
(
builder
);
final
List
<
String
>
description
=
builder
.
properties
...
...
@@ -93,6 +99,8 @@ void main() {
'textStyle: TextStyle(inherit: true, decoration: TextDecoration.underline)'
,
'wait duration:
${wait.toString()}
'
,
'show duration:
${show.toString()}
'
,
'triggerMode:
$triggerMode
'
,
'enableFeedback: true'
,
]);
});
...
...
@@ -985,6 +993,54 @@ void main() {
expect
(
find
.
text
(
tooltipText
),
findsNothing
);
});
testWidgets
(
'Tooltip triggerMode - ThemeData.triggerMode'
,
(
WidgetTester
tester
)
async
{
const
TooltipTriggerMode
triggerMode
=
TooltipTriggerMode
.
tap
;
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Theme
(
data:
ThemeData
(
tooltipTheme:
const
TooltipThemeData
(
triggerMode:
triggerMode
),
),
child:
const
Center
(
child:
Tooltip
(
message:
tooltipText
,
child:
SizedBox
(
width:
100.0
,
height:
100.0
),
),
),
),
),
);
final
Finder
tooltip
=
find
.
byType
(
Tooltip
);
final
TestGesture
gesture
=
await
tester
.
startGesture
(
tester
.
getCenter
(
tooltip
));
await
gesture
.
up
();
await
tester
.
pump
();
expect
(
find
.
text
(
tooltipText
),
findsOneWidget
);
// Tooltip should show immediately after tap
});
testWidgets
(
'Tooltip triggerMode - TooltipTheme'
,
(
WidgetTester
tester
)
async
{
const
TooltipTriggerMode
triggerMode
=
TooltipTriggerMode
.
tap
;
await
tester
.
pumpWidget
(
const
MaterialApp
(
home:
TooltipTheme
(
data:
TooltipThemeData
(
triggerMode:
triggerMode
),
child:
Center
(
child:
Tooltip
(
message:
tooltipText
,
child:
SizedBox
(
width:
100.0
,
height:
100.0
),
),
),
),
),
);
final
Finder
tooltip
=
find
.
byType
(
Tooltip
);
final
TestGesture
gesture
=
await
tester
.
startGesture
(
tester
.
getCenter
(
tooltip
));
await
gesture
.
up
();
await
tester
.
pump
();
expect
(
find
.
text
(
tooltipText
),
findsOneWidget
);
// Tooltip should show immediately after tap
});
testWidgets
(
'Semantics included by default - ThemeData.tooltipTheme'
,
(
WidgetTester
tester
)
async
{
final
SemanticsTester
semantics
=
SemanticsTester
(
tester
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment