import 'package:flutter/material.dart'; import '../main.dart'; import '../services/collection_service.dart'; import '../theme/app_colors.dart'; /// Screen to manage a collection: rename, invite/remove members, delete. class ManageCollectionScreen extends StatefulWidget { final Collection collection; const ManageCollectionScreen({super.key, required this.collection}); @override State createState() => _ManageCollectionScreenState(); } class _ManageCollectionScreenState extends State { late Collection _collection; List _members = []; bool _isLoading = true; @override void initState() { super.initState(); _collection = widget.collection; _loadMembers(); } Future _loadMembers() async { setState(() => _isLoading = true); try { final members = await CollectionService.getMembers(_collection.id); if (!mounted) return; setState(() { _members = members; _isLoading = false; }); } catch (e) { if (!mounted) return; setState(() => _isLoading = false); showGlobalSnackBar('Failed to load members: $e', isError: true); } } Future _rename() async { final ctrl = TextEditingController(text: _collection.name); final descCtrl = TextEditingController(text: _collection.description ?? ''); final result = await showDialog( context: context, builder: (_) => AlertDialog( title: const Text('Rename Collection'), content: Column( mainAxisSize: MainAxisSize.min, children: [ TextField( controller: ctrl, autofocus: true, decoration: const InputDecoration(labelText: 'Name'), ), const SizedBox(height: 12), TextField( controller: descCtrl, decoration: const InputDecoration(labelText: 'Description (optional)'), ), ], ), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('Cancel'), ), ElevatedButton( onPressed: () { if (ctrl.text.trim().isEmpty) return; Navigator.pop(context, true); }, child: const Text('Save'), ), ], ), ); if (result != true) return; try { await CollectionService.update( collectionId: _collection.id, name: ctrl.text.trim(), description: descCtrl.text.trim(), ); setState(() { _collection = Collection( id: _collection.id, name: ctrl.text.trim(), description: descCtrl.text.trim(), ownerId: _collection.ownerId, createdAt: _collection.createdAt, role: _collection.role, itemCount: _collection.itemCount, memberCount: _collection.memberCount, ); }); showGlobalSnackBar('Collection renamed!'); } catch (e) { showGlobalSnackBar('Failed: $e', isError: true); } } Future _inviteMember() async { final emailCtrl = TextEditingController(); final result = await showDialog( context: context, builder: (_) => AlertDialog( icon: Container( padding: const EdgeInsets.all(12), decoration: const BoxDecoration( gradient: AppColors.brandGradient, shape: BoxShape.circle, ), child: const Icon(Icons.person_add, color: Colors.white, size: 28), ), title: const Text('Invite Member'), content: Column( mainAxisSize: MainAxisSize.min, children: [ const Text( 'Enter the email address of the person you want to invite. ' 'They must already have an account.', style: TextStyle( fontSize: 13, color: AppColors.textSecondary, ), ), const SizedBox(height: 16), TextField( controller: emailCtrl, autofocus: true, keyboardType: TextInputType.emailAddress, decoration: const InputDecoration( labelText: 'Email address', hintText: 'user@example.com', prefixIcon: Icon(Icons.email_outlined), ), ), ], ), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('Cancel'), ), ElevatedButton( onPressed: () { if (emailCtrl.text.trim().isEmpty) return; Navigator.pop(context, true); }, child: const Text('Invite'), ), ], ), ); if (result != true) return; try { await CollectionService.inviteByEmail( collectionId: _collection.id, email: emailCtrl.text.trim(), ); showGlobalSnackBar('Member invited!'); _loadMembers(); } catch (e) { showGlobalSnackBar('$e', isError: true); } } Future _removeMember(CollectionMember member) async { final confirmed = await showDialog( context: context, builder: (_) => AlertDialog( title: const Text('Remove Member?'), content: Text( 'Remove ${member.email} from this collection?'), actions: [ TextButton( onPressed: () => Navigator.pop(context, false), child: const Text('Cancel'), ), ElevatedButton( onPressed: () => Navigator.pop(context, true), style: ElevatedButton.styleFrom(backgroundColor: AppColors.error), child: const Text('Remove'), ), ], ), ); if (confirmed != true) return; try { await CollectionService.removeMember( collectionId: _collection.id, membershipId: member.id, ); showGlobalSnackBar('Member removed.'); _loadMembers(); } catch (e) { showGlobalSnackBar('Failed: $e', isError: true); } } Future _leaveCollection() async { final confirmed = await showDialog( context: context, builder: (_) => AlertDialog( title: const Text('Leave Collection?'), content: Text( 'You will lose access to "${_collection.name}". ' 'This action cannot be undone.'), actions: [ TextButton( onPressed: () => Navigator.pop(context, false), child: const Text('Cancel'), ), ElevatedButton( onPressed: () => Navigator.pop(context, true), style: ElevatedButton.styleFrom(backgroundColor: AppColors.error), child: const Text('Leave'), ), ], ), ); if (confirmed != true) return; try { await CollectionService.leave(_collection.id); showGlobalSnackBar('Left "${_collection.name}".'); if (mounted) Navigator.pop(context); } catch (e) { showGlobalSnackBar('Failed: $e', isError: true); } } Future _deleteCollection() async { final confirmed = await showDialog( context: context, builder: (_) => AlertDialog( title: const Text('Delete Collection?'), content: Text( 'Delete "${_collection.name}" and ALL its items? ' 'This cannot be undone.'), actions: [ TextButton( onPressed: () => Navigator.pop(context, false), child: const Text('Cancel'), ), ElevatedButton( onPressed: () => Navigator.pop(context, true), style: ElevatedButton.styleFrom(backgroundColor: AppColors.error), child: const Text('Delete Forever'), ), ], ), ); if (confirmed != true) return; try { await CollectionService.delete(_collection.id); showGlobalSnackBar('Collection deleted.'); if (mounted) Navigator.pop(context); } catch (e) { showGlobalSnackBar('Failed: $e', isError: true); } } @override Widget build(BuildContext context) { final theme = Theme.of(context); final currentUserId = supabase.auth.currentUser?.id; return Scaffold( appBar: AppBar( title: Text(_collection.name), actions: [ if (_collection.isOwner) IconButton( icon: const Icon(Icons.edit), tooltip: 'Rename', onPressed: _rename, ), ], ), body: ListView( padding: const EdgeInsets.all(16), children: [ // ── Description ── if (_collection.description != null && _collection.description!.isNotEmpty) ...[ Text( _collection.description!, style: const TextStyle( fontSize: 14, color: AppColors.textSecondary), ), const SizedBox(height: 16), ], // ── Members section ── Row( children: [ Text( 'Members', style: theme.textTheme.titleMedium?.copyWith( fontWeight: FontWeight.w600, ), ), const Spacer(), if (_collection.isOwner) TextButton.icon( onPressed: _inviteMember, icon: const Icon(Icons.person_add, size: 18), label: const Text('Invite'), ), ], ), const SizedBox(height: 8), if (_isLoading) const Center( child: Padding( padding: EdgeInsets.all(24), child: CircularProgressIndicator(), ), ) else ...List.generate(_members.length, (i) { final m = _members[i]; return Card( margin: const EdgeInsets.only(bottom: 8), child: ListTile( leading: CircleAvatar( backgroundColor: m.isOwner ? AppColors.orange : AppColors.navy, child: Icon( m.isOwner ? Icons.star : Icons.person, color: Colors.white, size: 20, ), ), title: Text( m.email, style: const TextStyle(fontWeight: FontWeight.w500), ), subtitle: Text( m.isOwner ? 'Owner' : 'Member', style: const TextStyle(fontSize: 12), ), trailing: (!m.isOwner && _collection.isOwner && m.userId != currentUserId) ? IconButton( icon: const Icon(Icons.remove_circle_outline, color: AppColors.error), onPressed: () => _removeMember(m), ) : null, ), ); }), const SizedBox(height: 32), const Divider(), const SizedBox(height: 16), // ── Danger zone ── Text( 'Danger Zone', style: theme.textTheme.titleMedium?.copyWith( fontWeight: FontWeight.w600, color: AppColors.error, ), ), const SizedBox(height: 12), if (!_collection.isOwner) SizedBox( width: double.infinity, child: OutlinedButton.icon( onPressed: _leaveCollection, icon: const Icon(Icons.exit_to_app, color: AppColors.error), label: const Text('Leave Collection', style: TextStyle(color: AppColors.error)), style: OutlinedButton.styleFrom( side: const BorderSide(color: AppColors.error), padding: const EdgeInsets.symmetric(vertical: 14), ), ), ), if (_collection.isOwner) SizedBox( width: double.infinity, child: OutlinedButton.icon( onPressed: _deleteCollection, icon: const Icon(Icons.delete_forever, color: AppColors.error), label: const Text('Delete Collection', style: TextStyle(color: AppColors.error)), style: OutlinedButton.styleFrom( side: const BorderSide(color: AppColors.error), padding: const EdgeInsets.symmetric(vertical: 14), ), ), ), ], ), ); } }