refactored room and file sorting to use direct comparators instead of temporary sort strings, removed obsolete 'sort' properties from API models, and improved file list sorting with case-insensitive name comparisons and null-safe date handling
This commit is contained in:
@@ -16,26 +16,20 @@ class GetRoomResponse extends ApiResponse {
|
||||
Map<String, dynamic> toJson() => _$GetRoomResponseToJson(this);
|
||||
|
||||
List<GetRoomResponseObject> sortBy({
|
||||
bool lastActivity = true,
|
||||
required bool favoritesToTop,
|
||||
required bool unreadToTop,
|
||||
}) {
|
||||
for (var chat in data) {
|
||||
final buffer = StringBuffer();
|
||||
|
||||
if (favoritesToTop) {
|
||||
buffer.write(chat.isFavorite ? 'b' : 'a');
|
||||
return data.toList()..sort((a, b) {
|
||||
if (favoritesToTop && a.isFavorite != b.isFavorite) {
|
||||
return a.isFavorite ? -1 : 1;
|
||||
}
|
||||
if (unreadToTop) {
|
||||
buffer.write(chat.unreadMessages > 0 ? 'b' : 'a');
|
||||
final aUnread = a.unreadMessages > 0;
|
||||
final bUnread = b.unreadMessages > 0;
|
||||
if (aUnread != bUnread) return aUnread ? -1 : 1;
|
||||
}
|
||||
|
||||
buffer.write(chat.lastActivity);
|
||||
|
||||
chat.sort = buffer.toString();
|
||||
}
|
||||
|
||||
return data.toList()..sort((a, b) => b.sort!.compareTo(a.sort!));
|
||||
return b.lastActivity.compareTo(a.lastActivity);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +65,6 @@ class GetRoomResponseObject {
|
||||
String? status;
|
||||
String? statusIcon;
|
||||
String? statusMessage;
|
||||
String? sort;
|
||||
|
||||
GetRoomResponseObject(
|
||||
this.id,
|
||||
|
||||
@@ -60,7 +60,7 @@ GetRoomResponseObject _$GetRoomResponseObjectFromJson(
|
||||
json['status'] as String?,
|
||||
json['statusIcon'] as String?,
|
||||
json['statusMessage'] as String?,
|
||||
)..sort = json['sort'] as String?;
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$GetRoomResponseObjectToJson(
|
||||
GetRoomResponseObject instance,
|
||||
@@ -97,7 +97,6 @@ Map<String, dynamic> _$GetRoomResponseObjectToJson(
|
||||
'status': instance.status,
|
||||
'statusIcon': instance.statusIcon,
|
||||
'statusMessage': instance.statusMessage,
|
||||
'sort': instance.sort,
|
||||
};
|
||||
|
||||
const _$GetRoomResponseObjectConversationTypeEnumMap = {
|
||||
|
||||
@@ -13,7 +13,6 @@ class CacheableFile {
|
||||
String? eTag;
|
||||
DateTime? createdAt;
|
||||
DateTime? modifiedAt;
|
||||
String? sort;
|
||||
|
||||
/// Nextcloud's instance-local file id (`oc:fileid`). Used to address the
|
||||
/// preview API by id, which is more reliable than the path-based variant
|
||||
|
||||
@@ -22,7 +22,7 @@ CacheableFile _$CacheableFileFromJson(Map<String, dynamic> json) =>
|
||||
: DateTime.parse(json['modifiedAt'] as String),
|
||||
fileId: (json['fileId'] as num?)?.toInt(),
|
||||
hasPreview: json['hasPreview'] as bool?,
|
||||
)..sort = json['sort'] as String?;
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$CacheableFileToJson(CacheableFile instance) =>
|
||||
<String, dynamic>{
|
||||
@@ -34,7 +34,6 @@ Map<String, dynamic> _$CacheableFileToJson(CacheableFile instance) =>
|
||||
'eTag': instance.eTag,
|
||||
'createdAt': instance.createdAt?.toIso8601String(),
|
||||
'modifiedAt': instance.modifiedAt?.toIso8601String(),
|
||||
'sort': instance.sort,
|
||||
'fileId': instance.fileId,
|
||||
'hasPreview': instance.hasPreview,
|
||||
};
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import 'package:jiffy/jiffy.dart';
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
import '../../../../../view/pages/files/data/sort_options.dart';
|
||||
@@ -22,60 +21,19 @@ class ListFilesResponse extends ApiResponse {
|
||||
SortOption sortOption = SortOption.name,
|
||||
bool reversed = false,
|
||||
}) {
|
||||
var list = List<CacheableFile>.empty(growable: true);
|
||||
final ascending = SortOptions.getOption(sortOption).compare;
|
||||
// `reversed=true` means user picked "Aufsteigend" (a→z, oldest→newest,
|
||||
// smallest→largest); default is descending.
|
||||
final compare = reversed
|
||||
? ascending
|
||||
: (CacheableFile a, CacheableFile b) => ascending(b, a);
|
||||
|
||||
if (foldersToTop) {
|
||||
list.addAll(
|
||||
_sort(
|
||||
files.where((element) => element.isDirectory).toSet(),
|
||||
reversed: reversed,
|
||||
sortOption: sortOption,
|
||||
),
|
||||
);
|
||||
list.addAll(
|
||||
_sort(
|
||||
files.where((element) => !element.isDirectory).toSet(),
|
||||
reversed: reversed,
|
||||
sortOption: sortOption,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
list.addAll(_sort(files, reversed: reversed, sortOption: sortOption));
|
||||
if (!foldersToTop) {
|
||||
return files.toList()..sort(compare);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
List<CacheableFile> _sort(
|
||||
Set<CacheableFile> files, {
|
||||
SortOption sortOption = SortOption.name,
|
||||
bool reversed = false,
|
||||
}) {
|
||||
for (var file in files) {
|
||||
final buffer = StringBuffer();
|
||||
|
||||
switch (sortOption) {
|
||||
case SortOption.date:
|
||||
buffer.write(
|
||||
Jiffy.parseFromMillisecondsSinceEpoch(
|
||||
file.modifiedAt?.millisecondsSinceEpoch ?? 0,
|
||||
).format(pattern: 'yyyyMMddhhmmss'),
|
||||
);
|
||||
break;
|
||||
|
||||
case SortOption.name:
|
||||
buffer.write(file.name.toLowerCase());
|
||||
break;
|
||||
|
||||
case SortOption.size:
|
||||
buffer.write(file.size);
|
||||
break;
|
||||
}
|
||||
|
||||
file.sort = buffer.toString();
|
||||
}
|
||||
|
||||
var list = files.toList()..sort((a, b) => b.sort!.compareTo(a.sort!));
|
||||
return reversed ? list.reversed.toList() : list;
|
||||
final folders = files.where((f) => f.isDirectory).toList()..sort(compare);
|
||||
final regular = files.where((f) => !f.isDirectory).toList()..sort(compare);
|
||||
return [...folders, ...regular];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,12 +21,16 @@ class SortOptions {
|
||||
SortOption.name: BetterSortOption(
|
||||
displayName: 'Name',
|
||||
icon: Icons.sort_by_alpha_outlined,
|
||||
compare: (a, b) => a.name.compareTo(b.name),
|
||||
compare: (a, b) => a.name.toLowerCase().compareTo(b.name.toLowerCase()),
|
||||
),
|
||||
SortOption.date: BetterSortOption(
|
||||
displayName: 'Datum',
|
||||
icon: Icons.history_outlined,
|
||||
compare: (a, b) => a.modifiedAt!.compareTo(b.modifiedAt!),
|
||||
compare: (a, b) {
|
||||
final aMs = a.modifiedAt?.millisecondsSinceEpoch ?? 0;
|
||||
final bMs = b.modifiedAt?.millisecondsSinceEpoch ?? 0;
|
||||
return aMs.compareTo(bMs);
|
||||
},
|
||||
),
|
||||
SortOption.size: BetterSortOption(
|
||||
displayName: 'Größe',
|
||||
|
||||
@@ -100,7 +100,6 @@ class ShareChatPicker extends StatelessWidget {
|
||||
if (rooms == null) return const SizedBox.shrink();
|
||||
final sorted = rooms
|
||||
.sortBy(
|
||||
lastActivity: true,
|
||||
favoritesToTop: talkSettings.sortFavoritesToTop,
|
||||
unreadToTop: talkSettings.sortUnreadToTop,
|
||||
)
|
||||
|
||||
@@ -162,7 +162,6 @@ class _ChatListViewState extends State<_ChatListView> {
|
||||
.val()
|
||||
.talkSettings;
|
||||
final sorted = rooms.sortBy(
|
||||
lastActivity: true,
|
||||
favoritesToTop: talkSettings.sortFavoritesToTop,
|
||||
unreadToTop: talkSettings.sortUnreadToTop,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user