This commit is contained in:
Leon Bösche
2025-12-16 22:26:05 +01:00
parent 18f41ba2b3
commit 8b5a5f9b7e
4 changed files with 110 additions and 34 deletions

View File

@@ -13,6 +13,7 @@ class FileBrowserBloc extends Bloc<FileBrowserEvent, FileBrowserState> {
int _currentPage = 1; int _currentPage = 1;
int _pageSize = 20; int _pageSize = 20;
String _sortBy = 'name'; String _sortBy = 'name';
bool _isAscending = true;
FileBrowserBloc(this._fileService) : super(DirectoryInitial()) { FileBrowserBloc(this._fileService) : super(DirectoryInitial()) {
on<LoadDirectory>(_onLoadDirectory); on<LoadDirectory>(_onLoadDirectory);
@@ -36,7 +37,7 @@ class FileBrowserBloc extends Bloc<FileBrowserEvent, FileBrowserState> {
_currentPath = event.path; _currentPath = event.path;
try { try {
final files = await _fileService.getFiles(event.orgId, event.path); final files = await _fileService.getFiles(event.orgId, event.path);
_currentFiles = _sortFiles(files, _sortBy); _currentFiles = _sortFiles(files, _sortBy, _isAscending);
_filteredFiles = _currentFiles; _filteredFiles = _currentFiles;
_currentPage = 1; _currentPage = 1;
if (files.isEmpty) { if (files.isEmpty) {
@@ -66,7 +67,8 @@ class FileBrowserBloc extends Bloc<FileBrowserEvent, FileBrowserState> {
void _onApplySort(ApplySort event, Emitter<FileBrowserState> emit) { void _onApplySort(ApplySort event, Emitter<FileBrowserState> emit) {
_sortBy = event.sortBy; _sortBy = event.sortBy;
_currentFiles = _sortFiles(_currentFiles, _sortBy); _isAscending = event.isAscending;
_currentFiles = _sortFiles(_currentFiles, _sortBy, _isAscending);
_filteredFiles = _currentFiles _filteredFiles = _currentFiles
.where((f) => f.name.toLowerCase().contains('')) .where((f) => f.name.toLowerCase().contains(''))
.toList(); // Re-apply filter if any, but since filter is separate, perhaps need to track filter .toList(); // Re-apply filter if any, but since filter is separate, perhaps need to track filter
@@ -111,6 +113,7 @@ class FileBrowserBloc extends Bloc<FileBrowserEvent, FileBrowserState> {
_currentPage = 1; _currentPage = 1;
_pageSize = 20; _pageSize = 20;
_sortBy = 'name'; _sortBy = 'name';
_isAscending = true;
} }
void _onLoadPage(LoadPage event, Emitter<FileBrowserState> emit) { void _onLoadPage(LoadPage event, Emitter<FileBrowserState> emit) {
@@ -155,6 +158,7 @@ class FileBrowserBloc extends Bloc<FileBrowserEvent, FileBrowserState> {
pageSize: _pageSize, pageSize: _pageSize,
totalPages: totalPages, totalPages: totalPages,
sortBy: _sortBy, sortBy: _sortBy,
isAscending: _isAscending,
), ),
); );
} }
@@ -165,24 +169,40 @@ class FileBrowserBloc extends Bloc<FileBrowserEvent, FileBrowserState> {
return _filteredFiles.sublist(start, end.clamp(0, _filteredFiles.length)); return _filteredFiles.sublist(start, end.clamp(0, _filteredFiles.length));
} }
List<FileItem> _sortFiles(List<FileItem> files, String sortBy) { List<FileItem> _sortFiles(
List<FileItem> files,
String sortBy,
bool isAscending,
) {
final sorted = List<FileItem>.from(files); final sorted = List<FileItem>.from(files);
sorted.sort((a, b) { sorted.sort((a, b) {
switch (sortBy) { switch (sortBy) {
case 'name': case 'name':
return a.name.compareTo(b.name); return isAscending
? a.name.compareTo(b.name)
: b.name.compareTo(a.name);
case 'date': case 'date':
return b.lastModified.compareTo(a.lastModified); return isAscending
? a.lastModified.compareTo(b.lastModified)
: b.lastModified.compareTo(a.lastModified);
case 'size': case 'size':
return b.size.compareTo(a.size); return isAscending
? a.size.compareTo(b.size)
: b.size.compareTo(a.size);
case 'type': case 'type':
// Folders before files // Folders before files if ascending, else files before folders
if (a.type == FileType.folder && b.type == FileType.file) return -1; int typeCompare = isAscending
if (a.type == FileType.file && b.type == FileType.folder) return 1; ? 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 // 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: default:
return a.name.compareTo(b.name); return isAscending
? a.name.compareTo(b.name)
: b.name.compareTo(a.name);
} }
}); });
return sorted; return sorted;

View File

@@ -30,11 +30,12 @@ class RefreshDirectory extends FileBrowserEvent {}
class ApplySort extends FileBrowserEvent { class ApplySort extends FileBrowserEvent {
final String sortBy; // name, date, size, type final String sortBy; // name, date, size, type
final bool isAscending;
const ApplySort(this.sortBy); const ApplySort(this.sortBy, {this.isAscending = true});
@override @override
List<Object> get props => [sortBy]; List<Object> get props => [sortBy, isAscending];
} }
class ApplyFilter extends FileBrowserEvent { class ApplyFilter extends FileBrowserEvent {

View File

@@ -32,6 +32,7 @@ class DirectoryLoaded extends FileBrowserState {
final int pageSize; final int pageSize;
final int totalPages; final int totalPages;
final String sortBy; final String sortBy;
final bool isAscending;
const DirectoryLoaded({ const DirectoryLoaded({
required this.files, required this.files,
@@ -43,6 +44,7 @@ class DirectoryLoaded extends FileBrowserState {
required this.pageSize, required this.pageSize,
required this.totalPages, required this.totalPages,
required this.sortBy, required this.sortBy,
required this.isAscending,
}); });
@override @override
@@ -56,6 +58,7 @@ class DirectoryLoaded extends FileBrowserState {
pageSize, pageSize,
totalPages, totalPages,
sortBy, sortBy,
isAscending,
]; ];
} }

View File

@@ -213,36 +213,88 @@ class _FileExplorerState extends State<FileExplorer> {
} }
}, },
), ),
const SizedBox(width: 860), const SizedBox(width: 800),
BlocBuilder<FileBrowserBloc, FileBrowserState>( BlocBuilder<FileBrowserBloc, FileBrowserState>(
builder: (context, state) { builder: (context, state) {
String currentSort = 'name'; String currentSort = 'name';
bool isAscending = true;
if (state is DirectoryLoaded) { if (state is DirectoryLoaded) {
currentSort = state.sortBy; currentSort = state.sortBy;
isAscending = state.isAscending;
} }
return DropdownButton<String>( return Row(
value: currentSort, children: [
dropdownColor: AppTheme.accentColor.withAlpha(160), PopupMenuButton<String>(
color: AppTheme.accentColor.withAlpha(200),
style: const TextStyle( position: PopupMenuPosition.under,
color: AppTheme.primaryText, offset: const Offset(48, 8),
fontSize: 14, itemBuilder: (BuildContext context) => [
), const PopupMenuItem(
underline: Container(), // Remove underline value: 'name',
items: const [
DropdownMenuItem(value: 'name', child: Text('Name')), child: Text('Name'),
DropdownMenuItem(value: 'date', child: Text('Date')), ),
DropdownMenuItem(value: 'size', child: Text('Size')), const PopupMenuItem(
DropdownMenuItem(value: 'type', child: Text('Type')), value: 'date',
child: Text('Date'),
),
const PopupMenuItem(
value: 'size',
child: Text('Size'),
),
const PopupMenuItem(
value: 'type',
child: Text('Type'),
),
],
onSelected: (value) {
context.read<FileBrowserBloc>().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<FileBrowserBloc>().add(
ApplySort(
currentSort,
isAscending: !isAscending,
),
);
},
),
], ],
onChanged: (value) {
if (value != null) {
context.read<FileBrowserBloc>().add(
ApplySort(value),
);
}
},
); );
}, },
), ),