From a7d861f0a167b21f00d89eed46219ec001c96608 Mon Sep 17 00:00:00 2001 From: Nikolas Rimikis Date: Fri, 18 Aug 2023 11:40:56 +0200 Subject: [PATCH] feat(sort_box,neon_files,neon_news,neon_notes): recursive sort Signed-off-by: Nikolas Rimikis --- packages/neon/neon_files/lib/sort/files.dart | 8 +- .../neon/neon_news/lib/sort/articles.dart | 8 +- packages/neon/neon_news/lib/sort/feeds.dart | 8 +- packages/neon/neon_news/lib/sort/folders.dart | 8 +- .../neon/neon_notes/lib/sort/categories.dart | 4 +- packages/neon/neon_notes/lib/sort/notes.dart | 4 +- packages/sort_box/lib/sort_box.dart | 42 ++++---- packages/sort_box/test/sort_box_test.dart | 100 ++++++++++++------ 8 files changed, 122 insertions(+), 60 deletions(-) diff --git a/packages/neon/neon_files/lib/sort/files.dart b/packages/neon/neon_files/lib/sort/files.dart index 1f65ac7c..aba203b7 100644 --- a/packages/neon/neon_files/lib/sort/files.dart +++ b/packages/neon/neon_files/lib/sort/files.dart @@ -7,7 +7,11 @@ final filesSortBox = SortBox( FilesSortProperty.size: (final file) => file.size ?? 0, }, { - FilesSortProperty.modifiedDate: Box(FilesSortProperty.name, SortBoxOrder.ascending), - FilesSortProperty.size: Box(FilesSortProperty.name, SortBoxOrder.ascending), + FilesSortProperty.modifiedDate: { + Box(FilesSortProperty.name, SortBoxOrder.ascending), + }, + FilesSortProperty.size: { + Box(FilesSortProperty.name, SortBoxOrder.ascending), + }, }, ); diff --git a/packages/neon/neon_news/lib/sort/articles.dart b/packages/neon/neon_news/lib/sort/articles.dart index ff1087ba..18f69a15 100644 --- a/packages/neon/neon_news/lib/sort/articles.dart +++ b/packages/neon/neon_news/lib/sort/articles.dart @@ -7,7 +7,11 @@ final articlesSortBox = SortBox( ArticlesSortProperty.byFeed: (final article) => article.feedId, }, { - ArticlesSortProperty.alphabetical: Box(ArticlesSortProperty.publishDate, SortBoxOrder.descending), - ArticlesSortProperty.byFeed: Box(ArticlesSortProperty.alphabetical, SortBoxOrder.ascending), + ArticlesSortProperty.alphabetical: { + Box(ArticlesSortProperty.publishDate, SortBoxOrder.descending), + }, + ArticlesSortProperty.byFeed: { + Box(ArticlesSortProperty.alphabetical, SortBoxOrder.ascending), + }, }, ); diff --git a/packages/neon/neon_news/lib/sort/feeds.dart b/packages/neon/neon_news/lib/sort/feeds.dart index 7425e875..5e9f37a5 100644 --- a/packages/neon/neon_news/lib/sort/feeds.dart +++ b/packages/neon/neon_news/lib/sort/feeds.dart @@ -6,7 +6,11 @@ final feedsSortBox = SortBox( FeedsSortProperty.unreadCount: (final feed) => feed.unreadCount ?? 0, }, { - FeedsSortProperty.alphabetical: Box(FeedsSortProperty.unreadCount, SortBoxOrder.descending), - FeedsSortProperty.unreadCount: Box(FeedsSortProperty.alphabetical, SortBoxOrder.ascending), + FeedsSortProperty.alphabetical: { + Box(FeedsSortProperty.unreadCount, SortBoxOrder.descending), + }, + FeedsSortProperty.unreadCount: { + Box(FeedsSortProperty.alphabetical, SortBoxOrder.ascending), + }, }, ); diff --git a/packages/neon/neon_news/lib/sort/folders.dart b/packages/neon/neon_news/lib/sort/folders.dart index 633c5882..39061dcc 100644 --- a/packages/neon/neon_news/lib/sort/folders.dart +++ b/packages/neon/neon_news/lib/sort/folders.dart @@ -6,8 +6,12 @@ final foldersSortBox = SortBox( FoldersSortProperty.unreadCount: (final folderFeedsWrapper) => folderFeedsWrapper.$3, }, { - FoldersSortProperty.alphabetical: Box(FoldersSortProperty.unreadCount, SortBoxOrder.descending), - FoldersSortProperty.unreadCount: Box(FoldersSortProperty.alphabetical, SortBoxOrder.ascending), + FoldersSortProperty.alphabetical: { + Box(FoldersSortProperty.unreadCount, SortBoxOrder.descending), + }, + FoldersSortProperty.unreadCount: { + Box(FoldersSortProperty.alphabetical, SortBoxOrder.ascending), + }, }, ); diff --git a/packages/neon/neon_notes/lib/sort/categories.dart b/packages/neon/neon_notes/lib/sort/categories.dart index 42f461c4..53cbbc0e 100644 --- a/packages/neon/neon_notes/lib/sort/categories.dart +++ b/packages/neon/neon_notes/lib/sort/categories.dart @@ -6,7 +6,9 @@ final categoriesSortBox = SortBox( CategoriesSortProperty.notesCount: (final category) => category.count, }, { - CategoriesSortProperty.notesCount: Box(CategoriesSortProperty.alphabetical, SortBoxOrder.ascending), + CategoriesSortProperty.notesCount: { + Box(CategoriesSortProperty.alphabetical, SortBoxOrder.ascending), + }, }, ); diff --git a/packages/neon/neon_notes/lib/sort/notes.dart b/packages/neon/neon_notes/lib/sort/notes.dart index 137dcdfb..04606eb4 100644 --- a/packages/neon/neon_notes/lib/sort/notes.dart +++ b/packages/neon/neon_notes/lib/sort/notes.dart @@ -6,6 +6,8 @@ final notesSortBox = SortBox( NotesSortProperty.lastModified: (final note) => note.modified, }, { - NotesSortProperty.alphabetical: Box(NotesSortProperty.lastModified, SortBoxOrder.descending), + NotesSortProperty.alphabetical: { + Box(NotesSortProperty.lastModified, SortBoxOrder.descending), + }, }, ); diff --git a/packages/sort_box/lib/sort_box.dart b/packages/sort_box/lib/sort_box.dart index 6c174810..7c922d2e 100644 --- a/packages/sort_box/lib/sort_box.dart +++ b/packages/sort_box/lib/sort_box.dart @@ -5,40 +5,42 @@ typedef ComparableGetter = Comparable Function(T); class SortBox { SortBox( this._properties, - this._secondaryBoxes, + this._boxes, ); final Map> _properties; - final Map> _secondaryBoxes; + final Map>> _boxes; List sort(final List input, final Box box) { if (input.length <= 1) { return input; } - final comparableGetter = _properties[box.property]!; - final secondaryBox = _secondaryBoxes[box.property]; - final comparableGetter2 = _properties[secondaryBox?.property]; + final sorted = input + ..sort((final item1, final item2) => _compare(item1, item2, box, _boxes[box.property]?.iterator)); + + return sorted; + } - return input - ..sort( - (final item1, final item2) { - final first = _compare(item1, item2, box.order, comparableGetter); + int _compare( + final R item1, + final R item2, + final Box box, + final Iterator>? iterator, + ) { + final comparableGetter = _properties[box.property]!; - if (first == 0 && secondaryBox != null) { - return _compare(item1, item2, secondaryBox.order, comparableGetter2!); - } + final comparable1 = comparableGetter(item1); + final comparable2 = comparableGetter(item2); - return first; - }, - ); - } + final order = + box.order == SortBoxOrder.ascending ? comparable1.compareTo(comparable2) : comparable2.compareTo(comparable1); - int _compare(final R item1, final R item2, final SortBoxOrder order, final ComparableGetter getter) { - final comparable1 = getter(item1); - final comparable2 = getter(item2); + if (order == 0 && iterator != null && iterator.moveNext()) { + return _compare(item1, item2, iterator.current, iterator); + } - return order == SortBoxOrder.ascending ? comparable1.compareTo(comparable2) : comparable2.compareTo(comparable1); + return order; } } diff --git a/packages/sort_box/test/sort_box_test.dart b/packages/sort_box/test/sort_box_test.dart index 2ea10bfc..02032676 100644 --- a/packages/sort_box/test/sort_box_test.dart +++ b/packages/sort_box/test/sort_box_test.dart @@ -4,16 +4,19 @@ import 'package:test/test.dart'; enum FruitSort { alphabetical, count, + price, } class Fruit { - Fruit( + const Fruit( this.name, - this.count, - ); + this.count, [ + this.price, + ]); final String name; final int count; + final int? price; @override String toString() => 'Fruit(name: $name, count: $count)'; @@ -24,21 +27,30 @@ void main() { { FruitSort.alphabetical: (final fruit) => fruit.name.toLowerCase(), FruitSort.count: (final fruit) => fruit.count, + FruitSort.price: (final fruit) => fruit.price!, }, { - FruitSort.alphabetical: Box(FruitSort.count, SortBoxOrder.ascending), - FruitSort.count: Box(FruitSort.alphabetical, SortBoxOrder.ascending), + FruitSort.alphabetical: { + Box(FruitSort.count, SortBoxOrder.ascending), + }, + FruitSort.count: { + Box(FruitSort.alphabetical, SortBoxOrder.ascending), + }, + FruitSort.price: { + Box(FruitSort.alphabetical, SortBoxOrder.descending), + Box(FruitSort.count, SortBoxOrder.ascending), + }, }, ); group('Primary', () { test('Alphabetical', () { final fruits = [ - Fruit('Apple', 1), - Fruit('Banana', 2), - Fruit('Apple', 3), - Fruit('Banana', 4), - Fruit('Apple', 5), + const Fruit('Apple', 1), + const Fruit('Banana', 2), + const Fruit('Apple', 3), + const Fruit('Banana', 4), + const Fruit('Apple', 5), ]; final sorted = sortBox.sort(fruits, Box(FruitSort.alphabetical, SortBoxOrder.ascending)); @@ -52,11 +64,11 @@ void main() { test('Count', () { final fruits = [ - Fruit('Apple', 1), - Fruit('Banana', 5), - Fruit('Apple', 4), - Fruit('Banana', 2), - Fruit('Apple', 3), + const Fruit('Apple', 1), + const Fruit('Banana', 5), + const Fruit('Apple', 4), + const Fruit('Banana', 2), + const Fruit('Apple', 3), ]; final sorted = sortBox.sort(fruits, Box(FruitSort.count, SortBoxOrder.ascending)); @@ -73,11 +85,11 @@ void main() { group('Secondary', () { test('Alphabetical', () { final fruits = [ - Fruit('Apple', 1), - Fruit('Banana', 2), - Fruit('Apple', 2), - Fruit('Banana', 1), - Fruit('Apple', 2), + const Fruit('Apple', 1), + const Fruit('Banana', 2), + const Fruit('Apple', 2), + const Fruit('Banana', 1), + const Fruit('Apple', 2), ]; final sorted = sortBox.sort(fruits, Box(FruitSort.count, SortBoxOrder.ascending)); @@ -94,11 +106,11 @@ void main() { test('Count', () { final fruits = [ - Fruit('Apple', 3), - Fruit('Banana', 4), - Fruit('Apple', 1), - Fruit('Banana', 2), - Fruit('Apple', 5), + const Fruit('Apple', 3), + const Fruit('Banana', 4), + const Fruit('Apple', 1), + const Fruit('Banana', 2), + const Fruit('Apple', 5), ]; final sorted = sortBox.sort(fruits, Box(FruitSort.alphabetical, SortBoxOrder.ascending)); @@ -116,11 +128,11 @@ void main() { test('Primary all equal', () { final fruits = [ - Fruit('Coconut', 1), - Fruit('Banana', 1), - Fruit('Apple', 1), - Fruit('Elderberry', 1), - Fruit('Damson', 1), + const Fruit('Coconut', 1), + const Fruit('Banana', 1), + const Fruit('Apple', 1), + const Fruit('Elderberry', 1), + const Fruit('Damson', 1), ]; final sorted = sortBox.sort(fruits, Box(FruitSort.count, SortBoxOrder.ascending)); @@ -130,4 +142,32 @@ void main() { } }); }); + + group('Third', () { + test('Count', () { + final fruits = [ + const Fruit('Apple', 1, 3), + const Fruit('Banana', 2, 2), + const Fruit('Apple', 2, 0), + const Fruit('Banana', 1, 3), + const Fruit('Apple', 2, 3), + ]; + final sorted = sortBox.sort(fruits, Box(FruitSort.price, 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]); + } + }); + }); }