From 18f41ba2b33ad2333a27c8ab2d656128b1b1efce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leon=20B=C3=B6sche?= Date: Tue, 16 Dec 2025 22:11:15 +0100 Subject: [PATCH] fourth commit --- .../blocs/file_browser/file_browser_bloc.dart | 7 + .../file_browser/file_browser_event.dart | 2 +- .../file_browser/file_browser_state.dart | 3 + b0esche_cloud/lib/pages/file_explorer.dart | 144 ++++++++++++++---- .../repositories/mock_file_repository.dart | 137 +++++++++++++++++ .../lib/theme/modern_glass_button.dart | 25 +-- 6 files changed, 270 insertions(+), 48 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 26bc74f..da7413e 100644 --- a/b0esche_cloud/lib/blocs/file_browser/file_browser_bloc.dart +++ b/b0esche_cloud/lib/blocs/file_browser/file_browser_bloc.dart @@ -154,6 +154,7 @@ class FileBrowserBloc extends Bloc { currentPage: _currentPage, pageSize: _pageSize, totalPages: totalPages, + sortBy: _sortBy, ), ); } @@ -174,6 +175,12 @@ class FileBrowserBloc extends Bloc { return b.lastModified.compareTo(a.lastModified); case 'size': return 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; + // Within same type, sort by name + return a.name.compareTo(b.name); default: return a.name.compareTo(b.name); } 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 e37a41b..3fe0a77 100644 --- a/b0esche_cloud/lib/blocs/file_browser/file_browser_event.dart +++ b/b0esche_cloud/lib/blocs/file_browser/file_browser_event.dart @@ -29,7 +29,7 @@ class NavigateToFolder extends FileBrowserEvent { class RefreshDirectory extends FileBrowserEvent {} class ApplySort extends FileBrowserEvent { - final String sortBy; // name, date, size + final String sortBy; // name, date, size, type const ApplySort(this.sortBy); 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 9dc8c5f..651bf44 100644 --- a/b0esche_cloud/lib/blocs/file_browser/file_browser_state.dart +++ b/b0esche_cloud/lib/blocs/file_browser/file_browser_state.dart @@ -31,6 +31,7 @@ class DirectoryLoaded extends FileBrowserState { final int currentPage; final int pageSize; final int totalPages; + final String sortBy; const DirectoryLoaded({ required this.files, @@ -41,6 +42,7 @@ class DirectoryLoaded extends FileBrowserState { required this.currentPage, required this.pageSize, required this.totalPages, + required this.sortBy, }); @override @@ -53,6 +55,7 @@ class DirectoryLoaded extends FileBrowserState { currentPage, pageSize, totalPages, + sortBy, ]; } diff --git a/b0esche_cloud/lib/pages/file_explorer.dart b/b0esche_cloud/lib/pages/file_explorer.dart index 8ef8dec..a1624a8 100644 --- a/b0esche_cloud/lib/pages/file_explorer.dart +++ b/b0esche_cloud/lib/pages/file_explorer.dart @@ -120,7 +120,12 @@ class _FileExplorerState extends State { }, child: const Text( 'Create', - style: TextStyle(color: AppTheme.accentColor), + style: TextStyle( + color: AppTheme.accentColor, + decoration: TextDecoration.underline, + decorationColor: AppTheme.accentColor, + decorationThickness: 1.5, + ), ), ), ], @@ -180,31 +185,68 @@ class _FileExplorerState extends State { curve: Curves.easeInOut, child: Padding( padding: const EdgeInsets.only(top: 2), - child: IconButton( - icon: Icon( - _isSearching ? Icons.close : Icons.search, - color: AppTheme.accentColor, - ), - onPressed: () { - if (_isSearching) { - setState(() { - _showField = false; - _isSearching = false; - _searchController.clear(); - _searchQuery = ''; - context.read().add(ApplyFilter('')); - }); - } else { - setState(() { - _isSearching = true; - }); - Future.delayed(const Duration(milliseconds: 150), () { - setState(() { - _showField = true; - }); - }); - } - }, + child: Row( + children: [ + IconButton( + icon: Icon( + _isSearching ? Icons.close : Icons.search, + color: AppTheme.accentColor, + ), + onPressed: () { + if (_isSearching) { + setState(() { + _showField = false; + _isSearching = false; + _searchController.clear(); + _searchQuery = ''; + context.read().add(ApplyFilter('')); + }); + } else { + setState(() { + _isSearching = true; + }); + Future.delayed(const Duration(milliseconds: 150), () { + setState(() { + _showField = true; + }); + }); + } + }, + ), + const SizedBox(width: 860), + + BlocBuilder( + builder: (context, state) { + String currentSort = 'name'; + if (state is DirectoryLoaded) { + currentSort = state.sortBy; + } + return DropdownButton( + value: currentSort, + dropdownColor: AppTheme.accentColor.withAlpha(160), + + 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')), + ], + onChanged: (value) { + if (value != null) { + context.read().add( + ApplySort(value), + ); + } + }, + ); + }, + ), + ], ), ), ), @@ -259,7 +301,9 @@ class _FileExplorerState extends State { return BlocBuilder( builder: (context, state) { if (state is DirectoryLoading) { - return const Center(child: CircularProgressIndicator()); + return Center( + child: CircularProgressIndicator(color: AppTheme.accentColor), + ); } if (state is DirectoryError) { return Center( @@ -517,9 +561,9 @@ class _FileExplorerState extends State { const SizedBox(height: 16), Expanded( child: ListView.builder( - itemCount: state.filteredFiles.length, + itemCount: state.paginatedFiles.length, itemBuilder: (context, index) { - final file = state.filteredFiles[index]; + final file = state.paginatedFiles[index]; final isSelected = _selectedFilePath == file.path; return GestureDetector( onTap: () { @@ -611,6 +655,48 @@ class _FileExplorerState extends State { }, ), ), + // Pagination controls + if (state.totalPages > 1) ...[ + const SizedBox(height: 16), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + IconButton( + icon: const Icon( + Icons.chevron_left, + color: AppTheme.primaryText, + ), + onPressed: state.currentPage > 1 + ? () { + context.read().add( + LoadPage(state.currentPage - 1), + ); + } + : null, + ), + Text( + '${state.currentPage} / ${state.totalPages}', + style: const TextStyle( + color: AppTheme.primaryText, + fontSize: 16, + ), + ), + IconButton( + icon: const Icon( + Icons.chevron_right, + color: AppTheme.primaryText, + ), + onPressed: state.currentPage < state.totalPages + ? () { + context.read().add( + LoadPage(state.currentPage + 1), + ); + } + : null, + ), + ], + ), + ], ], ), ); diff --git a/b0esche_cloud/lib/repositories/mock_file_repository.dart b/b0esche_cloud/lib/repositories/mock_file_repository.dart index b0495e9..aa906ea 100644 --- a/b0esche_cloud/lib/repositories/mock_file_repository.dart +++ b/b0esche_cloud/lib/repositories/mock_file_repository.dart @@ -29,6 +29,143 @@ class MockFileRepository implements FileRepository { size: 512, lastModified: DateTime.now(), ), + // Add more files for pagination testing + FileItem( + name: 'presentation.pptx', + path: '/presentation.pptx', + type: FileType.file, + size: 2048, + lastModified: DateTime.now(), + ), + FileItem( + name: 'data.xlsx', + path: '/data.xlsx', + type: FileType.file, + size: 1024, + lastModified: DateTime.now(), + ), + FileItem( + name: 'video.mp4', + path: '/video.mp4', + type: FileType.file, + size: 102400, + lastModified: DateTime.now(), + ), + FileItem( + name: 'archive.zip', + path: '/archive.zip', + type: FileType.file, + size: 5120, + lastModified: DateTime.now(), + ), + FileItem( + name: 'notes.txt', + path: '/notes.txt', + type: FileType.file, + size: 256, + lastModified: DateTime.now(), + ), + FileItem( + name: 'config.json', + path: '/config.json', + type: FileType.file, + size: 128, + lastModified: DateTime.now(), + ), + FileItem( + name: 'script.js', + path: '/script.js', + type: FileType.file, + size: 256, + lastModified: DateTime.now(), + ), + FileItem( + name: 'styles.css', + path: '/styles.css', + type: FileType.file, + size: 512, + lastModified: DateTime.now(), + ), + FileItem( + name: 'index.html', + path: '/index.html', + type: FileType.file, + size: 1024, + lastModified: DateTime.now(), + ), + FileItem( + name: 'database.db', + path: '/database.db', + type: FileType.file, + size: 20480, + lastModified: DateTime.now(), + ), + FileItem( + name: 'logs', + path: '/logs', + type: FileType.folder, + lastModified: DateTime.now(), + ), + FileItem( + name: 'temp', + path: '/temp', + type: FileType.folder, + lastModified: DateTime.now(), + ), + FileItem( + name: 'backup', + path: '/backup', + type: FileType.folder, + lastModified: DateTime.now(), + ), + FileItem( + name: 'Music', + path: '/Music', + type: FileType.folder, + lastModified: DateTime.now(), + ), + FileItem( + name: 'Videos', + path: '/Videos', + type: FileType.folder, + lastModified: DateTime.now(), + ), + FileItem( + name: 'Projects', + path: '/Projects', + type: FileType.folder, + lastModified: DateTime.now(), + ), + FileItem( + name: 'Downloads', + path: '/Downloads', + type: FileType.folder, + lastModified: DateTime.now(), + ), + FileItem( + name: 'Pictures', + path: '/Pictures', + type: FileType.folder, + lastModified: DateTime.now(), + ), + FileItem( + name: 'Documents2', + path: '/Documents2', + type: FileType.folder, + lastModified: DateTime.now(), + ), + FileItem( + name: 'Archive', + path: '/Archive', + type: FileType.folder, + lastModified: DateTime.now(), + ), + FileItem( + name: 'OldFiles', + path: '/OldFiles', + type: FileType.folder, + lastModified: DateTime.now(), + ), ]; @override diff --git a/b0esche_cloud/lib/theme/modern_glass_button.dart b/b0esche_cloud/lib/theme/modern_glass_button.dart index 8266a9d..bcb6475 100644 --- a/b0esche_cloud/lib/theme/modern_glass_button.dart +++ b/b0esche_cloud/lib/theme/modern_glass_button.dart @@ -105,24 +105,13 @@ class _ModernGlassButtonState extends State ), ), child: Center( - child: widget.isLoading - ? SizedBox( - width: 20, - height: 20, - child: CircularProgressIndicator( - valueColor: AlwaysStoppedAnimation( - AppTheme.primaryText, - ), - strokeWidth: 2, - ), - ) - : DefaultTextStyle( - style: const TextStyle( - color: AppTheme.primaryText, - fontWeight: FontWeight.w600, - ), - child: widget.child, - ), + child: DefaultTextStyle( + style: const TextStyle( + color: AppTheme.primaryText, + fontWeight: FontWeight.w600, + ), + child: widget.child, + ), ), ), ),