Fix semantic sort name (#48920)
This commit is contained in:
parent
8b2993337a
commit
1a3379d571
@ -3981,30 +3981,18 @@ String _concatStrings({
|
|||||||
return '$thisString\n$nestedLabel';
|
return '$thisString\n$nestedLabel';
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Base class for all sort keys for [Semantics] accessibility traversal order
|
/// Base class for all sort keys for [SemanticsProperties.sortKey] accessibility
|
||||||
/// sorting.
|
/// traversal order sorting.
|
||||||
///
|
///
|
||||||
/// Only keys of the same type and having matching [name]s are compared. If a
|
/// Sort keys are sorted by [name], then by the comparison that the subclass
|
||||||
/// list of sibling [SemanticsNode]s contains keys that are not comparable with
|
/// implements. If [SemanticsProperties.sortKey] is specified, sort keys within
|
||||||
/// each other the list is first sorted using the default sorting algorithm.
|
/// the same semantic group must all be of the same type.
|
||||||
/// Then the nodes are broken down into groups by moving comparable nodes
|
|
||||||
/// towards the _earliest_ node in the group. Finally each group is sorted by
|
|
||||||
/// sort key and the resulting list is made by concatenating the sorted groups
|
|
||||||
/// back.
|
|
||||||
///
|
///
|
||||||
/// For example, let's take nodes (C, D, B, E, A, F). Let's assign node A key 1,
|
/// Keys with no [name] are compared to other keys with no [name], and will
|
||||||
/// node B key 2, node C key 3. Let's also assume that the default sort order
|
/// be traversed before those with a [name].
|
||||||
/// leaves the original list intact. Because nodes A, B, and C, have comparable
|
|
||||||
/// sort key, they will form a group by pulling all nodes towards the earliest
|
|
||||||
/// node, which is C. The result is group (C, B, A). The remaining nodes D, E,
|
|
||||||
/// F, form a second group with sort key being `null`. The first group is sorted
|
|
||||||
/// using their sort keys becoming (A, B, C). The second group is left as is
|
|
||||||
/// because it does not specify sort keys. Then we concatenate the two groups -
|
|
||||||
/// (A, B, C) and (D, E, F) - into the final (A, B, C, D, E, F).
|
|
||||||
///
|
///
|
||||||
/// Because of the complexity introduced by incomparable sort keys among sibling
|
/// If no sort key is applied to a semantics node, then it will be ordered using
|
||||||
/// nodes, it is recommended to either use comparable keys for all nodes, or
|
/// a platform dependent default algorithm.
|
||||||
/// use null for all of them, leaving the sort order to the default algorithm.
|
|
||||||
///
|
///
|
||||||
/// See also:
|
/// See also:
|
||||||
///
|
///
|
||||||
@ -4014,17 +4002,35 @@ abstract class SemanticsSortKey extends Diagnosticable implements Comparable<Sem
|
|||||||
/// const constructors so that they can be used in const expressions.
|
/// const constructors so that they can be used in const expressions.
|
||||||
const SemanticsSortKey({this.name});
|
const SemanticsSortKey({this.name});
|
||||||
|
|
||||||
/// An optional name that will make this sort key only order itself
|
/// An optional name that will group this sort key with other sort keys of the
|
||||||
/// with respect to other sort keys of the same [name], as long as
|
/// same [name].
|
||||||
/// they are of the same [runtimeType].
|
///
|
||||||
|
/// Sort keys must have the same `runtimeType` when compared.
|
||||||
|
///
|
||||||
|
/// Keys with no [name] are compared to other keys with no [name], and will
|
||||||
|
/// be traversed before those with a [name].
|
||||||
final String name;
|
final String name;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int compareTo(SemanticsSortKey other) {
|
int compareTo(SemanticsSortKey other) {
|
||||||
// The sorting algorithm must not compare incomparable keys.
|
// Sort by name first and then subclass ordering.
|
||||||
assert(runtimeType == other.runtimeType);
|
assert(runtimeType == other.runtimeType, 'Semantics sort keys can only be compared to other sort keys of the same type.');
|
||||||
assert(name == other.name);
|
|
||||||
return doCompare(other);
|
// Defer to the subclass implementation for ordering only if the names are
|
||||||
|
// identical (or both null).
|
||||||
|
if (name == other.name) {
|
||||||
|
return doCompare(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keys that don't have a name are sorted together and come before those with
|
||||||
|
// a name.
|
||||||
|
if (name == null && other.name != null) {
|
||||||
|
return -1;
|
||||||
|
} else if (name != null && other.name == null) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return name.compareTo(other.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The implementation of [compareTo].
|
/// The implementation of [compareTo].
|
||||||
@ -4052,14 +4058,22 @@ abstract class SemanticsSortKey extends Diagnosticable implements Comparable<Sem
|
|||||||
/// The [OrdinalSortKey] compares itself with other [OrdinalSortKey]s
|
/// The [OrdinalSortKey] compares itself with other [OrdinalSortKey]s
|
||||||
/// to sort based on the order it is given.
|
/// to sort based on the order it is given.
|
||||||
///
|
///
|
||||||
/// The ordinal value `order` is typically a whole number, though it can be
|
/// [OrdinalSortKey]s are sorted by the optional [name], then by their [order].
|
||||||
|
/// If [SemanticsProperties.sortKey] is a [OrdinalSortKey], then all the other
|
||||||
|
/// speficied sort keys in the same semantics group must also be
|
||||||
|
/// [OrdinalSortKey]s.
|
||||||
|
///
|
||||||
|
/// Keys with no [name] are compared to other keys with no [name], and will
|
||||||
|
/// be traversed before those with a [name].
|
||||||
|
///
|
||||||
|
/// The ordinal value [order] is typically a whole number, though it can be
|
||||||
/// fractional, e.g. in order to fit between two other consecutive whole
|
/// fractional, e.g. in order to fit between two other consecutive whole
|
||||||
/// numbers. The value must be finite (it cannot be [double.nan],
|
/// numbers. The value must be finite (it cannot be [double.nan],
|
||||||
/// [double.infinity], or [double.negativeInfinity]).
|
/// [double.infinity], or [double.negativeInfinity]).
|
||||||
class OrdinalSortKey extends SemanticsSortKey {
|
class OrdinalSortKey extends SemanticsSortKey {
|
||||||
/// Creates a semantics sort key that uses a [double] as its key value.
|
/// Creates a const semantics sort key that uses a [double] as its key value.
|
||||||
///
|
///
|
||||||
/// The [order] must be a finite number.
|
/// The [order] must be a finite number, and must not be null.
|
||||||
const OrdinalSortKey(
|
const OrdinalSortKey(
|
||||||
this.order, {
|
this.order, {
|
||||||
String name,
|
String name,
|
||||||
@ -4073,7 +4087,8 @@ class OrdinalSortKey extends SemanticsSortKey {
|
|||||||
/// the order in which this node is traversed by the platform's accessibility
|
/// the order in which this node is traversed by the platform's accessibility
|
||||||
/// services.
|
/// services.
|
||||||
///
|
///
|
||||||
/// Lower values will be traversed first.
|
/// Lower values will be traversed first. Keys with the same [name] will be
|
||||||
|
/// grouped together and sorted by name first, and then sorted by [order].
|
||||||
final double order;
|
final double order;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -247,36 +247,50 @@ void main() {
|
|||||||
expect(() {
|
expect(() {
|
||||||
const OrdinalSortKey(0.0).compareTo(const CustomSortKey(0.0));
|
const OrdinalSortKey(0.0).compareTo(const CustomSortKey(0.0));
|
||||||
}, throwsAssertionError);
|
}, throwsAssertionError);
|
||||||
|
|
||||||
// Different names.
|
|
||||||
expect(() {
|
|
||||||
const OrdinalSortKey(0.0, name: 'a').compareTo(const OrdinalSortKey(0.0, name: 'b'));
|
|
||||||
}, throwsAssertionError);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('OrdinalSortKey compares correctly', () {
|
test('OrdinalSortKey compares correctly when names are the same', () {
|
||||||
const List<List<SemanticsSortKey>> tests = <List<SemanticsSortKey>>[
|
const List<List<SemanticsSortKey>> tests = <List<SemanticsSortKey>>[
|
||||||
<SemanticsSortKey>[OrdinalSortKey(0.0), OrdinalSortKey(0.0)],
|
<SemanticsSortKey>[OrdinalSortKey(0.0), OrdinalSortKey(0.0)],
|
||||||
<SemanticsSortKey>[OrdinalSortKey(0.0), OrdinalSortKey(1.0)],
|
<SemanticsSortKey>[OrdinalSortKey(0.0), OrdinalSortKey(1.0)],
|
||||||
<SemanticsSortKey>[OrdinalSortKey(1.0), OrdinalSortKey(0.0)],
|
<SemanticsSortKey>[OrdinalSortKey(1.0), OrdinalSortKey(0.0)],
|
||||||
<SemanticsSortKey>[OrdinalSortKey(1.0), OrdinalSortKey(1.0)],
|
<SemanticsSortKey>[OrdinalSortKey(1.0), OrdinalSortKey(1.0)],
|
||||||
|
<SemanticsSortKey>[OrdinalSortKey(0.0, name: 'a'), OrdinalSortKey(0.0, name: 'a')],
|
||||||
|
<SemanticsSortKey>[OrdinalSortKey(0.0, name: 'a'), OrdinalSortKey(1.0, name: 'a')],
|
||||||
|
<SemanticsSortKey>[OrdinalSortKey(1.0, name: 'a'), OrdinalSortKey(0.0, name: 'a')],
|
||||||
|
<SemanticsSortKey>[OrdinalSortKey(1.0, name: 'a'), OrdinalSortKey(1.0, name: 'a')],
|
||||||
];
|
];
|
||||||
final List<int> expectedResults = <int>[0, -1, 1, 0];
|
final List<int> expectedResults = <int>[0, -1, 1, 0, 0, -1, 1, 0];
|
||||||
assert(tests.length == expectedResults.length);
|
assert(tests.length == expectedResults.length);
|
||||||
final List<int> results = <int>[
|
final List<int> results = <int>[
|
||||||
for (final List<SemanticsSortKey> tuple in tests) tuple[0].compareTo(tuple[1]),
|
for (final List<SemanticsSortKey> tuple in tests) tuple[0].compareTo(tuple[1]),
|
||||||
];
|
];
|
||||||
expect(results, orderedEquals(expectedResults));
|
expect(results, orderedEquals(expectedResults));
|
||||||
|
|
||||||
|
// Differing types should throw an assertion.
|
||||||
|
expect(() => const OrdinalSortKey(0.0).compareTo(const CustomSortKey(0.0)), throwsAssertionError);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('OrdinalSortKey compares correctly', () {
|
test('OrdinalSortKey compares correctly when the names are different', () {
|
||||||
const List<List<SemanticsSortKey>> tests = <List<SemanticsSortKey>>[
|
const List<List<SemanticsSortKey>> tests = <List<SemanticsSortKey>>[
|
||||||
<SemanticsSortKey>[OrdinalSortKey(0.0), OrdinalSortKey(0.0)],
|
<SemanticsSortKey>[OrdinalSortKey(0.0), OrdinalSortKey(0.0, name: 'bar')],
|
||||||
<SemanticsSortKey>[OrdinalSortKey(0.0), OrdinalSortKey(1.0)],
|
<SemanticsSortKey>[OrdinalSortKey(0.0), OrdinalSortKey(1.0, name: 'bar')],
|
||||||
<SemanticsSortKey>[OrdinalSortKey(1.0), OrdinalSortKey(0.0)],
|
<SemanticsSortKey>[OrdinalSortKey(1.0), OrdinalSortKey(0.0, name: 'bar')],
|
||||||
<SemanticsSortKey>[OrdinalSortKey(1.0), OrdinalSortKey(1.0)],
|
<SemanticsSortKey>[OrdinalSortKey(1.0), OrdinalSortKey(1.0, name: 'bar')],
|
||||||
|
<SemanticsSortKey>[OrdinalSortKey(0.0, name: 'foo'), OrdinalSortKey(0.0)],
|
||||||
|
<SemanticsSortKey>[OrdinalSortKey(0.0, name: 'foo'), OrdinalSortKey(1.0)],
|
||||||
|
<SemanticsSortKey>[OrdinalSortKey(1.0, name: 'foo'), OrdinalSortKey(0.0)],
|
||||||
|
<SemanticsSortKey>[OrdinalSortKey(1.0, name: 'foo'), OrdinalSortKey(1.0)],
|
||||||
|
<SemanticsSortKey>[OrdinalSortKey(0.0, name: 'foo'), OrdinalSortKey(0.0, name: 'bar')],
|
||||||
|
<SemanticsSortKey>[OrdinalSortKey(0.0, name: 'foo'), OrdinalSortKey(1.0, name: 'bar')],
|
||||||
|
<SemanticsSortKey>[OrdinalSortKey(1.0, name: 'foo'), OrdinalSortKey(0.0, name: 'bar')],
|
||||||
|
<SemanticsSortKey>[OrdinalSortKey(1.0, name: 'foo'), OrdinalSortKey(1.0, name: 'bar')],
|
||||||
|
<SemanticsSortKey>[OrdinalSortKey(0.0, name: 'bar'), OrdinalSortKey(0.0, name: 'foo')],
|
||||||
|
<SemanticsSortKey>[OrdinalSortKey(0.0, name: 'bar'), OrdinalSortKey(1.0, name: 'foo')],
|
||||||
|
<SemanticsSortKey>[OrdinalSortKey(1.0, name: 'bar'), OrdinalSortKey(0.0, name: 'foo')],
|
||||||
|
<SemanticsSortKey>[OrdinalSortKey(1.0, name: 'bar'), OrdinalSortKey(1.0, name: 'foo')],
|
||||||
];
|
];
|
||||||
final List<int> expectedResults = <int>[0, -1, 1, 0];
|
final List<int> expectedResults = <int>[ -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1];
|
||||||
assert(tests.length == expectedResults.length);
|
assert(tests.length == expectedResults.length);
|
||||||
final List<int> results = <int>[
|
final List<int> results = <int>[
|
||||||
for (final List<SemanticsSortKey> tuple in tests) tuple[0].compareTo(tuple[1]),
|
for (final List<SemanticsSortKey> tuple in tests) tuple[0].compareTo(tuple[1]),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user