Skip to content

Commit

Permalink
Merge pull request #1422 from nextcloud/feat/sort_box/support_list_bu…
Browse files Browse the repository at this point in the history
…ilder

feat(sort_box): support sorting a ListBuilder
  • Loading branch information
Leptopoda authored Jan 5, 2024
2 parents 844ff0d + 78a41bd commit 3683491
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class SortBoxBuilder<T extends Enum, R> extends StatelessWidget {
valueListenable: sortBoxOrder,
builder: (context, order, _) {
final box = (property: property, order: order);
sortBox.sort(input, box, presort);
sortBox.sortList(input, box, presort);

return builder(context, input);
},
Expand Down
33 changes: 31 additions & 2 deletions packages/sort_box/lib/src/sort_box.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:built_collection/built_collection.dart';
import 'package:meta/meta.dart';

/// Signature of a function returning a [Comparable].
Expand Down Expand Up @@ -32,8 +33,10 @@ class SortBox<T extends Enum, R> {
/// A box contains the property and [SortBoxOrder] how the list should be sorted.
/// In case the property of two elements is considered equal all following boxes specified at `boxes[property]` are applied.
/// If specified [presort] will be applied before [box] and [boxes].
void sort(
///
/// See:
/// * [sortListBuilder] to sort a `ListBuilder` of a `BuiltList`
void sortList(
List<R> input,
Box<T> box, [
Set<Box<T>>? presort,
Expand All @@ -51,6 +54,32 @@ class SortBox<T extends Enum, R> {
input.sort((item1, item2) => _compare(item1, item2, boxes.iterator..moveNext()));
}

/// Sorts the [input] list according to their [box].
///
/// A box contains the property and [SortBoxOrder] how the list should be sorted.
/// In case the property of two elements is considered equal all following boxes specified at `boxes[property]` are applied.
/// If specified [presort] will be applied before [box] and [boxes].
///
/// See:
/// * [sortList] to sort a `List`
void sortListBuilder(
ListBuilder<R> input,
Box<T> box, [
Set<Box<T>>? presort,
]) {
if (input.length <= 1) {
return;
}

final boxes = {
...?presort,
box,
...?this.boxes[box.property],
};

input.sort((item1, item2) => _compare(item1, item2, boxes.iterator..moveNext()));
}

/// Iteratively compares two elements [item1] and [item2] according to the current box in [iterator].
int _compare(
R item1,
Expand Down
1 change: 1 addition & 0 deletions packages/sort_box/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ environment:
sdk: '>=3.1.0 <4.0.0'

dependencies:
built_collection: ^5.0.0
meta: ^1.0.0

dev_dependencies:
Expand Down
43 changes: 37 additions & 6 deletions packages/sort_box/test/sort_box_test.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:built_collection/built_collection.dart';
import 'package:sort_box/sort_box.dart';
import 'package:test/test.dart';

Expand Down Expand Up @@ -52,7 +53,7 @@ void main() {
const Fruit('Banana', 4),
const Fruit('Apple', 5),
];
sortBox.sort(fruits, (property: FruitSort.alphabetical, order: SortBoxOrder.ascending));
sortBox.sortList(fruits, (property: FruitSort.alphabetical, order: SortBoxOrder.ascending));

for (var i = 0; i < 3; i++) {
expect(fruits[i].name, 'Apple');
Expand All @@ -70,7 +71,7 @@ void main() {
const Fruit('Banana', 2),
const Fruit('Apple', 3),
];
sortBox.sort(fruits, (property: FruitSort.count, order: SortBoxOrder.ascending));
sortBox.sortList(fruits, (property: FruitSort.count, order: SortBoxOrder.ascending));

final names = ['Apple', 'Banana', 'Apple', 'Apple', 'Banana'];
for (var i = 0; i < 5; i++) {
Expand All @@ -91,7 +92,7 @@ void main() {
const Fruit('Banana', 1),
const Fruit('Apple', 2),
];
sortBox.sort(fruits, (property: FruitSort.count, order: SortBoxOrder.ascending));
sortBox.sortList(fruits, (property: FruitSort.count, order: SortBoxOrder.ascending));

final names = ['Apple', 'Banana', 'Apple', 'Apple', 'Banana'];
for (var i = 0; i < 5; i++) {
Expand All @@ -112,7 +113,7 @@ void main() {
const Fruit('Banana', 2),
const Fruit('Apple', 5),
];
sortBox.sort(fruits, (property: FruitSort.alphabetical, order: SortBoxOrder.ascending));
sortBox.sortList(fruits, (property: FruitSort.alphabetical, order: SortBoxOrder.ascending));

for (var i = 0; i < 3; i++) {
expect(fruits[i].name, 'Apple');
Expand All @@ -134,7 +135,7 @@ void main() {
const Fruit('Elderberry', 1),
const Fruit('Damson', 1),
];
sortBox.sort(fruits, (property: FruitSort.count, order: SortBoxOrder.ascending));
sortBox.sortList(fruits, (property: FruitSort.count, order: SortBoxOrder.ascending));

final names = ['Apple', 'Banana', 'Coconut', 'Damson', 'Elderberry'];
for (var i = 0; i < 5; i++) {
Expand All @@ -152,7 +153,7 @@ void main() {
const Fruit('Banana', 1, 3),
const Fruit('Apple', 2, 3),
];
sortBox.sort(fruits, (property: FruitSort.price, order: SortBoxOrder.ascending));
sortBox.sortList(fruits, (property: FruitSort.price, order: SortBoxOrder.ascending));

final price = [0, 2, 3, 3, 3];
for (var i = 0; i < 5; i++) {
Expand All @@ -170,4 +171,34 @@ void main() {
}
});
});

test('Sort BuiltList', () {
final fruits = BuiltList<Fruit>(const [
Fruit('Apple', 1, 3),
Fruit('Banana', 2, 2),
Fruit('Apple', 2, 0),
Fruit('Banana', 1, 3),
Fruit('Apple', 2, 3),
]);

// ignore: cascade_invocations
final sorted = fruits.rebuild((builder) {
sortBox.sortListBuilder(builder, (property: FruitSort.price, order: SortBoxOrder.ascending));
});

final price = [0, 2, 3, 3, 3];
for (var i = 0; i < 5; i++) {
expect(sorted[i].price, price[i]);
}

final names = ['Apple', 'Banana', 'Banana', 'Apple', 'Apple'];
for (var i = 0; i < 5; i++) {
expect(sorted[i].name, names[i]);
}

final counts = [2, 2, 1, 1, 2];
for (var i = 0; i < 5; i++) {
expect(sorted[i].count, counts[i]);
}
});
}

0 comments on commit 3683491

Please sign in to comment.