Show leave collection options

This commit is contained in:
AmanRajSinghMourya
2025-08-29 20:20:49 +05:30
parent e9f55b968a
commit 2ebb920faa
2 changed files with 173 additions and 74 deletions

View File

@@ -1,8 +1,11 @@
import "package:ente_events/event_bus.dart";
import "package:ente_ui/theme/ente_theme.dart";
import "package:flutter/material.dart";
import "package:locker/events/collections_updated_event.dart";
import "package:locker/l10n/l10n.dart";
import "package:locker/services/collections/models/collection.dart";
import "package:locker/services/collections/models/collection_view_type.dart";
import "package:locker/services/configuration.dart";
import "package:locker/ui/components/item_list_view.dart";
import "package:locker/ui/pages/collection_page.dart";
import "package:locker/utils/collection_actions.dart";
@@ -34,7 +37,7 @@ class CollectionRowWidget extends StatelessWidget {
? null
: Border(
bottom: BorderSide(
color: Theme.of(context).dividerColor.withOpacity(0.3),
color: Theme.of(context).dividerColor.withAlpha(30),
width: 0.5,
),
),
@@ -87,45 +90,7 @@ class CollectionRowWidget extends StatelessWidget {
size: 20,
),
itemBuilder: (BuildContext context) {
if (overflowActions != null && overflowActions!.isNotEmpty) {
return overflowActions!
.map(
(action) => PopupMenuItem<String>(
value: action.id,
child: Row(
children: [
Icon(action.icon, size: 16),
const SizedBox(width: 8),
Text(action.label),
],
),
),
)
.toList();
} else {
return [
PopupMenuItem<String>(
value: 'edit',
child: Row(
children: [
const Icon(Icons.edit, size: 16),
const SizedBox(width: 8),
Text(context.l10n.edit),
],
),
),
PopupMenuItem<String>(
value: 'delete',
child: Row(
children: [
const Icon(Icons.delete, size: 16),
const SizedBox(width: 8),
Text(context.l10n.delete),
],
),
),
];
}
return _buildPopupMenuItems(context);
},
),
],
@@ -134,6 +99,67 @@ class CollectionRowWidget extends StatelessWidget {
);
}
List<PopupMenuItem<String>> _buildPopupMenuItems(BuildContext context) {
final collectionViewType =
getCollectionViewType(collection, Configuration.instance.getUserID()!);
if (overflowActions != null && overflowActions!.isNotEmpty) {
return overflowActions!
.map(
(action) => PopupMenuItem<String>(
value: action.id,
child: Row(
children: [
Icon(action.icon, size: 16),
const SizedBox(width: 8),
Text(action.label),
],
),
),
)
.toList();
} else {
return [
if (collectionViewType == CollectionViewType.ownedCollection ||
collectionViewType == CollectionViewType.hiddenOwnedCollection ||
collectionViewType == CollectionViewType.quickLink)
PopupMenuItem<String>(
value: 'edit',
child: Row(
children: [
const Icon(Icons.edit, size: 16),
const SizedBox(width: 8),
Text(context.l10n.edit),
],
),
),
if (collectionViewType == CollectionViewType.ownedCollection ||
collectionViewType == CollectionViewType.hiddenOwnedCollection ||
collectionViewType == CollectionViewType.quickLink)
PopupMenuItem<String>(
value: 'delete',
child: Row(
children: [
const Icon(Icons.delete, size: 16),
const SizedBox(width: 8),
Text(context.l10n.delete),
],
),
),
if (collectionViewType == CollectionViewType.sharedCollection)
PopupMenuItem<String>(
value: 'leave_collection',
child: Row(
children: [
const Icon(Icons.logout),
const SizedBox(width: 12),
Text(context.l10n.leaveCollection),
],
),
),
];
}
}
void _handleMenuAction(BuildContext context, String action) {
if (overflowActions != null && overflowActions!.isNotEmpty) {
final customAction = overflowActions!.firstWhere(
@@ -149,6 +175,9 @@ class CollectionRowWidget extends StatelessWidget {
case 'delete':
_deleteCollection(context);
break;
case 'leave_collection':
_leaveCollection(context);
break;
}
}
}
@@ -168,4 +197,14 @@ class CollectionRowWidget extends StatelessWidget {
),
);
}
Future<void> _leaveCollection(BuildContext context) async {
await CollectionActions.leaveCollection(
context,
collection,
onSuccess: () {
Bus.instance.fire(CollectionsUpdatedEvent());
},
);
}
}

View File

