From 18b33ee0a2627a640a320909cf3de624f06641e9 Mon Sep 17 00:00:00 2001 From: PaperCube Date: Fri, 16 Feb 2024 17:48:03 +0000 Subject: [PATCH] Sort files with directories first in SFTP --- lib/core/utils/comparator.dart | 83 +++++++++++++++++++++++++++++++++ lib/view/page/storage/sftp.dart | 22 +++++++-- 2 files changed, 102 insertions(+), 3 deletions(-) create mode 100644 lib/core/utils/comparator.dart diff --git a/lib/core/utils/comparator.dart b/lib/core/utils/comparator.dart new file mode 100644 index 000000000..6416683b4 --- /dev/null +++ b/lib/core/utils/comparator.dart @@ -0,0 +1,83 @@ +class ChainComparator { + final ChainComparator? _parent; + final Comparator _comparator; + + ChainComparator._create(this._parent, this._comparator); + ChainComparator.empty() : this._create(null, (a, b) => 0); + ChainComparator.create() : this._create(null, (a, b) => 0); + + static ChainComparator comparing>( + F Function(T) extractor) { + return ChainComparator._create( + null, (a, b) => extractor(a).compareTo(extractor(b))); + } + + int compare(T a, T b) { + final parent = _parent; + if (parent != null) { + final int result = parent.compare(a, b); + if (result != 0) return result; + } + return _comparator(a, b); + } + + int call(T a, T b) { + return compare(a, b); + } + + ChainComparator thenCompareBy>( + F Function(T) extractor, + {bool reversed = false}) { + return ChainComparator._create( + this, + reversed + ? (a, b) => extractor(b).compareTo(extractor(a)) + : (a, b) => extractor(a).compareTo(extractor(b)), + ); + } + + ChainComparator thenWithComparator(Comparator comparator, + {bool reversed = false}) { + return ChainComparator._create( + this, + !reversed ? comparator : (a, b) => comparator(b, a), + ); + } + + ChainComparator thenCompareByReversed>( + F Function(T) extractor) { + return ChainComparator._create( + this, (a, b) => -extractor(a).compareTo(extractor(b))); + } + + ChainComparator thenTrueFirst(bool Function(T) f) { + return ChainComparator._create(this, (a, b) { + final fa = f(a), fb = f(b); + return fa == fb ? 0 : (fa ? -1 : 1); + }); + } + + ChainComparator reversed() { + return ChainComparator._create(null, (a, b) => this.compare(b, a)); + } +} + +class Comparators { + static Comparator compareStringCaseInsensitive( + {bool uppercaseFirst = false}) { + return (String a, String b) { + final r = a.toLowerCase().compareTo(b.toLowerCase()); + if (r != 0) return r; + return uppercaseFirst ? a.compareTo(b) : b.compareTo(a); + }; + } +} + +/* + +Comparator.comparing(Type1::getType2) +.thenCompare(Type1::getType3) +.thenCompare(Type1::getType4) +.thenCompareReversed(Type1::getType5) + + */ \ No newline at end of file diff --git a/lib/view/page/storage/sftp.dart b/lib/view/page/storage/sftp.dart index f6f1c0c9d..48eb8169e 100644 --- a/lib/view/page/storage/sftp.dart +++ b/lib/view/page/storage/sftp.dart @@ -8,6 +8,7 @@ import 'package:toolbox/core/extension/context/dialog.dart'; import 'package:toolbox/core/extension/context/locale.dart'; import 'package:toolbox/core/extension/context/snackbar.dart'; import 'package:toolbox/core/extension/sftpfile.dart'; +import 'package:toolbox/core/utils/comparator.dart'; import 'package:toolbox/core/utils/platform/base.dart'; import 'package:toolbox/data/res/logger.dart'; import 'package:toolbox/data/res/misc.dart'; @@ -800,15 +801,30 @@ enum _SortType { List sort(List files) { switch (this) { case _SortType.name: - files.sort((a, b) => a.filename.compareTo(b.filename)); + files.sort( + ChainComparator.create() + .thenTrueFirst((x) => x.attr.isDirectory) + .thenWithComparator((a, b) => + Comparators.compareStringCaseInsensitive()( + a.filename, b.filename)) + .compare, + ); break; case _SortType.time: files.sort( - (a, b) => (a.attr.modifyTime ?? 0).compareTo(b.attr.modifyTime ?? 0), + ChainComparator.create() + .thenTrueFirst((x) => x.attr.isDirectory) + .thenCompareBy((x) => x.attr.modifyTime ?? 0) + .compare, ); break; case _SortType.size: - files.sort((a, b) => (a.attr.size ?? 0).compareTo(b.attr.size ?? 0)); + files.sort( + ChainComparator.create() + .thenTrueFirst((x) => x.attr.isDirectory) + .thenCompareBy((x) => x.attr.size ?? 0) + .compare, + ); break; } return files;