From 1a3379d5714d3242336cf27d5ad194a4c5886a9e Mon Sep 17 00:00:00 2001 From: Greg Spencer Date: Mon, 27 Jan 2020 16:13:02 -0800 Subject: [PATCH] Fix semantic sort name (#48920) --- .../flutter/lib/src/semantics/semantics.dart | 79 +++++++++++-------- .../test/semantics/semantics_test.dart | 40 +++++++--- 2 files changed, 74 insertions(+), 45 deletions(-) diff --git a/packages/flutter/lib/src/semantics/semantics.dart b/packages/flutter/lib/src/semantics/semantics.dart index 609219e360..148a473aa8 100644 --- a/packages/flutter/lib/src/semantics/semantics.dart +++ b/packages/flutter/lib/src/semantics/semantics.dart @@ -3981,30 +3981,18 @@ String _concatStrings({ return '$thisString\n$nestedLabel'; } -/// Base class for all sort keys for [Semantics] accessibility traversal order -/// sorting. +/// Base class for all sort keys for [SemanticsProperties.sortKey] accessibility +/// traversal order sorting. /// -/// Only keys of the same type and having matching [name]s are compared. If a -/// list of sibling [SemanticsNode]s contains keys that are not comparable with -/// each other the list is first sorted using the default sorting algorithm. -/// 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. +/// Sort keys are sorted by [name], then by the comparison that the subclass +/// implements. If [SemanticsProperties.sortKey] is specified, sort keys within +/// the same semantic group must all be of the same type. /// -/// For example, let's take nodes (C, D, B, E, A, F). Let's assign node A key 1, -/// node B key 2, node C key 3. Let's also assume that the default sort order -/// 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). +/// Keys with no [name] are compared to other keys with no [name], and will +/// be traversed before those with a [name]. /// -/// Because of the complexity introduced by incomparable sort keys among sibling -/// nodes, it is recommended to either use comparable keys for all nodes, or -/// use null for all of them, leaving the sort order to the default algorithm. +/// If no sort key is applied to a semantics node, then it will be ordered using +/// a platform dependent default algorithm. /// /// See also: /// @@ -4014,17 +4002,35 @@ abstract class SemanticsSortKey extends Diagnosticable implements Comparable> tests = >[ [OrdinalSortKey(0.0), OrdinalSortKey(0.0)], [OrdinalSortKey(0.0), OrdinalSortKey(1.0)], [OrdinalSortKey(1.0), OrdinalSortKey(0.0)], [OrdinalSortKey(1.0), OrdinalSortKey(1.0)], + [OrdinalSortKey(0.0, name: 'a'), OrdinalSortKey(0.0, name: 'a')], + [OrdinalSortKey(0.0, name: 'a'), OrdinalSortKey(1.0, name: 'a')], + [OrdinalSortKey(1.0, name: 'a'), OrdinalSortKey(0.0, name: 'a')], + [OrdinalSortKey(1.0, name: 'a'), OrdinalSortKey(1.0, name: 'a')], ]; - final List expectedResults = [0, -1, 1, 0]; + final List expectedResults = [0, -1, 1, 0, 0, -1, 1, 0]; assert(tests.length == expectedResults.length); final List results = [ for (final List tuple in tests) tuple[0].compareTo(tuple[1]), ]; 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> tests = >[ - [OrdinalSortKey(0.0), OrdinalSortKey(0.0)], - [OrdinalSortKey(0.0), OrdinalSortKey(1.0)], - [OrdinalSortKey(1.0), OrdinalSortKey(0.0)], - [OrdinalSortKey(1.0), OrdinalSortKey(1.0)], + [OrdinalSortKey(0.0), OrdinalSortKey(0.0, name: 'bar')], + [OrdinalSortKey(0.0), OrdinalSortKey(1.0, name: 'bar')], + [OrdinalSortKey(1.0), OrdinalSortKey(0.0, name: 'bar')], + [OrdinalSortKey(1.0), OrdinalSortKey(1.0, name: 'bar')], + [OrdinalSortKey(0.0, name: 'foo'), OrdinalSortKey(0.0)], + [OrdinalSortKey(0.0, name: 'foo'), OrdinalSortKey(1.0)], + [OrdinalSortKey(1.0, name: 'foo'), OrdinalSortKey(0.0)], + [OrdinalSortKey(1.0, name: 'foo'), OrdinalSortKey(1.0)], + [OrdinalSortKey(0.0, name: 'foo'), OrdinalSortKey(0.0, name: 'bar')], + [OrdinalSortKey(0.0, name: 'foo'), OrdinalSortKey(1.0, name: 'bar')], + [OrdinalSortKey(1.0, name: 'foo'), OrdinalSortKey(0.0, name: 'bar')], + [OrdinalSortKey(1.0, name: 'foo'), OrdinalSortKey(1.0, name: 'bar')], + [OrdinalSortKey(0.0, name: 'bar'), OrdinalSortKey(0.0, name: 'foo')], + [OrdinalSortKey(0.0, name: 'bar'), OrdinalSortKey(1.0, name: 'foo')], + [OrdinalSortKey(1.0, name: 'bar'), OrdinalSortKey(0.0, name: 'foo')], + [OrdinalSortKey(1.0, name: 'bar'), OrdinalSortKey(1.0, name: 'foo')], ]; - final List expectedResults = [0, -1, 1, 0]; + final List expectedResults = [ -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1]; assert(tests.length == expectedResults.length); final List results = [ for (final List tuple in tests) tuple[0].compareTo(tuple[1]),