import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../models/plex_metadata.dart'; import '../providers/settings_provider.dart'; import '../utils/app_logger.dart'; import '../widgets/media_card.dart'; import '../widgets/desktop_app_bar.dart'; import '../i18n/strings.g.dart'; import '../utils/grid_size_calculator.dart'; import '../utils/dialogs.dart'; import '../utils/provider_extensions.dart'; import 'base_media_list_detail_screen.dart'; /// Screen to display the contents of a collection class CollectionDetailScreen extends StatefulWidget { final PlexMetadata collection; const CollectionDetailScreen({super.key, required this.collection}); @override State createState() => _CollectionDetailScreenState(); } class _CollectionDetailScreenState extends BaseMediaListDetailScreen { @override PlexMetadata get mediaItem => widget.collection; @override String get title => widget.collection.title; @override String get emptyMessage => t.collections.empty; @override Future loadItems() async { if (mounted) { setState(() { isLoading = true; errorMessage = null; }); } try { final client = this.client; final newItems = await client.getCollectionItems(widget.collection.ratingKey); if (mounted) { setState(() { items = newItems; isLoading = false; }); } appLogger.d( 'Loaded ${newItems.length} items for collection: ${widget.collection.title}', ); } catch (e) { appLogger.e('Failed to load collection items', error: e); if (mounted) { setState(() { errorMessage = t.collections.failedToLoadItems(error: e.toString()); isLoading = false; }); } } } Future _deleteCollection() async { // Get library section ID from the collection or its items int? sectionId = widget.collection.librarySectionID; // If collection doesn't have it, try to get it from loaded items if (sectionId == null && items.isNotEmpty) { sectionId = items.first.librarySectionID; } if (sectionId == null) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(t.collections.unknownLibrarySection)), ); } return; } // Show confirmation dialog final confirmed = await showDeleteConfirmation( context, title: t.collections.deleteCollection, message: t.collections.deleteConfirm(title: widget.collection.title), ); if (confirmed != true) return; if (!mounted) return; try { final clientProvider = context.plexClient; final client = clientProvider.client; if (client == null) return; final success = await client.deleteCollection( sectionId.toString(), widget.collection.ratingKey, ); if (!mounted) return; if (mounted) { if (success) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(t.collections.deleted)), ); Navigator.pop(context, true); // Return true to indicate refresh needed } else { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(t.collections.deleteFailed)), ); } } } catch (e) { appLogger.e('Failed to delete collection', error: e); if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( t.collections.deleteFailedWithError(error: e.toString()), ), ), ); } } } @override Widget build(BuildContext context) { return Scaffold( body: CustomScrollView( slivers: [ CustomAppBar( title: Text(widget.collection.title), pinned: true, actions: [ // Play button if (items.isNotEmpty) IconButton( icon: const Icon(Icons.play_arrow), tooltip: t.discover.play, onPressed: playItems, ), // Shuffle button if (items.isNotEmpty) IconButton( icon: const Icon(Icons.shuffle), tooltip: t.common.shuffle, onPressed: shufflePlayItems, ), // Delete button IconButton( icon: const Icon(Icons.delete), tooltip: t.common.delete, onPressed: _deleteCollection, color: Colors.red, ), ], ), if (errorMessage != null) SliverFillRemaining( child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Icon( Icons.error_outline, size: 48, color: Colors.red, ), const SizedBox(height: 16), Text(errorMessage!), const SizedBox(height: 16), ElevatedButton( onPressed: loadItems, child: Text(t.common.retry), ), ], ), ), ) else if (items.isEmpty && isLoading) const SliverFillRemaining( child: Center(child: CircularProgressIndicator()), ) else if (items.isEmpty) SliverFillRemaining( child: Center( child: Text(t.collections.noItems), ), ) else SliverPadding( padding: const EdgeInsets.fromLTRB(8, 8, 8, 8), sliver: Consumer( builder: (context, settingsProvider, child) { return SliverGrid( gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( maxCrossAxisExtent: GridSizeCalculator.getMaxCrossAxisExtent( context, settingsProvider.libraryDensity, ), childAspectRatio: 2 / 3.3, crossAxisSpacing: 0, mainAxisSpacing: 0, ), delegate: SliverChildBuilderDelegate( (context, index) { final item = items[index]; return MediaCard( key: Key(item.ratingKey), item: item, onRefresh: updateItem, collectionId: widget.collection.ratingKey, onListRefresh: loadItems, ); }, childCount: items.length, ), ); }, ), ), ], ), ); } }