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 {
bool button,
String label,
String value,
String increasedValue,
String decreasedValue,
String hint,
TextDirection textDirection,
VoidCallback onTap,
......@@ -3195,6 +3197,8 @@ class RenderSemanticsAnnotations extends RenderProxyBox {
_button = button,
_label = label,
_value = value,
_increasedValue = increasedValue,
_decreasedValue = decreasedValue,
_hint = hint,
_textDirection = textDirection,
_onTap = onTap,
......@@ -3283,7 +3287,7 @@ class RenderSemanticsAnnotations extends RenderProxyBox {
/// 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 _label;
set label(String value) {
......@@ -3296,7 +3300,7 @@ class RenderSemanticsAnnotations extends RenderProxyBox {
/// 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 _value;
set value(String value) {
......@@ -3307,9 +3311,37 @@ class RenderSemanticsAnnotations extends RenderProxyBox {
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.
///
/// The text's reading direction is given by [textDirection].
/// The reading direction is given by [textDirection].
String get hint => _hint;
String _hint;
set hint(String value) {
......@@ -3322,7 +3354,8 @@ class RenderSemanticsAnnotations extends RenderProxyBox {
/// 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 _textDirection;
set textDirection(TextDirection value) {
......@@ -3499,6 +3532,15 @@ class RenderSemanticsAnnotations extends RenderProxyBox {
@override
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.explicitChildNodes = explicitChildNodes;
......@@ -3512,6 +3554,10 @@ class RenderSemanticsAnnotations extends RenderProxyBox {
config.label = label;
if (value != null)
config.value = value;
if (increasedValue != null)
config.increasedValue = increasedValue;
if (decreasedValue != null)
config.decreasedValue = decreasedValue;
if (hint != null)
config.hint = hint;
if (textDirection != null)
......
......@@ -4454,6 +4454,8 @@ class Semantics extends SingleChildRenderObjectWidget {
this.button,
this.label,
this.value,
this.increasedValue,
this.decreasedValue,
this.hint,
this.textDirection,
this.onTap,
......@@ -4528,6 +4530,30 @@ class Semantics extends SingleChildRenderObjectWidget {
/// in TalkBack and VoiceOver.
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
/// on the widget.
///
......@@ -4539,7 +4565,8 @@ class Semantics extends SingleChildRenderObjectWidget {
/// in TalkBack and VoiceOver.
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].
final TextDirection textDirection;
......@@ -4625,6 +4652,9 @@ class Semantics extends SingleChildRenderObjectWidget {
/// This is a request to increase the value represented by the widget. For
/// 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
/// finger. TalkBack users on Android can trigger this action by pressing the
/// volume up button.
......@@ -4635,6 +4665,9 @@ class Semantics extends SingleChildRenderObjectWidget {
/// This is a request to decrease the value represented by the widget. For
/// 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
/// finger. TalkBack users on Android can trigger this action by pressing the
/// volume down button.
......@@ -4650,6 +4683,8 @@ class Semantics extends SingleChildRenderObjectWidget {
button: button,
label: label,
value: value,
increasedValue: increasedValue,
decreasedValue: decreasedValue,
hint: hint,
textDirection: _getTextDirection(context),
onTap: onTap,
......@@ -4672,6 +4707,8 @@ class Semantics extends SingleChildRenderObjectWidget {
..selected = selected
..label = label
..value = value
..increasedValue = increasedValue
..decreasedValue = decreasedValue
..hint = hint
..textDirection = _getTextDirection(context)
..onTap = onTap
......
......@@ -198,7 +198,7 @@ void main() {
expect(
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()
......
......@@ -513,4 +513,36 @@ void main() {
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 {
this.actions: 0,
this.label: '',
this.value: '',
this.increasedValue: '',
this.decreasedValue: '',
this.hint: '',
this.textDirection,
this.rect,
......@@ -45,6 +47,8 @@ class TestSemantics {
}) : assert(flags != null),
assert(label != null),
assert(value != null),
assert(increasedValue != null),
assert(decreasedValue != null),
assert(hint != null),
assert(children != null),
tags = tags?.toSet() ?? new Set<SemanticsTag>();
......@@ -56,6 +60,8 @@ class TestSemantics {
this.actions: 0,
this.label: '',
this.value: '',
this.increasedValue: '',
this.decreasedValue: '',
this.hint: '',
this.textDirection,
this.transform,
......@@ -64,6 +70,8 @@ class TestSemantics {
}) : id = 0,
assert(flags != null),
assert(label != null),
assert(increasedValue != null),
assert(decreasedValue != null),
assert(value != null),
assert(hint != null),
rect = TestSemantics.rootRect,
......@@ -86,6 +94,8 @@ class TestSemantics {
this.label: '',
this.hint: '',
this.value: '',
this.increasedValue: '',
this.decreasedValue: '',
this.textDirection,
this.rect,
Matrix4 transform,
......@@ -94,6 +104,8 @@ class TestSemantics {
}) : assert(flags != null),
assert(label != null),
assert(value != null),
assert(increasedValue != null),
assert(decreasedValue != null),
assert(hint != null),
transform = _applyRootChildScale(transform),
assert(children != null),
......@@ -117,6 +129,14 @@ class TestSemantics {
/// A textual description for the value of this node.
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
/// performed on this node.
final String hint;
......@@ -190,11 +210,15 @@ class TestSemantics {
return fail('expected node id $id to have label "$label" but found label "${nodeData.label}".');
if (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)
return fail('expected node id $id to have hint "$hint" but found hint "${nodeData.hint}".');
if (textDirection != null && textDirection != 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.');
if (!ignoreRect && 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