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
94b9fa41
Unverified
Commit
94b9fa41
authored
Nov 22, 2022
by
Taha Tesser
Committed by
GitHub
Nov 22, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Provide an option to update `Focus's semantics under `FocusableActionDetector` (#115833)
Update test Update comments
parent
b9caef58
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
126 additions
and
0 deletions
+126
-0
actions.dart
packages/flutter/lib/src/widgets/actions.dart
+7
-0
actions_test.dart
packages/flutter/test/widgets/actions_test.dart
+119
-0
No files found.
packages/flutter/lib/src/widgets/actions.dart
View file @
94b9fa41
...
@@ -1077,6 +1077,7 @@ class FocusableActionDetector extends StatefulWidget {
...
@@ -1077,6 +1077,7 @@ class FocusableActionDetector extends StatefulWidget {
this
.
onShowHoverHighlight
,
this
.
onShowHoverHighlight
,
this
.
onFocusChange
,
this
.
onFocusChange
,
this
.
mouseCursor
=
MouseCursor
.
defer
,
this
.
mouseCursor
=
MouseCursor
.
defer
,
this
.
includeFocusSemantics
=
true
,
required
this
.
child
,
required
this
.
child
,
})
:
assert
(
enabled
!=
null
),
})
:
assert
(
enabled
!=
null
),
assert
(
autofocus
!=
null
),
assert
(
autofocus
!=
null
),
...
@@ -1133,6 +1134,11 @@ class FocusableActionDetector extends StatefulWidget {
...
@@ -1133,6 +1134,11 @@ class FocusableActionDetector extends StatefulWidget {
/// cursor to the next region behind it in hit-test order.
/// cursor to the next region behind it in hit-test order.
final
MouseCursor
mouseCursor
;
final
MouseCursor
mouseCursor
;
/// Whether to include semantics from [Focus].
///
/// Defaults to true.
final
bool
includeFocusSemantics
;
/// The child widget for this [FocusableActionDetector] widget.
/// The child widget for this [FocusableActionDetector] widget.
///
///
/// {@macro flutter.widgets.ProxyWidget.child}
/// {@macro flutter.widgets.ProxyWidget.child}
...
@@ -1293,6 +1299,7 @@ class _FocusableActionDetectorState extends State<FocusableActionDetector> {
...
@@ -1293,6 +1299,7 @@ class _FocusableActionDetectorState extends State<FocusableActionDetector> {
descendantsAreTraversable:
widget
.
descendantsAreTraversable
,
descendantsAreTraversable:
widget
.
descendantsAreTraversable
,
canRequestFocus:
_canRequestFocus
,
canRequestFocus:
_canRequestFocus
,
onFocusChange:
_handleFocusChange
,
onFocusChange:
_handleFocusChange
,
includeSemantics:
widget
.
includeFocusSemantics
,
child:
widget
.
child
,
child:
widget
.
child
,
),
),
);
);
...
...
packages/flutter/test/widgets/actions_test.dart
View file @
94b9fa41
...
@@ -28,6 +28,7 @@ void main() {
...
@@ -28,6 +28,7 @@ void main() {
expect
(
invoked
,
isTrue
);
expect
(
invoked
,
isTrue
);
});
});
});
});
group
(
Actions
,
()
{
group
(
Actions
,
()
{
Intent
?
invokedIntent
;
Intent
?
invokedIntent
;
Action
<
Intent
>?
invokedAction
;
Action
<
Intent
>?
invokedAction
;
...
@@ -99,6 +100,7 @@ void main() {
...
@@ -99,6 +100,7 @@ void main() {
expect
(
result
,
isTrue
);
expect
(
result
,
isTrue
);
expect
(
invoked
,
isTrue
);
expect
(
invoked
,
isTrue
);
});
});
testWidgets
(
'maybeInvoke returns null when no action is found'
,
(
WidgetTester
tester
)
async
{
testWidgets
(
'maybeInvoke returns null when no action is found'
,
(
WidgetTester
tester
)
async
{
final
GlobalKey
containerKey
=
GlobalKey
();
final
GlobalKey
containerKey
=
GlobalKey
();
bool
invoked
=
false
;
bool
invoked
=
false
;
...
@@ -125,6 +127,7 @@ void main() {
...
@@ -125,6 +127,7 @@ void main() {
expect
(
result
,
isNull
);
expect
(
result
,
isNull
);
expect
(
invoked
,
isFalse
);
expect
(
invoked
,
isFalse
);
});
});
testWidgets
(
'invoke throws when no action is found'
,
(
WidgetTester
tester
)
async
{
testWidgets
(
'invoke throws when no action is found'
,
(
WidgetTester
tester
)
async
{
final
GlobalKey
containerKey
=
GlobalKey
();
final
GlobalKey
containerKey
=
GlobalKey
();
bool
invoked
=
false
;
bool
invoked
=
false
;
...
@@ -151,6 +154,7 @@ void main() {
...
@@ -151,6 +154,7 @@ void main() {
expect
(
result
,
isNull
);
expect
(
result
,
isNull
);
expect
(
invoked
,
isFalse
);
expect
(
invoked
,
isFalse
);
});
});
testWidgets
(
'Actions widget can invoke actions with custom dispatcher'
,
(
WidgetTester
tester
)
async
{
testWidgets
(
'Actions widget can invoke actions with custom dispatcher'
,
(
WidgetTester
tester
)
async
{
final
GlobalKey
containerKey
=
GlobalKey
();
final
GlobalKey
containerKey
=
GlobalKey
();
bool
invoked
=
false
;
bool
invoked
=
false
;
...
@@ -181,6 +185,7 @@ void main() {
...
@@ -181,6 +185,7 @@ void main() {
expect
(
invoked
,
isTrue
);
expect
(
invoked
,
isTrue
);
expect
(
invokedIntent
,
equals
(
intent
));
expect
(
invokedIntent
,
equals
(
intent
));
});
});
testWidgets
(
'Actions can invoke actions in ancestor dispatcher'
,
(
WidgetTester
tester
)
async
{
testWidgets
(
'Actions can invoke actions in ancestor dispatcher'
,
(
WidgetTester
tester
)
async
{
final
GlobalKey
containerKey
=
GlobalKey
();
final
GlobalKey
containerKey
=
GlobalKey
();
bool
invoked
=
false
;
bool
invoked
=
false
;
...
@@ -217,6 +222,7 @@ void main() {
...
@@ -217,6 +222,7 @@ void main() {
expect
(
invokedAction
,
equals
(
testAction
));
expect
(
invokedAction
,
equals
(
testAction
));
expect
(
invokedDispatcher
.
runtimeType
,
equals
(
TestDispatcher1
));
expect
(
invokedDispatcher
.
runtimeType
,
equals
(
TestDispatcher1
));
});
});
testWidgets
(
"Actions can invoke actions in ancestor dispatcher if a lower one isn't specified"
,
(
WidgetTester
tester
)
async
{
testWidgets
(
"Actions can invoke actions in ancestor dispatcher if a lower one isn't specified"
,
(
WidgetTester
tester
)
async
{
final
GlobalKey
containerKey
=
GlobalKey
();
final
GlobalKey
containerKey
=
GlobalKey
();
bool
invoked
=
false
;
bool
invoked
=
false
;
...
@@ -252,6 +258,7 @@ void main() {
...
@@ -252,6 +258,7 @@ void main() {
expect
(
invokedAction
,
equals
(
testAction
));
expect
(
invokedAction
,
equals
(
testAction
));
expect
(
invokedDispatcher
.
runtimeType
,
equals
(
TestDispatcher1
));
expect
(
invokedDispatcher
.
runtimeType
,
equals
(
TestDispatcher1
));
});
});
testWidgets
(
'Actions widget can be found with of'
,
(
WidgetTester
tester
)
async
{
testWidgets
(
'Actions widget can be found with of'
,
(
WidgetTester
tester
)
async
{
final
GlobalKey
containerKey
=
GlobalKey
();
final
GlobalKey
containerKey
=
GlobalKey
();
final
ActionDispatcher
testDispatcher
=
TestDispatcher1
(
postInvoke:
collect
);
final
ActionDispatcher
testDispatcher
=
TestDispatcher1
(
postInvoke:
collect
);
...
@@ -268,6 +275,7 @@ void main() {
...
@@ -268,6 +275,7 @@ void main() {
final
ActionDispatcher
dispatcher
=
Actions
.
of
(
containerKey
.
currentContext
!);
final
ActionDispatcher
dispatcher
=
Actions
.
of
(
containerKey
.
currentContext
!);
expect
(
dispatcher
,
equals
(
testDispatcher
));
expect
(
dispatcher
,
equals
(
testDispatcher
));
});
});
testWidgets
(
'Action can be found with find'
,
(
WidgetTester
tester
)
async
{
testWidgets
(
'Action can be found with find'
,
(
WidgetTester
tester
)
async
{
final
GlobalKey
containerKey
=
GlobalKey
();
final
GlobalKey
containerKey
=
GlobalKey
();
final
ActionDispatcher
testDispatcher
=
TestDispatcher1
(
postInvoke:
collect
);
final
ActionDispatcher
testDispatcher
=
TestDispatcher1
(
postInvoke:
collect
);
...
@@ -314,6 +322,7 @@ void main() {
...
@@ -314,6 +322,7 @@ void main() {
expect
(()
=>
Actions
.
find
<
DoNothingIntent
>(
containerKey
.
currentContext
!),
throwsAssertionError
);
expect
(()
=>
Actions
.
find
<
DoNothingIntent
>(
containerKey
.
currentContext
!),
throwsAssertionError
);
expect
(
Actions
.
maybeFind
<
DoNothingIntent
>(
containerKey
.
currentContext
!),
isNull
);
expect
(
Actions
.
maybeFind
<
DoNothingIntent
>(
containerKey
.
currentContext
!),
isNull
);
});
});
testWidgets
(
'FocusableActionDetector keeps track of focus and hover even when disabled.'
,
(
WidgetTester
tester
)
async
{
testWidgets
(
'FocusableActionDetector keeps track of focus and hover even when disabled.'
,
(
WidgetTester
tester
)
async
{
FocusManager
.
instance
.
highlightStrategy
=
FocusHighlightStrategy
.
alwaysTraditional
;
FocusManager
.
instance
.
highlightStrategy
=
FocusHighlightStrategy
.
alwaysTraditional
;
final
GlobalKey
containerKey
=
GlobalKey
();
final
GlobalKey
containerKey
=
GlobalKey
();
...
@@ -383,6 +392,7 @@ void main() {
...
@@ -383,6 +392,7 @@ void main() {
expect
(
hovering
,
isFalse
);
expect
(
hovering
,
isFalse
);
expect
(
focusing
,
isFalse
);
expect
(
focusing
,
isFalse
);
});
});
testWidgets
(
'FocusableActionDetector changes mouse cursor when hovered'
,
(
WidgetTester
tester
)
async
{
testWidgets
(
'FocusableActionDetector changes mouse cursor when hovered'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
await
tester
.
pumpWidget
(
MouseRegion
(
MouseRegion
(
...
@@ -415,6 +425,7 @@ void main() {
...
@@ -415,6 +425,7 @@ void main() {
expect
(
RendererBinding
.
instance
.
mouseTracker
.
debugDeviceActiveCursor
(
1
),
SystemMouseCursors
.
forbidden
);
expect
(
RendererBinding
.
instance
.
mouseTracker
.
debugDeviceActiveCursor
(
1
),
SystemMouseCursors
.
forbidden
);
});
});
testWidgets
(
'Actions.invoke returns the value of Action.invoke'
,
(
WidgetTester
tester
)
async
{
testWidgets
(
'Actions.invoke returns the value of Action.invoke'
,
(
WidgetTester
tester
)
async
{
final
GlobalKey
containerKey
=
GlobalKey
();
final
GlobalKey
containerKey
=
GlobalKey
();
final
Object
sentinel
=
Object
();
final
Object
sentinel
=
Object
();
...
@@ -445,6 +456,7 @@ void main() {
...
@@ -445,6 +456,7 @@ void main() {
expect
(
identical
(
result
,
sentinel
),
isTrue
);
expect
(
identical
(
result
,
sentinel
),
isTrue
);
expect
(
invoked
,
isTrue
);
expect
(
invoked
,
isTrue
);
});
});
testWidgets
(
'ContextAction can return null'
,
(
WidgetTester
tester
)
async
{
testWidgets
(
'ContextAction can return null'
,
(
WidgetTester
tester
)
async
{
final
GlobalKey
containerKey
=
GlobalKey
();
final
GlobalKey
containerKey
=
GlobalKey
();
const
TestIntent
intent
=
TestIntent
();
const
TestIntent
intent
=
TestIntent
();
...
@@ -471,6 +483,7 @@ void main() {
...
@@ -471,6 +483,7 @@ void main() {
expect
(
invokedDispatcher
.
runtimeType
,
equals
(
TestDispatcher1
));
expect
(
invokedDispatcher
.
runtimeType
,
equals
(
TestDispatcher1
));
expect
(
testAction
.
capturedContexts
.
single
,
containerKey
.
currentContext
);
expect
(
testAction
.
capturedContexts
.
single
,
containerKey
.
currentContext
);
});
});
testWidgets
(
'Disabled actions stop propagation to an ancestor'
,
(
WidgetTester
tester
)
async
{
testWidgets
(
'Disabled actions stop propagation to an ancestor'
,
(
WidgetTester
tester
)
async
{
final
GlobalKey
containerKey
=
GlobalKey
();
final
GlobalKey
containerKey
=
GlobalKey
();
bool
invoked
=
false
;
bool
invoked
=
false
;
...
@@ -775,6 +788,7 @@ void main() {
...
@@ -775,6 +788,7 @@ void main() {
expect
(
hovering
,
isFalse
);
expect
(
hovering
,
isFalse
);
expect
(
focusing
,
isFalse
);
expect
(
focusing
,
isFalse
);
});
});
testWidgets
(
'FocusableActionDetector shows focus highlight appropriately when focused and disabled'
,
(
WidgetTester
tester
)
async
{
testWidgets
(
'FocusableActionDetector shows focus highlight appropriately when focused and disabled'
,
(
WidgetTester
tester
)
async
{
FocusManager
.
instance
.
highlightStrategy
=
FocusHighlightStrategy
.
alwaysTraditional
;
FocusManager
.
instance
.
highlightStrategy
=
FocusHighlightStrategy
.
alwaysTraditional
;
final
GlobalKey
containerKey
=
GlobalKey
();
final
GlobalKey
containerKey
=
GlobalKey
();
...
@@ -805,6 +819,7 @@ void main() {
...
@@ -805,6 +819,7 @@ void main() {
await
tester
.
pump
();
await
tester
.
pump
();
expect
(
focusing
,
isTrue
);
expect
(
focusing
,
isTrue
);
});
});
testWidgets
(
'FocusableActionDetector can be used without callbacks'
,
(
WidgetTester
tester
)
async
{
testWidgets
(
'FocusableActionDetector can be used without callbacks'
,
(
WidgetTester
tester
)
async
{
FocusManager
.
instance
.
highlightStrategy
=
FocusHighlightStrategy
.
alwaysTraditional
;
FocusManager
.
instance
.
highlightStrategy
=
FocusHighlightStrategy
.
alwaysTraditional
;
final
GlobalKey
containerKey
=
GlobalKey
();
final
GlobalKey
containerKey
=
GlobalKey
();
...
@@ -951,6 +966,110 @@ void main() {
...
@@ -951,6 +966,110 @@ void main() {
expect
(
buttonNode2
.
hasFocus
,
isFalse
);
expect
(
buttonNode2
.
hasFocus
,
isFalse
);
},
},
);
);
testWidgets
(
'FocusableActionDetector can exclude Focus semantics'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
MaterialApp
(
home:
FocusableActionDetector
(
child:
Column
(
children:
<
Widget
>[
TextButton
(
onPressed:
()
{},
child:
const
Text
(
'Button 1'
),
),
TextButton
(
onPressed:
()
{},
child:
const
Text
(
'Button 2'
),
),
],
),
),
),
);
expect
(
tester
.
getSemantics
(
find
.
byType
(
FocusableActionDetector
)),
matchesSemantics
(
scopesRoute:
true
,
children:
<
Matcher
>[
// This semantic is from `Focus` widget under `FocusableActionDetector`.
matchesSemantics
(
isFocusable:
true
,
children:
<
Matcher
>[
matchesSemantics
(
hasTapAction:
true
,
isButton:
true
,
hasEnabledState:
true
,
isEnabled:
true
,
isFocusable:
true
,
label:
'Button 1'
,
textDirection:
TextDirection
.
ltr
,
),
matchesSemantics
(
hasTapAction:
true
,
isButton:
true
,
hasEnabledState:
true
,
isEnabled:
true
,
isFocusable:
true
,
label:
'Button 2'
,
textDirection:
TextDirection
.
ltr
,
),
],
),
],
),
);
// Set `includeFocusSemantics` to false to exclude semantics
// from `Focus` widget under `FocusableActionDetector`.
await
tester
.
pumpWidget
(
MaterialApp
(
home:
FocusableActionDetector
(
includeFocusSemantics:
false
,
child:
Column
(
children:
<
Widget
>[
TextButton
(
onPressed:
()
{},
child:
const
Text
(
'Button 1'
),
),
TextButton
(
onPressed:
()
{},
child:
const
Text
(
'Button 2'
),
),
],
),
),
),
);
// Semantics from the `Focus` widget will be removed.
expect
(
tester
.
getSemantics
(
find
.
byType
(
FocusableActionDetector
)),
matchesSemantics
(
scopesRoute:
true
,
children:
<
Matcher
>[
matchesSemantics
(
hasTapAction:
true
,
isButton:
true
,
hasEnabledState:
true
,
isEnabled:
true
,
isFocusable:
true
,
label:
'Button 1'
,
textDirection:
TextDirection
.
ltr
,
),
matchesSemantics
(
hasTapAction:
true
,
isButton:
true
,
hasEnabledState:
true
,
isEnabled:
true
,
isFocusable:
true
,
label:
'Button 2'
,
textDirection:
TextDirection
.
ltr
,
),
],
),
);
});
});
});
group
(
'Action subclasses'
,
()
{
group
(
'Action subclasses'
,
()
{
...
...
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