Add error handling for organization loading in HomePage
This commit is contained in:
@@ -12,6 +12,7 @@ import '../blocs/permission/permission_event.dart';
|
||||
import '../blocs/permission/permission_state.dart';
|
||||
import '../blocs/upload/upload_bloc.dart';
|
||||
import '../blocs/upload/upload_event.dart';
|
||||
import '../blocs/upload/upload_state.dart';
|
||||
import '../models/file_item.dart';
|
||||
import '../theme/app_theme.dart';
|
||||
import '../theme/modern_glass_button.dart';
|
||||
@@ -661,393 +662,416 @@ class _FileExplorerState extends State<FileExplorer> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<FileBrowserBloc, FileBrowserState>(
|
||||
builder: (context, state) {
|
||||
if (state is DirectoryLoading) {
|
||||
return Center(
|
||||
child: CircularProgressIndicator(color: AppTheme.accentColor),
|
||||
);
|
||||
return BlocListener<UploadBloc, UploadState>(
|
||||
listener: (context, uploadState) {
|
||||
if (uploadState is UploadInProgress) {
|
||||
final hasCompleted = uploadState.uploads.any((u) => u.isCompleted);
|
||||
if (hasCompleted) {
|
||||
final fbState = context.read<FileBrowserBloc>().state;
|
||||
String currentPath = '/';
|
||||
if (fbState is DirectoryLoaded) currentPath = fbState.currentPath;
|
||||
if (fbState is DirectoryEmpty) currentPath = fbState.currentPath;
|
||||
context.read<FileBrowserBloc>().add(
|
||||
LoadDirectory(orgId: widget.orgId, path: currentPath),
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
child: BlocBuilder<FileBrowserBloc, FileBrowserState>(
|
||||
builder: (context, state) {
|
||||
if (state is DirectoryLoading) {
|
||||
return Center(
|
||||
child: CircularProgressIndicator(color: AppTheme.accentColor),
|
||||
);
|
||||
}
|
||||
|
||||
if (state is DirectoryError) {
|
||||
return Center(
|
||||
child: Text(
|
||||
'Error: ${state.error}',
|
||||
style: const TextStyle(color: AppTheme.primaryText),
|
||||
),
|
||||
);
|
||||
}
|
||||
if (state is DirectoryError) {
|
||||
return Center(
|
||||
child: Text(
|
||||
'Error: ${state.error}',
|
||||
style: const TextStyle(color: AppTheme.primaryText),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (state is DirectoryEmpty) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border(
|
||||
bottom: BorderSide(
|
||||
color: AppTheme.primaryText.withValues(alpha: 0.5),
|
||||
width: 1,
|
||||
if (state is DirectoryEmpty) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border(
|
||||
bottom: BorderSide(
|
||||
color: AppTheme.primaryText.withValues(alpha: 0.5),
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
),
|
||||
child: _buildTitle(),
|
||||
),
|
||||
child: _buildTitle(),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
BlocBuilder<PermissionBloc, PermissionState>(
|
||||
builder: (context, permState) {
|
||||
if (permState is PermissionLoaded &&
|
||||
permState.capabilities.canWrite) {
|
||||
return Row(
|
||||
children: [
|
||||
ModernGlassButton(
|
||||
onPressed: () async {
|
||||
final result = await FilePicker.platform
|
||||
.pickFiles();
|
||||
if (result != null && result.files.isNotEmpty) {
|
||||
final files = result.files
|
||||
.map(
|
||||
(file) => FileItem(
|
||||
name: file.name,
|
||||
path: '/${file.name}',
|
||||
type: FileType.file,
|
||||
size: file.size,
|
||||
lastModified: DateTime.now(),
|
||||
localPath: file.path,
|
||||
bytes: file.bytes,
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
context.read<UploadBloc>().add(
|
||||
StartUpload(
|
||||
files: files,
|
||||
targetPath: '/',
|
||||
orgId: widget.orgId,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
child: const Row(
|
||||
children: [
|
||||
Icon(Icons.upload),
|
||||
SizedBox(width: 8),
|
||||
Text('Upload File'),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
ModernGlassButton(
|
||||
onPressed: () async {
|
||||
final folderName = await _showCreateFolderDialog(
|
||||
context,
|
||||
);
|
||||
if (folderName != null && folderName.isNotEmpty) {
|
||||
context.read<FileBrowserBloc>().add(
|
||||
CreateFolder(
|
||||
orgId: widget.orgId,
|
||||
parentPath: '/',
|
||||
folderName: folderName,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
child: const Row(
|
||||
children: [
|
||||
Icon(Icons.create_new_folder),
|
||||
SizedBox(width: 8),
|
||||
Text('New Folder'),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
return const SizedBox.shrink();
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
children: [
|
||||
IconButton(
|
||||
icon: const Icon(
|
||||
Icons.arrow_back,
|
||||
color: AppTheme.primaryText,
|
||||
),
|
||||
splashColor: Colors.transparent,
|
||||
highlightColor: Colors.transparent,
|
||||
onPressed: () {
|
||||
final parentPath = _getParentPath(state.currentPath);
|
||||
context.read<FileBrowserBloc>().add(
|
||||
LoadDirectory(orgId: widget.orgId, path: parentPath),
|
||||
);
|
||||
},
|
||||
),
|
||||
const Text(
|
||||
'Empty Folder',
|
||||
style: TextStyle(color: AppTheme.primaryText),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (state is DirectoryLoaded) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border(
|
||||
bottom: BorderSide(
|
||||
color: AppTheme.primaryText.withValues(alpha: 0.5),
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
),
|
||||
child: _buildTitle(),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Visibility(
|
||||
visible: state.breadcrumbs.isNotEmpty,
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
IconButton(
|
||||
icon: const Icon(
|
||||
Icons.arrow_back,
|
||||
color: AppTheme.primaryText,
|
||||
),
|
||||
onPressed: () {
|
||||
final parentPath = _getParentPath(
|
||||
state.currentPath,
|
||||
);
|
||||
context.read<FileBrowserBloc>().add(
|
||||
LoadDirectory(
|
||||
orgId: widget.orgId,
|
||||
path: parentPath,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: Row(
|
||||
children: state.breadcrumbs.map((breadcrumb) {
|
||||
return TextButton(
|
||||
onPressed: () {
|
||||
context.read<FileBrowserBloc>().add(
|
||||
NavigateToFolder(breadcrumb.path),
|
||||
);
|
||||
},
|
||||
child: Text(
|
||||
'/${breadcrumb.name}',
|
||||
style: const TextStyle(
|
||||
color: AppTheme.secondaryText,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
BlocBuilder<PermissionBloc, PermissionState>(
|
||||
builder: (context, permState) {
|
||||
if (permState is PermissionLoaded &&
|
||||
permState.capabilities.canWrite) {
|
||||
return Row(
|
||||
children: [
|
||||
ModernGlassButton(
|
||||
onPressed: () async {
|
||||
final result = await FilePicker.platform
|
||||
.pickFiles(withData: true);
|
||||
if (result != null && result.files.isNotEmpty) {
|
||||
final files = result.files
|
||||
.map(
|
||||
(file) => FileItem(
|
||||
name: file.name,
|
||||
// Parent path only; server uses filename from multipart
|
||||
path: state.currentPath,
|
||||
type: FileType.file,
|
||||
size: file.size,
|
||||
lastModified: DateTime.now(),
|
||||
localPath: file.path,
|
||||
bytes: file.bytes,
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
context.read<UploadBloc>().add(
|
||||
StartUpload(
|
||||
files: files,
|
||||
targetPath: state.currentPath,
|
||||
orgId: widget.orgId,
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
}
|
||||
},
|
||||
child: const Row(
|
||||
children: [
|
||||
Icon(Icons.upload),
|
||||
SizedBox(width: 8),
|
||||
Text('Upload File'),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
),
|
||||
),
|
||||
BlocBuilder<PermissionBloc, PermissionState>(
|
||||
builder: (context, permState) {
|
||||
if (permState is PermissionLoaded &&
|
||||
permState.capabilities.canWrite) {
|
||||
return Row(
|
||||
children: [
|
||||
ModernGlassButton(
|
||||
onPressed: () async {
|
||||
final result = await FilePicker.platform
|
||||
.pickFiles();
|
||||
if (result != null && result.files.isNotEmpty) {
|
||||
final files = result.files
|
||||
.map(
|
||||
(file) => FileItem(
|
||||
name: file.name,
|
||||
path: '/${file.name}',
|
||||
type: FileType.file,
|
||||
size: file.size,
|
||||
lastModified: DateTime.now(),
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
context.read<UploadBloc>().add(
|
||||
StartUpload(
|
||||
files: files,
|
||||
targetPath: '/',
|
||||
orgId: widget.orgId,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
child: const Row(
|
||||
children: [
|
||||
Icon(Icons.upload),
|
||||
SizedBox(width: 8),
|
||||
Text('Upload File'),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
ModernGlassButton(
|
||||
onPressed: () async {
|
||||
final folderName = await _showCreateFolderDialog(
|
||||
context,
|
||||
);
|
||||
if (folderName != null && folderName.isNotEmpty) {
|
||||
context.read<FileBrowserBloc>().add(
|
||||
CreateFolder(
|
||||
orgId: widget.orgId,
|
||||
parentPath: state.currentPath,
|
||||
folderName: folderName,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
child: const Row(
|
||||
children: [
|
||||
Icon(Icons.create_new_folder),
|
||||
SizedBox(width: 8),
|
||||
Text('New Folder'),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
return const SizedBox.shrink();
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Expanded(
|
||||
child: ListView.builder(
|
||||
itemCount: state.paginatedFiles.length,
|
||||
itemBuilder: (context, index) {
|
||||
final file = state.paginatedFiles[index];
|
||||
final isSelected = _selectedFilePath == file.path;
|
||||
final isHovered = _hovered[file.path] ?? false;
|
||||
|
||||
if (file.type == FileType.folder) {
|
||||
return DragTarget<FileItem>(
|
||||
builder: (context, candidate, rejected) {
|
||||
final isDraggedOver = candidate.isNotEmpty;
|
||||
return Draggable<FileItem>(
|
||||
data: file,
|
||||
feedback: Opacity(
|
||||
opacity: 0.8,
|
||||
child: Icon(
|
||||
Icons.folder,
|
||||
color: AppTheme.primaryText,
|
||||
size: 48,
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
ModernGlassButton(
|
||||
onPressed: () async {
|
||||
final folderName =
|
||||
await _showCreateFolderDialog(context);
|
||||
if (folderName != null &&
|
||||
folderName.isNotEmpty) {
|
||||
context.read<FileBrowserBloc>().add(
|
||||
CreateFolder(
|
||||
orgId: widget.orgId,
|
||||
parentPath: '/',
|
||||
folderName: folderName,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
child: const Row(
|
||||
children: [
|
||||
Icon(Icons.create_new_folder),
|
||||
SizedBox(width: 8),
|
||||
Text('New Folder'),
|
||||
],
|
||||
),
|
||||
child: _buildFileItem(
|
||||
file,
|
||||
isSelected,
|
||||
isHovered,
|
||||
isDraggedOver,
|
||||
),
|
||||
);
|
||||
},
|
||||
onAcceptWithDetails: (draggedFile) {
|
||||
context.read<FileBrowserBloc>().add(
|
||||
MoveFile(
|
||||
orgId: widget.orgId,
|
||||
sourcePath: draggedFile.data.path,
|
||||
targetPath: file.path,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
} else {
|
||||
return Draggable<FileItem>(
|
||||
data: file,
|
||||
feedback: Opacity(
|
||||
opacity: 0.8,
|
||||
child: Icon(
|
||||
Icons.insert_drive_file,
|
||||
color: AppTheme.primaryText,
|
||||
size: 48,
|
||||
),
|
||||
),
|
||||
child: _buildFileItem(
|
||||
file,
|
||||
isSelected,
|
||||
isHovered,
|
||||
false,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
return const SizedBox.shrink();
|
||||
},
|
||||
),
|
||||
),
|
||||
if (state.totalPages > 1) ...[
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
IconButton(
|
||||
icon: const Icon(
|
||||
Icons.chevron_left,
|
||||
Icons.arrow_back,
|
||||
color: AppTheme.primaryText,
|
||||
),
|
||||
splashColor: Colors.transparent,
|
||||
highlightColor: Colors.transparent,
|
||||
onPressed: state.currentPage > 1
|
||||
? () {
|
||||
context.read<FileBrowserBloc>().add(
|
||||
LoadPage(state.currentPage - 1),
|
||||
);
|
||||
}
|
||||
: null,
|
||||
onPressed: () {
|
||||
final parentPath = _getParentPath(state.currentPath);
|
||||
context.read<FileBrowserBloc>().add(
|
||||
LoadDirectory(
|
||||
orgId: widget.orgId,
|
||||
path: parentPath,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
Text(
|
||||
'${state.currentPage} / ${state.totalPages}',
|
||||
style: const TextStyle(
|
||||
color: AppTheme.primaryText,
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(
|
||||
Icons.chevron_right,
|
||||
color: AppTheme.primaryText,
|
||||
),
|
||||
splashColor: Colors.transparent,
|
||||
highlightColor: Colors.transparent,
|
||||
onPressed: state.currentPage < state.totalPages
|
||||
? () {
|
||||
context.read<FileBrowserBloc>().add(
|
||||
LoadPage(state.currentPage + 1),
|
||||
);
|
||||
}
|
||||
: null,
|
||||
const Text(
|
||||
'Empty Folder',
|
||||
style: TextStyle(color: AppTheme.primaryText),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return const SizedBox.shrink();
|
||||
},
|
||||
if (state is DirectoryLoaded) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border(
|
||||
bottom: BorderSide(
|
||||
color: AppTheme.primaryText.withValues(alpha: 0.5),
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
),
|
||||
child: _buildTitle(),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Visibility(
|
||||
visible: state.breadcrumbs.isNotEmpty,
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
IconButton(
|
||||
icon: const Icon(
|
||||
Icons.arrow_back,
|
||||
color: AppTheme.primaryText,
|
||||
),
|
||||
onPressed: () {
|
||||
final parentPath = _getParentPath(
|
||||
state.currentPath,
|
||||
);
|
||||
context.read<FileBrowserBloc>().add(
|
||||
LoadDirectory(
|
||||
orgId: widget.orgId,
|
||||
path: parentPath,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: Row(
|
||||
children: state.breadcrumbs.map((breadcrumb) {
|
||||
return TextButton(
|
||||
onPressed: () {
|
||||
context.read<FileBrowserBloc>().add(
|
||||
NavigateToFolder(breadcrumb.path),
|
||||
);
|
||||
},
|
||||
child: Text(
|
||||
'/${breadcrumb.name}',
|
||||
style: const TextStyle(
|
||||
color: AppTheme.secondaryText,
|
||||
),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
),
|
||||
),
|
||||
BlocBuilder<PermissionBloc, PermissionState>(
|
||||
builder: (context, permState) {
|
||||
if (permState is PermissionLoaded &&
|
||||
permState.capabilities.canWrite) {
|
||||
return Row(
|
||||
children: [
|
||||
ModernGlassButton(
|
||||
onPressed: () async {
|
||||
final result = await FilePicker.platform
|
||||
.pickFiles(withData: true);
|
||||
if (result != null && result.files.isNotEmpty) {
|
||||
final files = result.files
|
||||
.map(
|
||||
(file) => FileItem(
|
||||
name: file.name,
|
||||
// Parent path only; server uses filename from multipart
|
||||
path: state.currentPath,
|
||||
type: FileType.file,
|
||||
size: file.size,
|
||||
lastModified: DateTime.now(),
|
||||
localPath: file.path,
|
||||
bytes: file.bytes,
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
context.read<UploadBloc>().add(
|
||||
StartUpload(
|
||||
files: files,
|
||||
targetPath: state.currentPath,
|
||||
orgId: widget.orgId,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
child: const Row(
|
||||
children: [
|
||||
Icon(Icons.upload),
|
||||
SizedBox(width: 8),
|
||||
Text('Upload File'),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
ModernGlassButton(
|
||||
onPressed: () async {
|
||||
final folderName =
|
||||
await _showCreateFolderDialog(context);
|
||||
if (folderName != null &&
|
||||
folderName.isNotEmpty) {
|
||||
context.read<FileBrowserBloc>().add(
|
||||
CreateFolder(
|
||||
orgId: widget.orgId,
|
||||
parentPath: state.currentPath,
|
||||
folderName: folderName,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
child: const Row(
|
||||
children: [
|
||||
Icon(Icons.create_new_folder),
|
||||
SizedBox(width: 8),
|
||||
Text('New Folder'),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
return const SizedBox.shrink();
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Expanded(
|
||||
child: ListView.builder(
|
||||
itemCount: state.paginatedFiles.length,
|
||||
itemBuilder: (context, index) {
|
||||
final file = state.paginatedFiles[index];
|
||||
final isSelected = _selectedFilePath == file.path;
|
||||
final isHovered = _hovered[file.path] ?? false;
|
||||
|
||||
if (file.type == FileType.folder) {
|
||||
return DragTarget<FileItem>(
|
||||
builder: (context, candidate, rejected) {
|
||||
final isDraggedOver = candidate.isNotEmpty;
|
||||
return Draggable<FileItem>(
|
||||
data: file,
|
||||
feedback: Opacity(
|
||||
opacity: 0.8,
|
||||
child: Icon(
|
||||
Icons.folder,
|
||||
color: AppTheme.primaryText,
|
||||
size: 48,
|
||||
),
|
||||
),
|
||||
child: _buildFileItem(
|
||||
file,
|
||||
isSelected,
|
||||
isHovered,
|
||||
isDraggedOver,
|
||||
),
|
||||
);
|
||||
},
|
||||
onAcceptWithDetails: (draggedFile) {
|
||||
context.read<FileBrowserBloc>().add(
|
||||
MoveFile(
|
||||
orgId: widget.orgId,
|
||||
sourcePath: draggedFile.data.path,
|
||||
targetPath: file.path,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
} else {
|
||||
return Draggable<FileItem>(
|
||||
data: file,
|
||||
feedback: Opacity(
|
||||
opacity: 0.8,
|
||||
child: Icon(
|
||||
Icons.insert_drive_file,
|
||||
color: AppTheme.primaryText,
|
||||
size: 48,
|
||||
),
|
||||
),
|
||||
child: _buildFileItem(
|
||||
file,
|
||||
isSelected,
|
||||
isHovered,
|
||||
false,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
if (state.totalPages > 1) ...[
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
IconButton(
|
||||
icon: const Icon(
|
||||
Icons.chevron_left,
|
||||
color: AppTheme.primaryText,
|
||||
),
|
||||
splashColor: Colors.transparent,
|
||||
highlightColor: Colors.transparent,
|
||||
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,
|
||||
),
|
||||
splashColor: Colors.transparent,
|
||||
highlightColor: Colors.transparent,
|
||||
onPressed: state.currentPage < state.totalPages
|
||||
? () {
|
||||
context.read<FileBrowserBloc>().add(
|
||||
LoadPage(state.currentPage + 1),
|
||||
);
|
||||
}
|
||||
: null,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return const SizedBox.shrink();
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -345,6 +345,17 @@ class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
|
||||
>(
|
||||
listener: (context, state) {
|
||||
if (state is OrganizationLoaded) {
|
||||
// Show errors if present
|
||||
if (state.error != null &&
|
||||
state.error!.isNotEmpty) {
|
||||
ScaffoldMessenger.of(
|
||||
context,
|
||||
).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(state.error!),
|
||||
),
|
||||
);
|
||||
}
|
||||
final orgId =
|
||||
state.selectedOrg?.id ?? '';
|
||||
// Reload file browser when org changes (or when falling back to personal workspace)
|
||||
|
||||
Reference in New Issue
Block a user