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
55c7e6e3
Unverified
Commit
55c7e6e3
authored
Aug 02, 2018
by
Jonah Williams
Committed by
GitHub
Aug 02, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Support customizing standard accessibility action hints on Android. (#19665)
parent
651c5ab3
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
328 additions
and
14 deletions
+328
-14
proxy_box.dart
packages/flutter/lib/src/rendering/proxy_box.dart
+14
-0
semantics.dart
packages/flutter/lib/src/semantics/semantics.dart
+157
-10
basic.dart
packages/flutter/lib/src/widgets/basic.dart
+9
-0
semantics_test.dart
packages/flutter/test/widgets/semantics_test.dart
+45
-0
matchers.dart
packages/flutter_test/lib/src/matchers.dart
+43
-3
matchers_test.dart
packages/flutter_test/test/matchers_test.dart
+60
-1
No files found.
packages/flutter/lib/src/rendering/proxy_box.dart
View file @
55c7e6e3
...
@@ -3207,6 +3207,7 @@ class RenderSemanticsAnnotations extends RenderProxyBox {
...
@@ -3207,6 +3207,7 @@ class RenderSemanticsAnnotations extends RenderProxyBox {
String
increasedValue
,
String
increasedValue
,
String
decreasedValue
,
String
decreasedValue
,
String
hint
,
String
hint
,
SemanticsHintOverrides
hintOverrides
,
TextDirection
textDirection
,
TextDirection
textDirection
,
SemanticsSortKey
sortKey
,
SemanticsSortKey
sortKey
,
VoidCallback
onTap
,
VoidCallback
onTap
,
...
@@ -3252,6 +3253,7 @@ class RenderSemanticsAnnotations extends RenderProxyBox {
...
@@ -3252,6 +3253,7 @@ class RenderSemanticsAnnotations extends RenderProxyBox {
_increasedValue
=
increasedValue
,
_increasedValue
=
increasedValue
,
_decreasedValue
=
decreasedValue
,
_decreasedValue
=
decreasedValue
,
_hint
=
hint
,
_hint
=
hint
,
_hintOverrides
=
hintOverrides
,
_textDirection
=
textDirection
,
_textDirection
=
textDirection
,
_sortKey
=
sortKey
,
_sortKey
=
sortKey
,
_onTap
=
onTap
,
_onTap
=
onTap
,
...
@@ -3548,6 +3550,16 @@ class RenderSemanticsAnnotations extends RenderProxyBox {
...
@@ -3548,6 +3550,16 @@ class RenderSemanticsAnnotations extends RenderProxyBox {
markNeedsSemanticsUpdate
();
markNeedsSemanticsUpdate
();
}
}
/// If non-null, sets the [SemanticsNode.hintOverride] to the given value.
SemanticsHintOverrides
get
hintOverrides
=>
_hintOverrides
;
SemanticsHintOverrides
_hintOverrides
;
set
hintOverrides
(
SemanticsHintOverrides
value
)
{
if
(
_hintOverrides
==
value
)
return
;
_hintOverrides
=
value
;
markNeedsSemanticsUpdate
();
}
/// If non-null, sets the [SemanticsNode.textDirection] semantic to the given value.
/// If non-null, sets the [SemanticsNode.textDirection] semantic to the given value.
///
///
/// This must not be null if [label], [hint], [value], [increasedValue], or
/// This must not be null if [label], [hint], [value], [increasedValue], or
...
@@ -3989,6 +4001,8 @@ class RenderSemanticsAnnotations extends RenderProxyBox {
...
@@ -3989,6 +4001,8 @@ class RenderSemanticsAnnotations extends RenderProxyBox {
config
.
decreasedValue
=
decreasedValue
;
config
.
decreasedValue
=
decreasedValue
;
if
(
hint
!=
null
)
if
(
hint
!=
null
)
config
.
hint
=
hint
;
config
.
hint
=
hint
;
if
(
hintOverrides
!=
null
&&
hintOverrides
.
isNotEmpty
)
config
.
hintOverrides
=
hintOverrides
;
if
(
scopesRoute
!=
null
)
if
(
scopesRoute
!=
null
)
config
.
scopesRoute
=
scopesRoute
;
config
.
scopesRoute
=
scopesRoute
;
if
(
namesRoute
!=
null
)
if
(
namesRoute
!=
null
)
...
...
packages/flutter/lib/src/semantics/semantics.dart
View file @
55c7e6e3
...
@@ -83,7 +83,7 @@ class SemanticsTag {
...
@@ -83,7 +83,7 @@ class SemanticsTag {
/// these are presented in the radial context menu.
/// these are presented in the radial context menu.
///
///
/// Localization and text direction do not automatically apply to the provided
/// Localization and text direction do not automatically apply to the provided
/// label.
/// label
or hint
.
///
///
/// Instances of this class should either be instantiated with const or
/// Instances of this class should either be instantiated with const or
/// new instances cached in static fields.
/// new instances cached in static fields.
...
@@ -98,20 +98,45 @@ class CustomSemanticsAction {
...
@@ -98,20 +98,45 @@ class CustomSemanticsAction {
/// The [label] must not be null or the empty string.
/// The [label] must not be null or the empty string.
const
CustomSemanticsAction
({
@required
this
.
label
})
const
CustomSemanticsAction
({
@required
this
.
label
})
:
assert
(
label
!=
null
),
:
assert
(
label
!=
null
),
assert
(
label
!=
''
);
assert
(
label
!=
''
),
hint
=
null
,
action
=
null
;
/// The user readable name of this custom accessibility action.
/// Creates a new [CustomSemanticsAction] that overrides a standard semantics
/// action.
///
/// The [hint] must not be null or the empty string.
const
CustomSemanticsAction
.
overridingAction
({
@required
this
.
hint
,
@required
this
.
action
})
:
assert
(
hint
!=
null
),
assert
(
hint
!=
''
),
assert
(
action
!=
null
),
label
=
null
;
/// The user readable name of this custom semantics action.
final
String
label
;
final
String
label
;
/// The hint description of this custom semantics action.
final
String
hint
;
/// The standard semantics action this action replaces.
final
SemanticsAction
action
;
@override
@override
int
get
hashCode
=>
label
.
hashCode
;
int
get
hashCode
=>
ui
.
hashValues
(
label
,
hint
,
action
)
;
@override
@override
bool
operator
==(
dynamic
other
)
{
bool
operator
==(
dynamic
other
)
{
if
(
other
.
runtimeType
!=
runtimeType
)
if
(
other
.
runtimeType
!=
runtimeType
)
return
false
;
return
false
;
final
CustomSemanticsAction
typedOther
=
other
;
final
CustomSemanticsAction
typedOther
=
other
;
return
typedOther
.
label
==
label
;
return
typedOther
.
label
==
label
&&
typedOther
.
hint
==
hint
&&
typedOther
.
action
==
action
;
}
@override
String
toString
()
{
return
'CustomSemanticsAction(
${_ids[this]}
, label:
$label
, hint:
$hint
, action:
$action
)'
;
}
}
// Logic to assign a unique id to each custom action without requiring
// Logic to assign a unique id to each custom action without requiring
...
@@ -121,7 +146,6 @@ class CustomSemanticsAction {
...
@@ -121,7 +146,6 @@ class CustomSemanticsAction {
static
final
Map
<
CustomSemanticsAction
,
int
>
_ids
=
<
CustomSemanticsAction
,
int
>{};
static
final
Map
<
CustomSemanticsAction
,
int
>
_ids
=
<
CustomSemanticsAction
,
int
>{};
/// Get the identifier for a given `action`.
/// Get the identifier for a given `action`.
@visibleForTesting
static
int
getIdentifier
(
CustomSemanticsAction
action
)
{
static
int
getIdentifier
(
CustomSemanticsAction
action
)
{
int
result
=
_ids
[
action
];
int
result
=
_ids
[
action
];
if
(
result
==
null
)
{
if
(
result
==
null
)
{
...
@@ -133,7 +157,6 @@ class CustomSemanticsAction {
...
@@ -133,7 +157,6 @@ class CustomSemanticsAction {
}
}
/// Get the `action` for a given identifier.
/// Get the `action` for a given identifier.
@visibleForTesting
static
CustomSemanticsAction
getAction
(
int
id
)
{
static
CustomSemanticsAction
getAction
(
int
id
)
{
return
_actions
[
id
];
return
_actions
[
id
];
}
}
...
@@ -271,7 +294,8 @@ class SemanticsData extends Diagnosticable {
...
@@ -271,7 +294,8 @@ class SemanticsData extends Diagnosticable {
/// parent).
/// parent).
final
Matrix4
transform
;
final
Matrix4
transform
;
/// The identifiers for the custom semantics action defined for this node.
/// The identifiers for the custom semantics actions and standard action
/// overrides for this node.
///
///
/// The list must be sorted in increasing order.
/// The list must be sorted in increasing order.
///
///
...
@@ -407,6 +431,64 @@ class _SemanticsDiagnosticableNode extends DiagnosticableNode<SemanticsNode> {
...
@@ -407,6 +431,64 @@ class _SemanticsDiagnosticableNode extends DiagnosticableNode<SemanticsNode> {
}
}
}
}
/// Provides hint values which override the default hints on supported
/// platforms.
///
/// On iOS, these values are always ignored.
@immutable
class
SemanticsHintOverrides
extends
DiagnosticableTree
{
/// Creates a semantics hint overrides.
const
SemanticsHintOverrides
({
this
.
onTapHint
,
this
.
onLongPressHint
,
})
:
assert
(
onTapHint
!=
''
),
assert
(
onLongPressHint
!=
''
);
/// The hint text for a tap action.
///
/// If null, the standard hint is used instead.
///
/// The hint should describe what happens when a tap occurs, not the
/// manner in which a tap is accomplished.
///
/// Bad: 'Double tap to show movies'.
/// Good: 'show movies'.
final
String
onTapHint
;
/// The hint text for a long press action.
///
/// If null, the standard hint is used instead.
///
/// The hint should describe what happens when a long press occurs, not
/// the manner in which the long press is accomplished.
///
/// Bad: 'Double tap and hold to show tooltip'.
/// Good: 'show tooltip'.
final
String
onLongPressHint
;
/// Whether there are any non-null hint values.
bool
get
isNotEmpty
=>
onTapHint
!=
null
||
onLongPressHint
!=
null
;
@override
int
get
hashCode
=>
ui
.
hashValues
(
onTapHint
,
onLongPressHint
);
@override
bool
operator
==(
dynamic
other
)
{
if
(
other
.
runtimeType
!=
runtimeType
)
return
false
;
final
SemanticsHintOverrides
typedOther
=
other
;
return
typedOther
.
onTapHint
==
onTapHint
&&
typedOther
.
onLongPressHint
==
onLongPressHint
;
}
@override
void
debugFillProperties
(
DiagnosticPropertiesBuilder
properties
)
{
super
.
debugFillProperties
(
properties
);
properties
.
add
(
new
StringProperty
(
'onTapHint'
,
onTapHint
,
defaultValue:
null
));
properties
.
add
(
new
StringProperty
(
'onLongPressHint'
,
onLongPressHint
,
defaultValue:
null
));
}
}
/// Contains properties used by assistive technologies to make the application
/// Contains properties used by assistive technologies to make the application
/// more accessible.
/// more accessible.
///
///
...
@@ -436,6 +518,7 @@ class SemanticsProperties extends DiagnosticableTree {
...
@@ -436,6 +518,7 @@ class SemanticsProperties extends DiagnosticableTree {
this
.
increasedValue
,
this
.
increasedValue
,
this
.
decreasedValue
,
this
.
decreasedValue
,
this
.
hint
,
this
.
hint
,
this
.
hintOverrides
,
this
.
textDirection
,
this
.
textDirection
,
this
.
sortKey
,
this
.
sortKey
,
this
.
onTap
,
this
.
onTap
,
...
@@ -656,6 +739,16 @@ class SemanticsProperties extends DiagnosticableTree {
...
@@ -656,6 +739,16 @@ class SemanticsProperties extends DiagnosticableTree {
/// in TalkBack and VoiceOver.
/// in TalkBack and VoiceOver.
final
String
hint
;
final
String
hint
;
/// Provides hint values which override the default hints on supported
/// platforms.
///
/// On Android, If no hint overrides are used then default [hint] will be
/// combined with the [label]. Otherwise, the [hint] will be ignored as long
/// as there as at least one non-null hint override.
///
/// On iOS, these are always ignored and the default [hint] is used instead.
final
SemanticsHintOverrides
hintOverrides
;
/// The reading direction of the [label], [value], [hint], [increasedValue],
/// The reading direction of the [label], [value], [hint], [increasedValue],
/// and [decreasedValue].
/// and [decreasedValue].
///
///
...
@@ -889,6 +982,7 @@ class SemanticsProperties extends DiagnosticableTree {
...
@@ -889,6 +982,7 @@ class SemanticsProperties extends DiagnosticableTree {
properties
.
add
(
new
StringProperty
(
'hint'
,
hint
));
properties
.
add
(
new
StringProperty
(
'hint'
,
hint
));
properties
.
add
(
new
EnumProperty
<
TextDirection
>(
'textDirection'
,
textDirection
,
defaultValue:
null
));
properties
.
add
(
new
EnumProperty
<
TextDirection
>(
'textDirection'
,
textDirection
,
defaultValue:
null
));
properties
.
add
(
new
DiagnosticsProperty
<
SemanticsSortKey
>(
'sortKey'
,
sortKey
,
defaultValue:
null
));
properties
.
add
(
new
DiagnosticsProperty
<
SemanticsSortKey
>(
'sortKey'
,
sortKey
,
defaultValue:
null
));
properties
.
add
(
new
DiagnosticsProperty
<
SemanticsHintOverrides
>(
'hintOverrides'
,
hintOverrides
));
}
}
@override
@override
...
@@ -1341,6 +1435,11 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
...
@@ -1341,6 +1435,11 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
String
get
hint
=>
_hint
;
String
get
hint
=>
_hint
;
String
_hint
=
_kEmptyConfig
.
hint
;
String
_hint
=
_kEmptyConfig
.
hint
;
/// Provides hint values which override the default hints on supported
/// platforms.
SemanticsHintOverrides
get
hintOverrides
=>
_hintOverrides
;
SemanticsHintOverrides
_hintOverrides
;
/// The reading direction for [label], [value], [hint], [increasedValue], and
/// The reading direction for [label], [value], [hint], [increasedValue], and
/// [decreasedValue].
/// [decreasedValue].
TextDirection
get
textDirection
=>
_textDirection
;
TextDirection
get
textDirection
=>
_textDirection
;
...
@@ -1422,6 +1521,7 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
...
@@ -1422,6 +1521,7 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
_value
=
config
.
value
;
_value
=
config
.
value
;
_increasedValue
=
config
.
increasedValue
;
_increasedValue
=
config
.
increasedValue
;
_hint
=
config
.
hint
;
_hint
=
config
.
hint
;
_hintOverrides
=
config
.
hintOverrides
;
_flags
=
config
.
_flags
;
_flags
=
config
.
_flags
;
_textDirection
=
config
.
textDirection
;
_textDirection
=
config
.
textDirection
;
_sortKey
=
config
.
sortKey
;
_sortKey
=
config
.
sortKey
;
...
@@ -1468,6 +1568,22 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
...
@@ -1468,6 +1568,22 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
final
Set
<
int
>
customSemanticsActionIds
=
new
Set
<
int
>();
final
Set
<
int
>
customSemanticsActionIds
=
new
Set
<
int
>();
for
(
CustomSemanticsAction
action
in
_customSemanticsActions
.
keys
)
for
(
CustomSemanticsAction
action
in
_customSemanticsActions
.
keys
)
customSemanticsActionIds
.
add
(
CustomSemanticsAction
.
getIdentifier
(
action
));
customSemanticsActionIds
.
add
(
CustomSemanticsAction
.
getIdentifier
(
action
));
if
(
hintOverrides
!=
null
)
{
if
(
hintOverrides
.
onTapHint
!=
null
)
{
final
CustomSemanticsAction
action
=
new
CustomSemanticsAction
.
overridingAction
(
hint:
hintOverrides
.
onTapHint
,
action:
SemanticsAction
.
tap
,
);
customSemanticsActionIds
.
add
(
CustomSemanticsAction
.
getIdentifier
(
action
));
}
if
(
hintOverrides
.
onLongPressHint
!=
null
)
{
final
CustomSemanticsAction
action
=
new
CustomSemanticsAction
.
overridingAction
(
hint:
hintOverrides
.
onLongPressHint
,
action:
SemanticsAction
.
longPress
,
);
customSemanticsActionIds
.
add
(
CustomSemanticsAction
.
getIdentifier
(
action
));
}
}
if
(
mergeAllDescendantsIntoThisNode
)
{
if
(
mergeAllDescendantsIntoThisNode
)
{
_visitDescendants
((
SemanticsNode
node
)
{
_visitDescendants
((
SemanticsNode
node
)
{
...
@@ -1493,6 +1609,22 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
...
@@ -1493,6 +1609,22 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
for
(
CustomSemanticsAction
action
in
_customSemanticsActions
.
keys
)
for
(
CustomSemanticsAction
action
in
_customSemanticsActions
.
keys
)
customSemanticsActionIds
.
add
(
CustomSemanticsAction
.
getIdentifier
(
action
));
customSemanticsActionIds
.
add
(
CustomSemanticsAction
.
getIdentifier
(
action
));
}
}
if
(
node
.
hintOverrides
!=
null
)
{
if
(
node
.
hintOverrides
.
onTapHint
!=
null
)
{
final
CustomSemanticsAction
action
=
new
CustomSemanticsAction
.
overridingAction
(
hint:
node
.
hintOverrides
.
onTapHint
,
action:
SemanticsAction
.
tap
,
);
customSemanticsActionIds
.
add
(
CustomSemanticsAction
.
getIdentifier
(
action
));
}
if
(
node
.
hintOverrides
.
onLongPressHint
!=
null
)
{
final
CustomSemanticsAction
action
=
new
CustomSemanticsAction
.
overridingAction
(
hint:
node
.
hintOverrides
.
onLongPressHint
,
action:
SemanticsAction
.
longPress
,
);
customSemanticsActionIds
.
add
(
CustomSemanticsAction
.
getIdentifier
(
action
));
}
}
label
=
_concatStrings
(
label
=
_concatStrings
(
thisString:
label
,
thisString:
label
,
thisTextDirection:
textDirection
,
thisTextDirection:
textDirection
,
...
@@ -2139,8 +2271,10 @@ class SemanticsOwner extends ChangeNotifier {
...
@@ -2139,8 +2271,10 @@ class SemanticsOwner extends ChangeNotifier {
node
.
_addToUpdate
(
builder
,
customSemanticsActionIds
);
node
.
_addToUpdate
(
builder
,
customSemanticsActionIds
);
}
}
_dirtyNodes
.
clear
();
_dirtyNodes
.
clear
();
for
(
int
actionId
in
customSemanticsActionIds
)
for
(
int
actionId
in
customSemanticsActionIds
)
{
builder
.
updateCustomAction
(
id:
actionId
,
label:
CustomSemanticsAction
.
getAction
(
actionId
).
label
);
final
CustomSemanticsAction
action
=
CustomSemanticsAction
.
getAction
(
actionId
);
builder
.
updateCustomAction
(
id:
actionId
,
label:
action
.
label
,
hint:
action
.
hint
,
overrideId:
action
.
action
?.
index
??
-
1
);
}
ui
.
window
.
updateSemantics
(
builder
.
build
());
ui
.
window
.
updateSemantics
(
builder
.
build
());
notifyListeners
();
notifyListeners
();
}
}
...
@@ -2818,6 +2952,17 @@ class SemanticsConfiguration {
...
@@ -2818,6 +2952,17 @@ class SemanticsConfiguration {
_hasBeenAnnotated
=
true
;
_hasBeenAnnotated
=
true
;
}
}
/// Provides hint values which override the default hints on supported
/// platforms.
SemanticsHintOverrides
get
hintOverrides
=>
_hintOverrides
;
SemanticsHintOverrides
_hintOverrides
;
set
hintOverrides
(
SemanticsHintOverrides
value
)
{
if
(
value
==
null
)
return
;
_hintOverrides
=
value
;
_hasBeenAnnotated
=
true
;
}
/// Whether the semantics node is the root of a subtree for which values
/// Whether the semantics node is the root of a subtree for which values
/// should be announced.
/// should be announced.
///
///
...
@@ -3138,6 +3283,7 @@ class SemanticsConfiguration {
...
@@ -3138,6 +3283,7 @@ class SemanticsConfiguration {
_scrollPosition
??=
other
.
_scrollPosition
;
_scrollPosition
??=
other
.
_scrollPosition
;
_scrollExtentMax
??=
other
.
_scrollExtentMax
;
_scrollExtentMax
??=
other
.
_scrollExtentMax
;
_scrollExtentMin
??=
other
.
_scrollExtentMin
;
_scrollExtentMin
??=
other
.
_scrollExtentMin
;
_hintOverrides
??=
other
.
_hintOverrides
;
textDirection
??=
other
.
textDirection
;
textDirection
??=
other
.
textDirection
;
_sortKey
??=
other
.
_sortKey
;
_sortKey
??=
other
.
_sortKey
;
...
@@ -3178,6 +3324,7 @@ class SemanticsConfiguration {
...
@@ -3178,6 +3324,7 @@ class SemanticsConfiguration {
..
_value
=
_value
..
_value
=
_value
..
_decreasedValue
=
_decreasedValue
..
_decreasedValue
=
_decreasedValue
..
_hint
=
_hint
..
_hint
=
_hint
..
_hintOverrides
=
_hintOverrides
..
_flags
=
_flags
..
_flags
=
_flags
..
_tagsForChildren
=
_tagsForChildren
..
_tagsForChildren
=
_tagsForChildren
..
_textSelection
=
_textSelection
..
_textSelection
=
_textSelection
...
...
packages/flutter/lib/src/widgets/basic.dart
View file @
55c7e6e3
...
@@ -5098,6 +5098,8 @@ class Semantics extends SingleChildRenderObjectWidget {
...
@@ -5098,6 +5098,8 @@ class Semantics extends SingleChildRenderObjectWidget {
String
increasedValue
,
String
increasedValue
,
String
decreasedValue
,
String
decreasedValue
,
String
hint
,
String
hint
,
String
onTapHint
,
String
onLongPressHint
,
TextDirection
textDirection
,
TextDirection
textDirection
,
SemanticsSortKey
sortKey
,
SemanticsSortKey
sortKey
,
VoidCallback
onTap
,
VoidCallback
onTap
,
...
@@ -5165,6 +5167,11 @@ class Semantics extends SingleChildRenderObjectWidget {
...
@@ -5165,6 +5167,11 @@ class Semantics extends SingleChildRenderObjectWidget {
onDismiss:
onDismiss
,
onDismiss:
onDismiss
,
onSetSelection:
onSetSelection
,
onSetSelection:
onSetSelection
,
customSemanticsActions:
customSemanticsActions
,
customSemanticsActions:
customSemanticsActions
,
hintOverrides:
onTapHint
!=
null
||
onLongPressHint
!=
null
?
new
SemanticsHintOverrides
(
onTapHint:
onTapHint
,
onLongPressHint:
onLongPressHint
,
)
:
null
,
),
),
);
);
...
@@ -5248,6 +5255,7 @@ class Semantics extends SingleChildRenderObjectWidget {
...
@@ -5248,6 +5255,7 @@ class Semantics extends SingleChildRenderObjectWidget {
increasedValue:
properties
.
increasedValue
,
increasedValue:
properties
.
increasedValue
,
decreasedValue:
properties
.
decreasedValue
,
decreasedValue:
properties
.
decreasedValue
,
hint:
properties
.
hint
,
hint:
properties
.
hint
,
hintOverrides:
properties
.
hintOverrides
,
textDirection:
_getTextDirection
(
context
),
textDirection:
_getTextDirection
(
context
),
sortKey:
properties
.
sortKey
,
sortKey:
properties
.
sortKey
,
onTap:
properties
.
onTap
,
onTap:
properties
.
onTap
,
...
@@ -5308,6 +5316,7 @@ class Semantics extends SingleChildRenderObjectWidget {
...
@@ -5308,6 +5316,7 @@ class Semantics extends SingleChildRenderObjectWidget {
..
increasedValue
=
properties
.
increasedValue
..
increasedValue
=
properties
.
increasedValue
..
decreasedValue
=
properties
.
decreasedValue
..
decreasedValue
=
properties
.
decreasedValue
..
hint
=
properties
.
hint
..
hint
=
properties
.
hint
..
hintOverrides
=
properties
.
hintOverrides
..
namesRoute
=
properties
.
namesRoute
..
namesRoute
=
properties
.
namesRoute
..
textDirection
=
_getTextDirection
(
context
)
..
textDirection
=
_getTextDirection
(
context
)
..
sortKey
=
properties
.
sortKey
..
sortKey
=
properties
.
sortKey
...
...
packages/flutter/test/widgets/semantics_test.dart
View file @
55c7e6e3
...
@@ -634,6 +634,51 @@ void main() {
...
@@ -634,6 +634,51 @@ void main() {
semantics
.
dispose
();
semantics
.
dispose
();
});
});
testWidgets
(
'onTapHint and onLongPressHint create custom actions'
,
(
WidgetTester
tester
)
async
{
final
SemanticsHandle
semantics
=
tester
.
ensureSemantics
();
await
tester
.
pumpWidget
(
new
Semantics
(
container:
true
,
onTap:
()
{},
onTapHint:
'test'
,
));
expect
(
tester
.
getSemanticsData
(
find
.
byType
(
Semantics
)),
matchesSemanticsData
(
hasTapAction:
true
,
onTapHint:
'test'
));
await
tester
.
pumpWidget
(
new
Semantics
(
container:
true
,
onLongPress:
()
{},
onLongPressHint:
'foo'
,
));
expect
(
tester
.
getSemanticsData
(
find
.
byType
(
Semantics
)),
matchesSemanticsData
(
hasLongPressAction:
true
,
onLongPressHint:
'foo'
));
semantics
.
dispose
();
});
testWidgets
(
'CustomSemanticsActions can be added to a Semantics widget'
,
(
WidgetTester
tester
)
async
{
final
SemanticsHandle
semantics
=
tester
.
ensureSemantics
();
await
tester
.
pumpWidget
(
new
Semantics
(
container:
true
,
customSemanticsActions:
<
CustomSemanticsAction
,
VoidCallback
>{
const
CustomSemanticsAction
(
label:
'foo'
):
()
{},
const
CustomSemanticsAction
(
label:
'bar'
):
()
{}
},
));
expect
(
tester
.
getSemanticsData
(
find
.
byType
(
Semantics
)),
matchesSemanticsData
(
customActions:
<
CustomSemanticsAction
>[
const
CustomSemanticsAction
(
label:
'bar'
),
const
CustomSemanticsAction
(
label:
'foo'
),
],
));
semantics
.
dispose
();
});
testWidgets
(
'Increased/decreased values are annotated'
,
(
WidgetTester
tester
)
async
{
testWidgets
(
'Increased/decreased values are annotated'
,
(
WidgetTester
tester
)
async
{
final
SemanticsTester
semantics
=
new
SemanticsTester
(
tester
);
final
SemanticsTester
semantics
=
new
SemanticsTester
(
tester
);
...
...
packages/flutter_test/lib/src/matchers.dart
View file @
55c7e6e3
...
@@ -345,8 +345,11 @@ Matcher matchesSemanticsData({
...
@@ -345,8 +345,11 @@ Matcher matchesSemanticsData({
bool
hasPasteAction
=
false
,
bool
hasPasteAction
=
false
,
bool
hasDidGainAccessibilityFocusAction
=
false
,
bool
hasDidGainAccessibilityFocusAction
=
false
,
bool
hasDidLoseAccessibilityFocusAction
=
false
,
bool
hasDidLoseAccessibilityFocusAction
=
false
,
bool
hasCustomAction
=
false
,
bool
hasDismissAction
=
false
,
bool
hasDismissAction
=
false
,
// Custom actions and overrides
String
onTapHint
,
String
onLongPressHint
,
List
<
CustomSemanticsAction
>
customActions
,
})
{
})
{
final
List
<
SemanticsFlag
>
flags
=
<
SemanticsFlag
>[];
final
List
<
SemanticsFlag
>
flags
=
<
SemanticsFlag
>[];
if
(
hasCheckedState
)
if
(
hasCheckedState
)
...
@@ -421,7 +424,7 @@ Matcher matchesSemanticsData({
...
@@ -421,7 +424,7 @@ Matcher matchesSemanticsData({
actions
.
add
(
SemanticsAction
.
didGainAccessibilityFocus
);
actions
.
add
(
SemanticsAction
.
didGainAccessibilityFocus
);
if
(
hasDidLoseAccessibilityFocusAction
)
if
(
hasDidLoseAccessibilityFocusAction
)
actions
.
add
(
SemanticsAction
.
didLoseAccessibilityFocus
);
actions
.
add
(
SemanticsAction
.
didLoseAccessibilityFocus
);
if
(
hasCustomAction
)
if
(
customActions
!=
null
&&
customActions
.
isNotEmpty
)
actions
.
add
(
SemanticsAction
.
customAction
);
actions
.
add
(
SemanticsAction
.
customAction
);
if
(
hasDismissAction
)
if
(
hasDismissAction
)
actions
.
add
(
SemanticsAction
.
dismiss
);
actions
.
add
(
SemanticsAction
.
dismiss
);
...
@@ -429,6 +432,12 @@ Matcher matchesSemanticsData({
...
@@ -429,6 +432,12 @@ Matcher matchesSemanticsData({
actions
.
add
(
SemanticsAction
.
moveCursorForwardByWord
);
actions
.
add
(
SemanticsAction
.
moveCursorForwardByWord
);
if
(
hasMoveCursorBackwardByWordAction
)
if
(
hasMoveCursorBackwardByWordAction
)
actions
.
add
(
SemanticsAction
.
moveCursorBackwardByWord
);
actions
.
add
(
SemanticsAction
.
moveCursorBackwardByWord
);
SemanticsHintOverrides
hintOverrides
;
if
(
onTapHint
!=
null
||
onLongPressHint
!=
null
)
hintOverrides
=
new
SemanticsHintOverrides
(
onTapHint:
onTapHint
,
onLongPressHint:
onLongPressHint
,
);
return
new
_MatchesSemanticsData
(
return
new
_MatchesSemanticsData
(
label:
label
,
label:
label
,
...
@@ -438,6 +447,8 @@ Matcher matchesSemanticsData({
...
@@ -438,6 +447,8 @@ Matcher matchesSemanticsData({
flags:
flags
,
flags:
flags
,
textDirection:
textDirection
,
textDirection:
textDirection
,
rect:
rect
,
rect:
rect
,
customActions:
customActions
,
hintOverrides:
hintOverrides
,
);
);
}
}
...
@@ -1467,12 +1478,16 @@ class _MatchesSemanticsData extends Matcher {
...
@@ -1467,12 +1478,16 @@ class _MatchesSemanticsData extends Matcher {
this
.
actions
,
this
.
actions
,
this
.
textDirection
,
this
.
textDirection
,
this
.
rect
,
this
.
rect
,
this
.
customActions
,
this
.
hintOverrides
,
});
});
final
String
label
;
final
String
label
;
final
String
value
;
final
String
value
;
final
String
hint
;
final
String
hint
;
final
SemanticsHintOverrides
hintOverrides
;
final
List
<
SemanticsAction
>
actions
;
final
List
<
SemanticsAction
>
actions
;
final
List
<
CustomSemanticsAction
>
customActions
;
final
List
<
SemanticsFlag
>
flags
;
final
List
<
SemanticsFlag
>
flags
;
final
TextDirection
textDirection
;
final
TextDirection
textDirection
;
final
Rect
rect
;
final
Rect
rect
;
...
@@ -1494,6 +1509,10 @@ class _MatchesSemanticsData extends Matcher {
...
@@ -1494,6 +1509,10 @@ class _MatchesSemanticsData extends Matcher {
description
.
add
(
'with textDirection:
$textDirection
'
);
description
.
add
(
'with textDirection:
$textDirection
'
);
if
(
rect
!=
null
)
if
(
rect
!=
null
)
description
.
add
(
'with rect:
$rect
'
);
description
.
add
(
'with rect:
$rect
'
);
if
(
customActions
!=
null
)
description
.
add
(
'with custom actions:
$customActions
'
);
if
(
hintOverrides
!=
null
)
description
.
add
(
'with custom hints:
$hintOverrides
'
);
return
description
;
return
description
;
}
}
...
@@ -1511,7 +1530,7 @@ class _MatchesSemanticsData extends Matcher {
...
@@ -1511,7 +1530,7 @@ class _MatchesSemanticsData extends Matcher {
return
failWithDescription
(
matchState
,
'value was:
${data.value}
'
);
return
failWithDescription
(
matchState
,
'value was:
${data.value}
'
);
if
(
textDirection
!=
null
&&
textDirection
!=
data
.
textDirection
)
if
(
textDirection
!=
null
&&
textDirection
!=
data
.
textDirection
)
return
failWithDescription
(
matchState
,
'textDirection was:
$textDirection
'
);
return
failWithDescription
(
matchState
,
'textDirection was:
$textDirection
'
);
if
(
rect
!=
null
&&
rect
=
=
data
.
rect
)
{
if
(
rect
!=
null
&&
rect
!
=
data
.
rect
)
{
return
failWithDescription
(
matchState
,
'rect was:
$rect
'
);
return
failWithDescription
(
matchState
,
'rect was:
$rect
'
);
}
}
if
(
actions
!=
null
)
{
if
(
actions
!=
null
)
{
...
@@ -1527,6 +1546,27 @@ class _MatchesSemanticsData extends Matcher {
...
@@ -1527,6 +1546,27 @@ class _MatchesSemanticsData extends Matcher {
return
failWithDescription
(
matchState
,
'actions were:
$actionSummary
'
);
return
failWithDescription
(
matchState
,
'actions were:
$actionSummary
'
);
}
}
}
}
if
(
customActions
!=
null
||
hintOverrides
!=
null
)
{
final
List
<
CustomSemanticsAction
>
providedCustomActions
=
data
.
customSemanticsActionIds
.
map
((
int
id
)
{
return
CustomSemanticsAction
.
getAction
(
id
);
}).
toList
();
final
List
<
CustomSemanticsAction
>
expectedCustomActions
=
new
List
<
CustomSemanticsAction
>.
from
(
customActions
??
const
<
int
>[]);
if
(
hintOverrides
?.
onTapHint
!=
null
)
expectedCustomActions
.
add
(
new
CustomSemanticsAction
.
overridingAction
(
hint:
hintOverrides
.
onTapHint
,
action:
SemanticsAction
.
tap
));
if
(
hintOverrides
?.
onLongPressHint
!=
null
)
expectedCustomActions
.
add
(
new
CustomSemanticsAction
.
overridingAction
(
hint:
hintOverrides
.
onLongPressHint
,
action:
SemanticsAction
.
longPress
));
if
(
expectedCustomActions
.
length
!=
providedCustomActions
.
length
)
return
failWithDescription
(
matchState
,
'custom actions where:
$providedCustomActions
'
);
int
sortActions
(
CustomSemanticsAction
left
,
CustomSemanticsAction
right
)
{
return
CustomSemanticsAction
.
getIdentifier
(
left
)
-
CustomSemanticsAction
.
getIdentifier
(
right
);
}
expectedCustomActions
.
sort
(
sortActions
);
providedCustomActions
.
sort
(
sortActions
);
for
(
int
i
=
0
;
i
<
expectedCustomActions
.
length
;
i
++)
{
if
(
expectedCustomActions
[
i
]
!=
providedCustomActions
[
i
])
return
failWithDescription
(
matchState
,
'custom actions where:
$providedCustomActions
'
);
}
}
if
(
flags
!=
null
)
{
if
(
flags
!=
null
)
{
int
flagBits
=
0
;
int
flagBits
=
0
;
for
(
SemanticsFlag
flag
in
flags
)
for
(
SemanticsFlag
flag
in
flags
)
...
...
packages/flutter_test/test/matchers_test.dart
View file @
55c7e6e3
...
@@ -394,10 +394,17 @@ void main() {
...
@@ -394,10 +394,17 @@ void main() {
header:
true
,
header:
true
,
button:
true
,
button:
true
,
onTap:
()
{},
onTap:
()
{},
onLongPress:
()
{},
label:
'foo'
,
label:
'foo'
,
hint:
'bar'
,
hint:
'bar'
,
value:
'baz'
,
value:
'baz'
,
textDirection:
TextDirection
.
rtl
,
textDirection:
TextDirection
.
rtl
,
onTapHint:
'scan'
,
onLongPressHint:
'fill'
,
customSemanticsActions:
<
CustomSemanticsAction
,
VoidCallback
>{
const
CustomSemanticsAction
(
label:
'foo'
):
()
{},
const
CustomSemanticsAction
(
label:
'bar'
):
()
{},
},
));
));
expect
(
tester
.
getSemanticsData
(
find
.
byKey
(
key
)),
expect
(
tester
.
getSemanticsData
(
find
.
byKey
(
key
)),
...
@@ -407,17 +414,68 @@ void main() {
...
@@ -407,17 +414,68 @@ void main() {
value:
'baz'
,
value:
'baz'
,
textDirection:
TextDirection
.
rtl
,
textDirection:
TextDirection
.
rtl
,
hasTapAction:
true
,
hasTapAction:
true
,
hasLongPressAction:
true
,
isButton:
true
,
isButton:
true
,
isHeader:
true
,
isHeader:
true
,
namesRoute:
true
,
namesRoute:
true
,
onTapHint:
'scan'
,
onLongPressHint:
'fill'
,
customActions:
<
CustomSemanticsAction
>[
const
CustomSemanticsAction
(
label:
'foo'
),
const
CustomSemanticsAction
(
label:
'bar'
)
],
),
),
);
);
// Doesn't match custom actions
expect
(
tester
.
getSemanticsData
(
find
.
byKey
(
key
)),
isNot
(
matchesSemanticsData
(
label:
'foo'
,
hint:
'bar'
,
value:
'baz'
,
textDirection:
TextDirection
.
rtl
,
hasTapAction:
true
,
hasLongPressAction:
true
,
isButton:
true
,
isHeader:
true
,
namesRoute:
true
,
onTapHint:
'scan'
,
onLongPressHint:
'fill'
,
customActions:
<
CustomSemanticsAction
>[
const
CustomSemanticsAction
(
label:
'foo'
),
const
CustomSemanticsAction
(
label:
'barz'
)
],
)),
);
// Doesn't match wrong hints
expect
(
tester
.
getSemanticsData
(
find
.
byKey
(
key
)),
isNot
(
matchesSemanticsData
(
label:
'foo'
,
hint:
'bar'
,
value:
'baz'
,
textDirection:
TextDirection
.
rtl
,
hasTapAction:
true
,
hasLongPressAction:
true
,
isButton:
true
,
isHeader:
true
,
namesRoute:
true
,
onTapHint:
'scans'
,
onLongPressHint:
'fills'
,
customActions:
<
CustomSemanticsAction
>[
const
CustomSemanticsAction
(
label:
'foo'
),
const
CustomSemanticsAction
(
label:
'bar'
)
],
)),
);
handle
.
dispose
();
handle
.
dispose
();
});
});
testWidgets
(
'Can match all semantics flags and actions'
,
(
WidgetTester
tester
)
async
{
testWidgets
(
'Can match all semantics flags and actions'
,
(
WidgetTester
tester
)
async
{
int
actions
=
0
;
int
actions
=
0
;
int
flags
=
0
;
int
flags
=
0
;
const
CustomSemanticsAction
action
=
const
CustomSemanticsAction
(
label:
'test'
);
for
(
int
index
in
SemanticsAction
.
values
.
keys
)
for
(
int
index
in
SemanticsAction
.
values
.
keys
)
actions
|=
index
;
actions
|=
index
;
for
(
int
index
in
SemanticsFlag
.
values
.
keys
)
for
(
int
index
in
SemanticsFlag
.
values
.
keys
)
...
@@ -436,6 +494,7 @@ void main() {
...
@@ -436,6 +494,7 @@ void main() {
scrollPosition:
null
,
scrollPosition:
null
,
scrollExtentMax:
null
,
scrollExtentMax:
null
,
scrollExtentMin:
null
,
scrollExtentMin:
null
,
customSemanticsActionIds:
<
int
>[
CustomSemanticsAction
.
getIdentifier
(
action
)],
);
);
expect
(
data
,
matchesSemanticsData
(
expect
(
data
,
matchesSemanticsData
(
...
@@ -478,8 +537,8 @@ void main() {
...
@@ -478,8 +537,8 @@ void main() {
hasPasteAction:
true
,
hasPasteAction:
true
,
hasDidGainAccessibilityFocusAction:
true
,
hasDidGainAccessibilityFocusAction:
true
,
hasDidLoseAccessibilityFocusAction:
true
,
hasDidLoseAccessibilityFocusAction:
true
,
hasCustomAction:
true
,
hasDismissAction:
true
,
hasDismissAction:
true
,
customActions:
<
CustomSemanticsAction
>[
action
],
));
));
});
});
});
});
...
...
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