Unverified Commit 9184dfba authored by Michael Goderbauer's avatar Michael Goderbauer Committed by GitHub

Support value announcement for increase/decrease (#12741)

* Support value announcment for increase/decrease

* ++

* review comments about docs
parent e1174eb0
...@@ -3177,6 +3177,8 @@ class RenderSemanticsAnnotations extends RenderProxyBox { ...@@ -3177,6 +3177,8 @@ class RenderSemanticsAnnotations extends RenderProxyBox {
bool button, bool button,
String label, String label,
String value, String value,
String increasedValue,
String decreasedValue,
String hint, String hint,
TextDirection textDirection, TextDirection textDirection,
VoidCallback onTap, VoidCallback onTap,
...@@ -3195,6 +3197,8 @@ class RenderSemanticsAnnotations extends RenderProxyBox { ...@@ -3195,6 +3197,8 @@ class RenderSemanticsAnnotations extends RenderProxyBox {
_button = button, _button = button,
_label = label, _label = label,
_value = value, _value = value,
_increasedValue = increasedValue,
_decreasedValue = decreasedValue,
_hint = hint, _hint = hint,
_textDirection = textDirection, _textDirection = textDirection,
_onTap = onTap, _onTap = onTap,
...@@ -3283,7 +3287,7 @@ class RenderSemanticsAnnotations extends RenderProxyBox { ...@@ -3283,7 +3287,7 @@ class RenderSemanticsAnnotations extends RenderProxyBox {
/// If non-null, sets the [SemanticsNode.label] semantic to the given value. /// If non-null, sets the [SemanticsNode.label] semantic to the given value.
/// ///
/// The text's reading direction is given by [textDirection]. /// The reading direction is given by [textDirection].
String get label => _label; String get label => _label;
String _label; String _label;
set label(String value) { set label(String value) {
...@@ -3296,7 +3300,7 @@ class RenderSemanticsAnnotations extends RenderProxyBox { ...@@ -3296,7 +3300,7 @@ class RenderSemanticsAnnotations extends RenderProxyBox {
/// If non-null, sets the [SemanticsNode.value] semantic to the given value. /// If non-null, sets the [SemanticsNode.value] semantic to the given value.
/// ///
/// The text's reading direction is given by [textDirection]. /// The reading direction is given by [textDirection].
String get value => _value; String get value => _value;
String _value; String _value;
set value(String value) { set value(String value) {
...@@ -3307,9 +3311,37 @@ class RenderSemanticsAnnotations extends RenderProxyBox { ...@@ -3307,9 +3311,37 @@ class RenderSemanticsAnnotations extends RenderProxyBox {
markNeedsSemanticsUpdate(onlyLocalUpdates: (value != null) == hadValue); markNeedsSemanticsUpdate(onlyLocalUpdates: (value != null) == hadValue);
} }
/// If non-null, sets the [SemanticsNode.increasedValue] semantic to the given
/// value.
///
/// The reading direction is given by [textDirection].
String get increasedValue => _increasedValue;
String _increasedValue;
set increasedValue(String value) {
if (_increasedValue == value)
return;
final bool hadValue = _increasedValue != null;
_increasedValue = value;
markNeedsSemanticsUpdate(onlyLocalUpdates: (value != null) == hadValue);
}
/// If non-null, sets the [SemanticsNode.decreasedValue] semantic to the given
/// value.
///
/// The reading direction is given by [textDirection].
String get decreasedValue => _decreasedValue;
String _decreasedValue;
set decreasedValue(String value) {
if (_decreasedValue == value)
return;
final bool hadValue = _decreasedValue != null;
_decreasedValue = value;
markNeedsSemanticsUpdate(onlyLocalUpdates: (value != null) == hadValue);
}
/// If non-null, sets the [SemanticsNode.hint] semantic to the given value. /// If non-null, sets the [SemanticsNode.hint] semantic to the given value.
/// ///
/// The text's reading direction is given by [textDirection]. /// The reading direction is given by [textDirection].
String get hint => _hint; String get hint => _hint;
String _hint; String _hint;
set hint(String value) { set hint(String value) {
...@@ -3322,7 +3354,8 @@ class RenderSemanticsAnnotations extends RenderProxyBox { ...@@ -3322,7 +3354,8 @@ class RenderSemanticsAnnotations extends RenderProxyBox {
/// 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], or [value] is not null. /// This must not be null if [label], [hint], [value], [increasedValue], or
/// [decreasedValue] are not null.
TextDirection get textDirection => _textDirection; TextDirection get textDirection => _textDirection;
TextDirection _textDirection; TextDirection _textDirection;
set textDirection(TextDirection value) { set textDirection(TextDirection value) {
...@@ -3499,6 +3532,15 @@ class RenderSemanticsAnnotations extends RenderProxyBox { ...@@ -3499,6 +3532,15 @@ class RenderSemanticsAnnotations extends RenderProxyBox {
@override @override
void describeSemanticsConfiguration(SemanticsConfiguration config) { void describeSemanticsConfiguration(SemanticsConfiguration config) {
assert(
onIncrease == null || (value == null) == (increasedValue == null),
'If "onIncrease" is set either both "value" and "increasedValue" or neither have to be set.',
);
assert(
onDecrease == null || (value == null) == (decreasedValue == null),
'If "onDecrease" is set either both "value" and "decreasedValue" or neither have to be set.',
);
config.isSemanticBoundary = container; config.isSemanticBoundary = container;
config.explicitChildNodes = explicitChildNodes; config.explicitChildNodes = explicitChildNodes;
...@@ -3512,6 +3554,10 @@ class RenderSemanticsAnnotations extends RenderProxyBox { ...@@ -3512,6 +3554,10 @@ class RenderSemanticsAnnotations extends RenderProxyBox {
config.label = label; config.label = label;
if (value != null) if (value != null)
config.value = value; config.value = value;
if (increasedValue != null)
config.increasedValue = increasedValue;
if (decreasedValue != null)
config.decreasedValue = decreasedValue;
if (hint != null) if (hint != null)
config.hint = hint; config.hint = hint;
if (textDirection != null) if (textDirection != null)
......
...@@ -76,7 +76,9 @@ class SemanticsData extends Diagnosticable { ...@@ -76,7 +76,9 @@ class SemanticsData extends Diagnosticable {
@required this.flags, @required this.flags,
@required this.actions, @required this.actions,
@required this.label, @required this.label,
@required this.increasedValue,
@required this.value, @required this.value,
@required this.decreasedValue,
@required this.hint, @required this.hint,
@required this.textDirection, @required this.textDirection,
@required this.rect, @required this.rect,
...@@ -85,7 +87,15 @@ class SemanticsData extends Diagnosticable { ...@@ -85,7 +87,15 @@ class SemanticsData extends Diagnosticable {
}) : assert(flags != null), }) : assert(flags != null),
assert(actions != null), assert(actions != null),
assert(label != null), assert(label != null),
assert(value != null),
assert(decreasedValue != null),
assert(increasedValue != null),
assert(hint != null),
assert(label == '' || textDirection != null, 'A SemanticsData object with label "$label" had a null textDirection.'), assert(label == '' || textDirection != null, 'A SemanticsData object with label "$label" had a null textDirection.'),
assert(value == '' || textDirection != null, 'A SemanticsData object with value "$value" had a null textDirection.'),
assert(hint == '' || textDirection != null, 'A SemanticsData object with hint "$hint" had a null textDirection.'),
assert(decreasedValue == '' || textDirection != null, 'A SemanticsData object with decreasedValue "$decreasedValue" had a null textDirection.'),
assert(increasedValue == '' || textDirection != null, 'A SemanticsData object with increasedValue "$increasedValue" had a null textDirection.'),
assert(rect != null); assert(rect != null);
/// A bit field of [SemanticsFlags] that apply to this node. /// A bit field of [SemanticsFlags] that apply to this node.
...@@ -96,20 +106,33 @@ class SemanticsData extends Diagnosticable { ...@@ -96,20 +106,33 @@ class SemanticsData extends Diagnosticable {
/// A textual description of this node. /// A textual description of this node.
/// ///
/// The text's reading direction is given by [textDirection]. /// The reading direction is given by [textDirection].
final String label; final String label;
/// A textual description for the current value of the node. /// A textual description for the current value of the node.
/// ///
/// The text's reading direction is given by [textDirection]. /// The reading direction is given by [textDirection].
final String value; final String value;
/// The value that [value] will become after performing a
/// [SemanticsAction.increase] action.
///
/// The reading direction is given by [textDirection].
final String increasedValue;
/// The value that [value] will become after performing a
/// [SemanticsAction.decrease] action.
///
/// The reading direction is given by [textDirection].
final String decreasedValue;
/// A brief description of the result of performing an action on this node. /// A brief description of the result of performing an action on this node.
/// ///
/// The text's reading direction is given by [textDirection]. /// The reading direction is given by [textDirection].
final String hint; final String hint;
/// The reading direction for the text in [label], [value], and [hint]. /// The reading direction for the text in [label], [value], [hint],
/// [increasedValue], and [decreasedValue].
final TextDirection textDirection; final TextDirection textDirection;
/// The bounding box for this node in its coordinate system. /// The bounding box for this node in its coordinate system.
...@@ -153,6 +176,10 @@ class SemanticsData extends Diagnosticable { ...@@ -153,6 +176,10 @@ class SemanticsData extends Diagnosticable {
} }
properties.add(new IterableProperty<String>('flags', flagSummary, ifEmpty: null)); properties.add(new IterableProperty<String>('flags', flagSummary, ifEmpty: null));
properties.add(new StringProperty('label', label, defaultValue: '')); properties.add(new StringProperty('label', label, defaultValue: ''));
properties.add(new StringProperty('value', value, defaultValue: ''));
properties.add(new StringProperty('increasedValue', increasedValue, defaultValue: ''));
properties.add(new StringProperty('decreasedValue', decreasedValue, defaultValue: ''));
properties.add(new StringProperty('hint', hint, defaultValue: ''));
properties.add(new EnumProperty<TextDirection>('textDirection', textDirection, defaultValue: null)); properties.add(new EnumProperty<TextDirection>('textDirection', textDirection, defaultValue: null));
} }
...@@ -495,7 +522,9 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin { ...@@ -495,7 +522,9 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
bool _isDifferentFromCurrentSemanticAnnotation(SemanticsConfiguration config) { bool _isDifferentFromCurrentSemanticAnnotation(SemanticsConfiguration config) {
return _label != config.label || return _label != config.label ||
_hint != config.hint || _hint != config.hint ||
_decreasedValue != config.decreasedValue ||
_value != config.value || _value != config.value ||
_increasedValue != config.increasedValue ||
_flags != config._flags || _flags != config._flags ||
_textDirection != config.textDirection || _textDirection != config.textDirection ||
_actionsAsBits != config._actionsAsBits || _actionsAsBits != config._actionsAsBits ||
...@@ -523,23 +552,44 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin { ...@@ -523,23 +552,44 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
/// A textual description of this node. /// A textual description of this node.
/// ///
/// The text's reading direction is given by [textDirection]. /// The reading direction is given by [textDirection].
String get label => _label; String get label => _label;
String _label = _kEmptyConfig.label; String _label = _kEmptyConfig.label;
/// A textual description for the current value of the node. /// A textual description for the current value of the node.
/// ///
/// The text's reading direction is given by [textDirection]. /// The reading direction is given by [textDirection].
String get value => _value; String get value => _value;
String _value = _kEmptyConfig.value; String _value = _kEmptyConfig.value;
/// The value that [value] will have after a [SemanticsAction.decrease] action
/// has been performed.
///
/// This property is only valid if the [SemanticsAction.decrease] action is
/// available on this node.
///
/// The reading direction is given by [textDirection].
String get decreasedValue => _decreasedValue;
String _decreasedValue = _kEmptyConfig.decreasedValue;
/// The value that [value] will have after a [SemanticsAction.increase] action
/// has been performed.
///
/// This property is only valid if the [SemanticsAction.increase] action is
/// available on this node.
///
/// The reading direction is given by [textDirection].
String get increasedValue => _increasedValue;
String _increasedValue = _kEmptyConfig.increasedValue;
/// A brief description of the result of performing an action on this node. /// A brief description of the result of performing an action on this node.
/// ///
/// The text's reading direction is given by [textDirection]. /// The reading direction is given by [textDirection].
String get hint => _hint; String get hint => _hint;
String _hint = _kEmptyConfig.hint; String _hint = _kEmptyConfig.hint;
/// The reading direction for [label], [value], and [hint]. /// The reading direction for [label], [value], [hint], [increasedValue], and
/// [decreasedValue].
TextDirection get textDirection => _textDirection; TextDirection get textDirection => _textDirection;
TextDirection _textDirection = _kEmptyConfig.textDirection; TextDirection _textDirection = _kEmptyConfig.textDirection;
...@@ -556,7 +606,9 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin { ...@@ -556,7 +606,9 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
_markDirty(); _markDirty();
_label = config.label; _label = config.label;
_decreasedValue = config.decreasedValue;
_value = config.value; _value = config.value;
_increasedValue = config.increasedValue;
_hint = config.hint; _hint = config.hint;
_flags = config._flags; _flags = config._flags;
_textDirection = config.textDirection; _textDirection = config.textDirection;
...@@ -564,6 +616,15 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin { ...@@ -564,6 +616,15 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
_actionsAsBits = config._actionsAsBits; _actionsAsBits = config._actionsAsBits;
_mergeAllDescendantsIntoThisNode = config.isMergingSemanticsOfDescendants; _mergeAllDescendantsIntoThisNode = config.isMergingSemanticsOfDescendants;
_replaceChildren(childrenInInversePaintOrder ?? const <SemanticsNode>[]); _replaceChildren(childrenInInversePaintOrder ?? const <SemanticsNode>[]);
assert(
!_canPerformAction(SemanticsAction.increase) || (_value == '') == (_increasedValue == ''),
'A SemanticsNode with action "increase" needs to be annotated with either both "value" and "increasedValue" or neither',
);
assert(
!_canPerformAction(SemanticsAction.decrease) || (_value == '') == (_decreasedValue == ''),
'A SemanticsNode with action "increase" needs to be annotated with either both "value" and "decreasedValue" or neither',
);
} }
...@@ -578,6 +639,8 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin { ...@@ -578,6 +639,8 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
String label = _label; String label = _label;
String hint = _hint; String hint = _hint;
String value = _value; String value = _value;
String increasedValue = _increasedValue;
String decreasedValue = _decreasedValue;
TextDirection textDirection = _textDirection; TextDirection textDirection = _textDirection;
Set<SemanticsTag> mergedTags = tags == null ? null : new Set<SemanticsTag>.from(tags); Set<SemanticsTag> mergedTags = tags == null ? null : new Set<SemanticsTag>.from(tags);
...@@ -589,6 +652,10 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin { ...@@ -589,6 +652,10 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
textDirection ??= node._textDirection; textDirection ??= node._textDirection;
if (value == '' || value == null) if (value == '' || value == null)
value = node._value; value = node._value;
if (increasedValue == '' || increasedValue == null)
increasedValue = node._increasedValue;
if (decreasedValue == '' || decreasedValue == null)
decreasedValue = node._decreasedValue;
if (node.tags != null) { if (node.tags != null) {
mergedTags ??= new Set<SemanticsTag>(); mergedTags ??= new Set<SemanticsTag>();
mergedTags.addAll(node.tags); mergedTags.addAll(node.tags);
...@@ -614,6 +681,8 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin { ...@@ -614,6 +681,8 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
actions: actions, actions: actions,
label: label, label: label,
value: value, value: value,
increasedValue: increasedValue,
decreasedValue: decreasedValue,
hint: hint, hint: hint,
textDirection: textDirection, textDirection: textDirection,
rect: rect, rect: rect,
...@@ -648,6 +717,8 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin { ...@@ -648,6 +717,8 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
rect: data.rect, rect: data.rect,
label: data.label, label: data.label,
value: data.value, value: data.value,
decreasedValue: data.decreasedValue,
increasedValue: data.increasedValue,
hint: data.hint, hint: data.hint,
textDirection: data.textDirection, textDirection: data.textDirection,
transform: data.transform?.storage ?? _kIdentityTransform, transform: data.transform?.storage ?? _kIdentityTransform,
...@@ -707,6 +778,8 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin { ...@@ -707,6 +778,8 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
properties.add(new FlagProperty('isButton', value: _hasFlag(SemanticsFlags.isButton), ifTrue: 'button')); properties.add(new FlagProperty('isButton', value: _hasFlag(SemanticsFlags.isButton), ifTrue: 'button'));
properties.add(new StringProperty('label', _label, defaultValue: '')); properties.add(new StringProperty('label', _label, defaultValue: ''));
properties.add(new StringProperty('value', _value, defaultValue: '')); properties.add(new StringProperty('value', _value, defaultValue: ''));
properties.add(new StringProperty('increasedValue', _increasedValue, defaultValue: ''));
properties.add(new StringProperty('decreasedValue', _decreasedValue, defaultValue: ''));
properties.add(new StringProperty('hint', _hint, defaultValue: '')); properties.add(new StringProperty('hint', _hint, defaultValue: ''));
properties.add(new EnumProperty<TextDirection>('textDirection', _textDirection, defaultValue: null)); properties.add(new EnumProperty<TextDirection>('textDirection', _textDirection, defaultValue: null));
} }
...@@ -1018,6 +1091,7 @@ class SemanticsConfiguration { ...@@ -1018,6 +1091,7 @@ class SemanticsConfiguration {
/// ///
/// Whenever the user performs `action` the provided `handler` is called. /// Whenever the user performs `action` the provided `handler` is called.
void addAction(SemanticsAction action, VoidCallback handler) { void addAction(SemanticsAction action, VoidCallback handler) {
assert(handler != null);
_actions[action] = handler; _actions[action] = handler;
_actionsAsBits |= action.index; _actionsAsBits |= action.index;
_hasBeenAnnotated = true; _hasBeenAnnotated = true;
...@@ -1050,10 +1124,11 @@ class SemanticsConfiguration { ...@@ -1050,10 +1124,11 @@ class SemanticsConfiguration {
/// [value] and [hint] in the following order: [value], [label], [hint]. /// [value] and [hint] in the following order: [value], [label], [hint].
/// The concatenated value is then used as the `Text` description. /// The concatenated value is then used as the `Text` description.
/// ///
/// The text's reading direction is given by [textDirection]. /// The reading direction is given by [textDirection].
String get label => _label; String get label => _label;
String _label = ''; String _label = '';
set label(String label) { set label(String label) {
assert(label != null);
_label = label; _label = label;
_hasBeenAnnotated = true; _hasBeenAnnotated = true;
} }
...@@ -1065,14 +1140,51 @@ class SemanticsConfiguration { ...@@ -1065,14 +1140,51 @@ class SemanticsConfiguration {
/// [label] and [hint] in the following order: [value], [label], [hint]. /// [label] and [hint] in the following order: [value], [label], [hint].
/// The concatenated value is then used as the `Text` description. /// The concatenated value is then used as the `Text` description.
/// ///
/// The text's reading direction is given by [textDirection]. /// The reading direction is given by [textDirection].
///
/// See also:
/// * [decreasedValue], describes what [value] will be after performing
/// [SemanticsAction.decrease]
/// * [increasedValue], describes what [value] will be after performing
/// [SemanticsAction.increase]
String get value => _value; String get value => _value;
String _value = ''; String _value = '';
set value(String value) { set value(String value) {
assert(value != null);
_value = value; _value = value;
_hasBeenAnnotated = true; _hasBeenAnnotated = true;
} }
/// The value that [value] will have after performing a
/// [SemanticsAction.decrease] action.
///
/// This must be set if a handler for [SemanticsAction.decrease] is provided
/// and [value] is set.
///
/// The reading direction is given by [textDirection].
String get decreasedValue => _decreasedValue;
String _decreasedValue = '';
set decreasedValue(String decreasedValue) {
assert(decreasedValue != null);
_decreasedValue = decreasedValue;
_hasBeenAnnotated = true;
}
/// The value that [value] will have after performing a
/// [SemanticsAction.increase] action.
///
/// This must be set if a handler for [SemanticsAction.increase] is provided
/// and [value] is set.
///
/// The reading direction is given by [textDirection].
String get increasedValue => _increasedValue;
String _increasedValue = '';
set increasedValue(String increasedValue) {
assert(increasedValue != null);
_increasedValue = increasedValue;
_hasBeenAnnotated = true;
}
/// A brief description of the result of performing an action on this node. /// A brief description of the result of performing an action on this node.
/// ///
/// On iOS this is used for the `accessibilityHint` property defined in the /// On iOS this is used for the `accessibilityHint` property defined in the
...@@ -1080,15 +1192,17 @@ class SemanticsConfiguration { ...@@ -1080,15 +1192,17 @@ class SemanticsConfiguration {
/// [label] and [value] in the following order: [value], [label], [hint]. /// [label] and [value] in the following order: [value], [label], [hint].
/// The concatenated value is then used as the `Text` description. /// The concatenated value is then used as the `Text` description.
/// ///
/// The text's reading direction is given by [textDirection]. /// The reading direction is given by [textDirection].
String get hint => _hint; String get hint => _hint;
String _hint = ''; String _hint = '';
set hint(String hint) { set hint(String hint) {
assert(hint != null);
_hint = hint; _hint = hint;
_hasBeenAnnotated = true; _hasBeenAnnotated = true;
} }
/// The reading direction for the text in [label], [value], and [hint]. /// The reading direction for the text in [label], [value], [hint],
/// [increasedValue], and [decreasedValue].
TextDirection get textDirection => _textDirection; TextDirection get textDirection => _textDirection;
TextDirection _textDirection; TextDirection _textDirection;
set textDirection(TextDirection textDirection) { set textDirection(TextDirection textDirection) {
...@@ -1182,8 +1296,12 @@ class SemanticsConfiguration { ...@@ -1182,8 +1296,12 @@ class SemanticsConfiguration {
otherString: other._label, otherString: other._label,
otherTextDirection: other.textDirection, otherTextDirection: other.textDirection,
); );
if (_decreasedValue == '' || _decreasedValue == null)
_decreasedValue = other._decreasedValue;
if (_value == '' || _value == null) if (_value == '' || _value == null)
_value = other._value; _value = other._value;
if (_increasedValue == '' || _increasedValue == null)
_increasedValue = other._increasedValue;
_hint = _concatStrings( _hint = _concatStrings(
thisString: _hint, thisString: _hint,
thisTextDirection: textDirection, thisTextDirection: textDirection,
...@@ -1202,7 +1320,9 @@ class SemanticsConfiguration { ...@@ -1202,7 +1320,9 @@ class SemanticsConfiguration {
.._hasBeenAnnotated = _hasBeenAnnotated .._hasBeenAnnotated = _hasBeenAnnotated
.._textDirection = _textDirection .._textDirection = _textDirection
.._label = _label .._label = _label
.._increasedValue = _increasedValue
.._value = _value .._value = _value
.._decreasedValue = _decreasedValue
.._hint = _hint .._hint = _hint
.._flags = _flags .._flags = _flags
.._actionsAsBits = _actionsAsBits .._actionsAsBits = _actionsAsBits
......
...@@ -4454,6 +4454,8 @@ class Semantics extends SingleChildRenderObjectWidget { ...@@ -4454,6 +4454,8 @@ class Semantics extends SingleChildRenderObjectWidget {
this.button, this.button,
this.label, this.label,
this.value, this.value,
this.increasedValue,
this.decreasedValue,
this.hint, this.hint,
this.textDirection, this.textDirection,
this.onTap, this.onTap,
...@@ -4528,6 +4530,30 @@ class Semantics extends SingleChildRenderObjectWidget { ...@@ -4528,6 +4530,30 @@ class Semantics extends SingleChildRenderObjectWidget {
/// in TalkBack and VoiceOver. /// in TalkBack and VoiceOver.
final String value; final String value;
/// The value that [value] will become after a [SemanticsAction.increase]
/// action has been performed on this widget.
///
/// If a value is provided, [onIncrease] must also be set and there must
/// either be an ambient [Directionality] or an explicit [textDirection]
/// must be provided.
///
/// See also:
/// * [SemanticsConfiguration.increasedValue] for a description of how this
/// is exposed in TalkBack and VoiceOver.
final String increasedValue;
/// The value that [value] will become after a [SemanticsAction.decrease]
/// action has been performed on this widget.
///
/// If a value is provided, [onDecrease] must also be set and there must
/// either be an ambient [Directionality] or an explicit [textDirection]
/// must be provided.
///
/// See also:
/// * [SemanticsConfiguration.decreasedValue] for a description of how this
/// is exposed in TalkBack and VoiceOver.
final String decreasedValue;
/// Provides a brief textual description of the result of an action performed /// Provides a brief textual description of the result of an action performed
/// on the widget. /// on the widget.
/// ///
...@@ -4539,7 +4565,8 @@ class Semantics extends SingleChildRenderObjectWidget { ...@@ -4539,7 +4565,8 @@ class Semantics extends SingleChildRenderObjectWidget {
/// in TalkBack and VoiceOver. /// in TalkBack and VoiceOver.
final String hint; final String hint;
/// The reading direction of the [label], [value], and [hint]. /// The reading direction of the [label], [value], [hint], [increasedValue],
/// and [decreasedValue].
/// ///
/// Defaults to the ambient [Directionality]. /// Defaults to the ambient [Directionality].
final TextDirection textDirection; final TextDirection textDirection;
...@@ -4625,6 +4652,9 @@ class Semantics extends SingleChildRenderObjectWidget { ...@@ -4625,6 +4652,9 @@ class Semantics extends SingleChildRenderObjectWidget {
/// This is a request to increase the value represented by the widget. For /// This is a request to increase the value represented by the widget. For
/// example, this action might be recognized by a slider control. /// example, this action might be recognized by a slider control.
/// ///
/// If a [value] is set, [increasedValue] must also be provided and
/// [onIncrease] must ensure that [value] will be set to [increasedValue].
///
/// VoiceOver users on iOS can trigger this action by swiping up with one /// VoiceOver users on iOS can trigger this action by swiping up with one
/// finger. TalkBack users on Android can trigger this action by pressing the /// finger. TalkBack users on Android can trigger this action by pressing the
/// volume up button. /// volume up button.
...@@ -4635,6 +4665,9 @@ class Semantics extends SingleChildRenderObjectWidget { ...@@ -4635,6 +4665,9 @@ class Semantics extends SingleChildRenderObjectWidget {
/// This is a request to decrease the value represented by the widget. For /// This is a request to decrease the value represented by the widget. For
/// example, this action might be recognized by a slider control. /// example, this action might be recognized by a slider control.
/// ///
/// If a [value] is set, [decreasedValue] must also be provided and
/// [onDecrease] must ensure that [value] will be set to [decreasedValue].
///
/// VoiceOver users on iOS can trigger this action by swiping down with one /// VoiceOver users on iOS can trigger this action by swiping down with one
/// finger. TalkBack users on Android can trigger this action by pressing the /// finger. TalkBack users on Android can trigger this action by pressing the
/// volume down button. /// volume down button.
...@@ -4650,6 +4683,8 @@ class Semantics extends SingleChildRenderObjectWidget { ...@@ -4650,6 +4683,8 @@ class Semantics extends SingleChildRenderObjectWidget {
button: button, button: button,
label: label, label: label,
value: value, value: value,
increasedValue: increasedValue,
decreasedValue: decreasedValue,
hint: hint, hint: hint,
textDirection: _getTextDirection(context), textDirection: _getTextDirection(context),
onTap: onTap, onTap: onTap,
...@@ -4672,6 +4707,8 @@ class Semantics extends SingleChildRenderObjectWidget { ...@@ -4672,6 +4707,8 @@ class Semantics extends SingleChildRenderObjectWidget {
..selected = selected ..selected = selected
..label = label ..label = label
..value = value ..value = value
..increasedValue = increasedValue
..decreasedValue = decreasedValue
..hint = hint ..hint = hint
..textDirection = _getTextDirection(context) ..textDirection = _getTextDirection(context)
..onTap = onTap ..onTap = onTap
......
...@@ -198,7 +198,7 @@ void main() { ...@@ -198,7 +198,7 @@ void main() {
expect( expect(
minimalProperties.toStringDeep(minLevel: DiagnosticLevel.hidden), minimalProperties.toStringDeep(minLevel: DiagnosticLevel.hidden),
'SemanticsNode#16(owner: null, isPartOfNodeMerging: false, Rect.fromLTRB(0.0, 0.0, 0.0, 0.0), actions: [], isSelected: false, isButton: false, label: "", value: "", hint: "", textDirection: null)\n', 'SemanticsNode#16(owner: null, isPartOfNodeMerging: false, Rect.fromLTRB(0.0, 0.0, 0.0, 0.0), actions: [], isSelected: false, isButton: false, label: "", value: "", increasedValue: "", decreasedValue: "", hint: "", textDirection: null)\n',
); );
final SemanticsConfiguration config = new SemanticsConfiguration() final SemanticsConfiguration config = new SemanticsConfiguration()
......
...@@ -513,4 +513,36 @@ void main() { ...@@ -513,4 +513,36 @@ void main() {
semantics.dispose(); semantics.dispose();
}); });
testWidgets('Increased/decreased values are annotated', (WidgetTester tester) async {
final SemanticsTester semantics = new SemanticsTester(tester);
await tester.pumpWidget(
new Directionality(
textDirection: TextDirection.ltr,
child: new Semantics(
container: true,
value: '10s',
increasedValue: '11s',
decreasedValue: '9s',
onIncrease: () => () {},
onDecrease: () => () {},
),
),
);
expect(semantics, hasSemantics(new TestSemantics.root(
children: <TestSemantics>[
new TestSemantics.rootChild(
actions: SemanticsAction.increase.index | SemanticsAction.decrease.index,
textDirection: TextDirection.ltr,
value: '10s',
increasedValue: '11s',
decreasedValue: '9s',
),
],
), ignoreTransform: true, ignoreRect: true, ignoreId: true));
semantics.dispose();
});
} }
...@@ -36,6 +36,8 @@ class TestSemantics { ...@@ -36,6 +36,8 @@ class TestSemantics {
this.actions: 0, this.actions: 0,
this.label: '', this.label: '',
this.value: '', this.value: '',
this.increasedValue: '',
this.decreasedValue: '',
this.hint: '', this.hint: '',
this.textDirection, this.textDirection,
this.rect, this.rect,
...@@ -45,6 +47,8 @@ class TestSemantics { ...@@ -45,6 +47,8 @@ class TestSemantics {
}) : assert(flags != null), }) : assert(flags != null),
assert(label != null), assert(label != null),
assert(value != null), assert(value != null),
assert(increasedValue != null),
assert(decreasedValue != null),
assert(hint != null), assert(hint != null),
assert(children != null), assert(children != null),
tags = tags?.toSet() ?? new Set<SemanticsTag>(); tags = tags?.toSet() ?? new Set<SemanticsTag>();
...@@ -56,6 +60,8 @@ class TestSemantics { ...@@ -56,6 +60,8 @@ class TestSemantics {
this.actions: 0, this.actions: 0,
this.label: '', this.label: '',
this.value: '', this.value: '',
this.increasedValue: '',
this.decreasedValue: '',
this.hint: '', this.hint: '',
this.textDirection, this.textDirection,
this.transform, this.transform,
...@@ -64,6 +70,8 @@ class TestSemantics { ...@@ -64,6 +70,8 @@ class TestSemantics {
}) : id = 0, }) : id = 0,
assert(flags != null), assert(flags != null),
assert(label != null), assert(label != null),
assert(increasedValue != null),
assert(decreasedValue != null),
assert(value != null), assert(value != null),
assert(hint != null), assert(hint != null),
rect = TestSemantics.rootRect, rect = TestSemantics.rootRect,
...@@ -86,6 +94,8 @@ class TestSemantics { ...@@ -86,6 +94,8 @@ class TestSemantics {
this.label: '', this.label: '',
this.hint: '', this.hint: '',
this.value: '', this.value: '',
this.increasedValue: '',
this.decreasedValue: '',
this.textDirection, this.textDirection,
this.rect, this.rect,
Matrix4 transform, Matrix4 transform,
...@@ -94,6 +104,8 @@ class TestSemantics { ...@@ -94,6 +104,8 @@ class TestSemantics {
}) : assert(flags != null), }) : assert(flags != null),
assert(label != null), assert(label != null),
assert(value != null), assert(value != null),
assert(increasedValue != null),
assert(decreasedValue != null),
assert(hint != null), assert(hint != null),
transform = _applyRootChildScale(transform), transform = _applyRootChildScale(transform),
assert(children != null), assert(children != null),
...@@ -117,6 +129,14 @@ class TestSemantics { ...@@ -117,6 +129,14 @@ class TestSemantics {
/// A textual description for the value of this node. /// A textual description for the value of this node.
final String value; final String value;
/// What [value] will become after [SemanticsAction.increase] has been
/// performed.
final String increasedValue;
/// What [value] will become after [SemanticsAction.decrease] has been
/// performed.
final String decreasedValue;
/// A brief textual description of the result of the action that can be /// A brief textual description of the result of the action that can be
/// performed on this node. /// performed on this node.
final String hint; final String hint;
...@@ -190,11 +210,15 @@ class TestSemantics { ...@@ -190,11 +210,15 @@ class TestSemantics {
return fail('expected node id $id to have label "$label" but found label "${nodeData.label}".'); return fail('expected node id $id to have label "$label" but found label "${nodeData.label}".');
if (value != nodeData.value) if (value != nodeData.value)
return fail('expected node id $id to have value "$value" but found value "${nodeData.value}".'); return fail('expected node id $id to have value "$value" but found value "${nodeData.value}".');
if (increasedValue != nodeData.increasedValue)
return fail('expected node id $id to have increasedValue "$increasedValue" but found value "${nodeData.increasedValue}".');
if (decreasedValue != nodeData.decreasedValue)
return fail('expected node id $id to have decreasedValue "$decreasedValue" but found value "${nodeData.decreasedValue}".');
if (hint != nodeData.hint) if (hint != nodeData.hint)
return fail('expected node id $id to have hint "$hint" but found hint "${nodeData.hint}".'); return fail('expected node id $id to have hint "$hint" but found hint "${nodeData.hint}".');
if (textDirection != null && textDirection != nodeData.textDirection) if (textDirection != null && textDirection != nodeData.textDirection)
return fail('expected node id $id to have textDirection "$textDirection" but found "${nodeData.textDirection}".'); return fail('expected node id $id to have textDirection "$textDirection" but found "${nodeData.textDirection}".');
if ((nodeData.label != '' || nodeData.value != '' || nodeData.hint != '') && nodeData.textDirection == null) if ((nodeData.label != '' || nodeData.value != '' || nodeData.hint != '' || node.increasedValue != '' || node.decreasedValue != '') && nodeData.textDirection == null)
return fail('expected node id $id, which has a label, value, or hint, to have a textDirection, but it did not.'); return fail('expected node id $id, which has a label, value, or hint, to have a textDirection, but it did not.');
if (!ignoreRect && rect != nodeData.rect) if (!ignoreRect && rect != nodeData.rect)
return fail('expected node id $id to have rect $rect but found rect ${nodeData.rect}.'); return fail('expected node id $id to have rect $rect but found rect ${nodeData.rect}.');
......
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