From 8b5a5f9b7e9b6ad5d9db6c45675d443f002490e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leon=20B=C3=B6sche?= Date: Tue, 16 Dec 2025 22:26:05 +0100 Subject: [PATCH] sort --- .../blocs/file_browser/file_browser_bloc.dart | 42 ++++++--- .../file_browser/file_browser_event.dart | 5 +- .../file_browser/file_browser_state.dart | 3 + b0esche_cloud/lib/pages/file_explorer.dart | 94 ++++++++++++++----- 4 files changed, 110 insertions(+), 34 deletions(-) diff --git a/b0esche_cloud/lib/blocs/file_browser/file_browser_bloc.dart b/b0esche_cloud/lib/blocs/file_browser/file_browser_bloc.dart index da7413e..1066f6b 100644 --- a/b0esche_cloud/lib/blocs/file_browser/file_browser_bloc.dart +++ b/b0esche_cloud/lib/blocs/file_browser/file_browser_bloc.dart @@ -13,6 +13,7 @@ class FileBrowserBloc extends Bloc { int _currentPage = 1; int _pageSize = 20; String _sortBy = 'name'; + bool _isAscending = true; FileBrowserBloc(this._fileService) : super(DirectoryInitial()) { on(_onLoadDirectory); @@ -36,7 +37,7 @@ class FileBrowserBloc extends Bloc { _currentPath = event.path; try { final files = await _fileService.getFiles(event.orgId, event.path); - _currentFiles = _sortFiles(files, _sortBy); + _currentFiles = _sortFiles(files, _sortBy, _isAscending); _filteredFiles = _currentFiles; _currentPage = 1; if (files.isEmpty) { @@ -66,7 +67,8 @@ class FileBrowserBloc extends Bloc { void _onApplySort(ApplySort event, Emitter emit) { _sortBy = event.sortBy; - _currentFiles = _sortFiles(_currentFiles, _sortBy); + _isAscending = event.isAscending; + _currentFiles = _sortFiles(_currentFiles, _sortBy, _isAscending); _filteredFiles = _currentFiles .where((f) => f.name.toLowerCase().contains('')) .toList(); // Re-apply filter if any, but since filter is separate, perhaps need to track filter @@ -111,6 +113,7 @@ class FileBrowserBloc extends Bloc { _currentPage = 1; _pageSize = 20; _sortBy = 'name'; + _isAscending = true; } void _onLoadPage(LoadPage event, Emitter emit) { @@ -155,6 +158,7 @@ class FileBrowserBloc extends Bloc { pageSize: _pageSize, totalPages: totalPages, sortBy: _sortBy, + isAscending: _isAscending, ), ); } @@ -165,24 +169,40 @@ class FileBrowserBloc extends Bloc { return _filteredFiles.sublist(start, end.clamp(0, _filteredFiles.length)); } - List _sortFiles(List files, String sortBy) { + List _sortFiles( + List files, + String sortBy, + bool isAscending, + ) { final sorted = List.from(files); sorted.sort((a, b) { switch (sortBy) { case 'name': - return a.name.compareTo(b.name); + return isAscending + ? a.name.compareTo(b.name) + : b.name.compareTo(a.name); case 'date': - return b.lastModified.compareTo(a.lastModified); + return isAscending + ? a.lastModified.compareTo(b.lastModified) + : b.lastModified.compareTo(a.lastModified); case 'size': - return b.size.compareTo(a.size); + return isAscending + ? a.size.compareTo(b.size) + : b.size.compareTo(a.size); case 'type': - // Folders before files - if (a.type == FileType.folder && b.type == FileType.file) return -1; - if (a.type == FileType.file && b.type == FileType.folder) return 1; + // Folders before files if ascending, else files before folders + int typeCompare = isAscending + ? a.type.index.compareTo(b.type.index) + : b.type.index.compareTo(a.type.index); + if (typeCompare != 0) return typeCompare; // Within same type, sort by name - return a.name.compareTo(b.name); + return isAscending + ? a.name.compareTo(b.name) + : b.name.compareTo(a.name); default: - return a.name.compareTo(b.name); + return isAscending + ? a.name.compareTo(b.name) + : b.name.compareTo(a.name); } }); return sorted; diff --git a/b0esche_cloud/lib/blocs/file_browser/file_browser_event.dart b/b0esche_cloud/lib/blocs/file_browser/file_browser_event.dart index 3fe0a77..50b3ee4 100644 --- a/b0esche_cloud/lib/blocs/file_browser/file_browser_event.dart +++ b/b0esche_cloud/lib/blocs/file_browser/file_browser_event.dart @@ -30,11 +30,12 @@ class RefreshDirectory extends FileBrowserEvent {} class ApplySort extends FileBrowserEvent { final String sortBy; // name, date, size, type + final bool isAscending; - const ApplySort(this.sortBy); + const ApplySort(this.sortBy, {this.isAscending = true}); @override - List get props => [sortBy]; + List get props => [sortBy, isAscending]; } class ApplyFilter extends FileBrowserEvent { diff --git a/b0esche_cloud/lib/blocs/file_browser/file_browser_state.dart b/b0esche_cloud/lib/blocs/file_browser/file_browser_state.dart index 651bf44..a4a6f5a 100644 --- a/b0esche_cloud/lib/blocs/file_browser/file_browser_state.dart +++ b/b0esche_cloud/lib/blocs/file_browser/file_browser_state.dart @@ -32,6 +32,7 @@ class DirectoryLoaded extends FileBrowserState { final int pageSize; final int totalPages; final String sortBy; + final bool isAscending; const DirectoryLoaded({ required this.files, @@ -43,6 +44,7 @@ class DirectoryLoaded extends FileBrowserState { required this.pageSize, required this.totalPages, required this.sortBy, + required this.isAscending, }); @override @@ -56,6 +58,7 @@ class DirectoryLoaded extends FileBrowserState { pageSize, totalPages, sortBy, + isAscending, ]; } diff --git a/b0esche_cloud/lib/pages/file_explorer.dart b/b0esche_cloud/lib/pages/file_explorer.dart index a1624a8..3c9d86b 100644 --- a/b0esche_cloud/lib/pages/file_explorer.dart +++ b/b0esche_cloud/lib/pages/file_explorer.dart @@ -213,36 +213,88 @@ class _FileExplorerState extends State { } }, ), - const SizedBox(width: 860), + const SizedBox(width: 800), BlocBuilder( builder: (context, state) { String currentSort = 'name'; + bool isAscending = true; if (state is DirectoryLoaded) { currentSort = state.sortBy; + isAscending = state.isAscending; } - return DropdownButton( - value: currentSort, - dropdownColor: AppTheme.accentColor.withAlpha(160), + return Row( + children: [ + PopupMenuButton( + color: AppTheme.accentColor.withAlpha(200), - style: const TextStyle( - color: AppTheme.primaryText, - fontSize: 14, - ), - underline: Container(), // Remove underline - items: const [ - DropdownMenuItem(value: 'name', child: Text('Name')), - DropdownMenuItem(value: 'date', child: Text('Date')), - DropdownMenuItem(value: 'size', child: Text('Size')), - DropdownMenuItem(value: 'type', child: Text('Type')), + position: PopupMenuPosition.under, + offset: const Offset(48, 8), + itemBuilder: (BuildContext context) => [ + const PopupMenuItem( + value: 'name', + + child: Text('Name'), + ), + const PopupMenuItem( + value: 'date', + child: Text('Date'), + ), + const PopupMenuItem( + value: 'size', + child: Text('Size'), + ), + const PopupMenuItem( + value: 'type', + child: Text('Type'), + ), + ], + onSelected: (value) { + context.read().add( + ApplySort(value, isAscending: isAscending), + ); + }, + child: Row( + children: [ + Icon( + Icons.arrow_drop_down, + color: AppTheme.primaryText, + ), + const SizedBox(width: 4), + Text( + currentSort == 'name' + ? 'Name' + : currentSort == 'date' + ? 'Date' + : currentSort == 'size' + ? 'Size' + : 'Type', + style: const TextStyle( + color: AppTheme.primaryText, + fontSize: 14, + ), + ), + ], + ), + ), + const SizedBox(width: 8), + IconButton( + icon: Icon( + isAscending + ? Icons.arrow_upward + : Icons.arrow_downward, + color: AppTheme.accentColor, + ), + onPressed: () { + context.read().add( + ApplySort( + currentSort, + isAscending: !isAscending, + ), + ); + }, + ), ], - onChanged: (value) { - if (value != null) { - context.read().add( - ApplySort(value), - ); - } - }, ); }, ),