fourth commit
This commit is contained in:
@@ -154,6 +154,7 @@ class FileBrowserBloc extends Bloc<FileBrowserEvent, FileBrowserState> {
|
||||
currentPage: _currentPage,
|
||||
pageSize: _pageSize,
|
||||
totalPages: totalPages,
|
||||
sortBy: _sortBy,
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -174,6 +175,12 @@ class FileBrowserBloc extends Bloc<FileBrowserEvent, FileBrowserState> {
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -120,7 +120,12 @@ class _FileExplorerState extends State<FileExplorer> {
|
||||
},
|
||||
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<FileExplorer> {
|
||||
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<FileBrowserBloc>().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<FileBrowserBloc>().add(ApplyFilter(''));
|
||||
});
|
||||
} else {
|
||||
setState(() {
|
||||
_isSearching = true;
|
||||
});
|
||||
Future.delayed(const Duration(milliseconds: 150), () {
|
||||
setState(() {
|
||||
_showField = true;
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
),
|
||||
const SizedBox(width: 860),
|
||||
|
||||
BlocBuilder<FileBrowserBloc, FileBrowserState>(
|
||||
builder: (context, state) {
|
||||
String currentSort = 'name';
|
||||
if (state is DirectoryLoaded) {
|
||||
currentSort = state.sortBy;
|
||||
}
|
||||
return DropdownButton<String>(
|
||||
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<FileBrowserBloc>().add(
|
||||
ApplySort(value),
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -259,7 +301,9 @@ class _FileExplorerState extends State<FileExplorer> {
|
||||
return BlocBuilder<FileBrowserBloc, FileBrowserState>(
|
||||
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<FileExplorer> {
|
||||
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<FileExplorer> {
|
||||
},
|
||||
),
|
||||
),
|
||||
// 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<FileBrowserBloc>().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<FileBrowserBloc>().add(
|
||||
LoadPage(state.currentPage + 1),
|
||||
);
|
||||
}
|
||||
: null,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -105,24 +105,13 @@ class _ModernGlassButtonState extends State<ModernGlassButton>
|
||||
),
|
||||
),
|
||||
child: Center(
|
||||
child: widget.isLoading
|
||||
? SizedBox(
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: CircularProgressIndicator(
|
||||
valueColor: AlwaysStoppedAnimation<Color>(
|
||||
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,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user