@@ -38,12 +38,15 @@ class CollectionPage extends UploaderPage {
class _CollectionPageState extends UploaderPageState<CollectionPage>
with SearchMixin {
final _logger = Logger("CollectionPage");
late StreamSubscription<CollectionsUpdatedEvent>
_collectionUpdateSubscription;
late Collection _collection;
List<EnteFile> _files = [];
List<EnteFile> _filteredFiles = [];
late CollectionViewType collectionViewType;
bool isQuickLink = false;
bool showFAB = true;
@override
void onFileUploadComplete() {
@@ -82,6 +85,12 @@ class _CollectionPageState extends UploaderPageState<CollectionPage>
}
}
@override
void dispose() {
_collectionUpdateSubscription.cancel();
super.dispose();
}
List<EnteFile> get _displayedFiles =>
isSearchActive ? _filteredFiles : _files;
@@ -89,18 +98,40 @@ class _CollectionPageState extends UploaderPageState<CollectionPage>
void initState() {
super.initState();
_initializeData(widget.collection);
Bus.instance.on<CollectionsUpdatedEvent>().listen((event) async {
final collection = (await CollectionService.instance.getCollections())
.where(
(c) => c.id == widget.collection.id,
)
.first;
await _initializeData(collection);
_collectionUpdateSubscription =
Bus.instance.on<CollectionsUpdatedEvent>().listen((event) async {
if (!mounted) return;
try {
final collections = await CollectionService.instance.getCollections();
final matchingCollection = collections.where(
(c) => c.id == widget.collection.id,
);
if (matchingCollection.isNotEmpty) {
await _initializeData(matchingCollection.first);
} else {
_logger.warning(
'Collection ${widget.collection.id} no longer exists, navigating back',
);
if (mounted) {
Navigator.of(context).pop();
}
}
} catch (e) {
_logger.severe('Error updating collection: $e');
}
});
collectionViewType = getCollectionViewType(
_collection,
Configuration.instance.getUserID()!,
);
showFAB = collectionViewType == CollectionViewType.ownedCollection ||
collectionViewType == CollectionViewType.hiddenOwnedCollection ||
collectionViewType == CollectionViewType.quickLink;
}
Future<void> _initializeData(Collection collection) async {
@@ -167,6 +198,13 @@ class _CollectionPageState extends UploaderPageState<CollectionPage>
}
}
Future<void> _leaveCollection() async {
await CollectionActions.leaveCollection(
context,
_collection,
);
}
@override
Widget build(BuildContext context) {
return KeyboardListener(
@@ -218,33 +256,53 @@ class _CollectionPageState extends UploaderPageState<CollectionPage>
case 'delete':
_deleteCollection();
break;
case 'leave_collection':
_leaveCollection();
break;
}
},
itemBuilder: (BuildContext context) {
return [
PopupMenuItem<String>(
value: 'edit',
child: Row(
children: [
const Icon(Icons.edit),
const SizedBox(width: 12),
Text(context.l10n.edit),
],
if (collectionViewType == CollectionViewType.ownedCollection ||
collectionViewType == CollectionViewType.hiddenOwnedCollection ||
collectionViewType == CollectionViewType.quickLink)
PopupMenuItem<String>(
value: 'edit',
child: Row(
children: [
const Icon(Icons.edit),
const SizedBox(width: 12),
Text(context.l10n.edit),
],
),
),
),
PopupMenuItem<String>(
value: 'delete',
child: Row(
children: [
const Icon(Icons.delete, color: Colors.red),
const SizedBox(width: 12),
Text(
context.l10n.delete,
style: const TextStyle(color: Colors.red),
),
],
if (collectionViewType == CollectionViewType.ownedCollection ||
collectionViewType == CollectionViewType.hiddenOwnedCollection ||
collectionViewType == CollectionViewType.quickLink)
PopupMenuItem<String>(
value: 'delete',
child: Row(
children: [
const Icon(Icons.delete, color: Colors.red),
const SizedBox(width: 12),
Text(
context.l10n.delete,
style: const TextStyle(color: Colors.red),
),
],
),
),
if (collectionViewType == CollectionViewType.sharedCollection)
PopupMenuItem<String>(
value: 'leave_collection',
child: Row(
children: [
const Icon(Icons.logout),
const SizedBox(width: 12),
Text(context.l10n.leaveCollection),
],
),
),
),
];
},
);
@@ -329,10 +387,12 @@ class _CollectionPageState extends UploaderPageState<CollectionPage>
}
Widget _buildFAB() {
return FloatingActionButton(
onPressed: addFile,
tooltip: context.l10n.addFiles,
child: const Icon(Icons.add),
);
return showFAB
? FloatingActionButton(
onPressed: addFile,
tooltip: context.l10n.addFiles,
child: const Icon(Icons.add),
)
: const SizedBox.shrink();
}
}