refactor: use play queues & other improvements

This commit is contained in:
edde746
2025-11-22 03:24:01 +01:00
parent 6e8a1a373e
commit 166654d374
61 changed files with 15248 additions and 9459 deletions
+15 -122
View File
@@ -1,17 +1,13 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../client/plex_client.dart';
import '../models/plex_metadata.dart';
import '../providers/plex_client_provider.dart';
import '../providers/multi_server_provider.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 '../utils/app_logger.dart';
import 'base_media_list_detail_screen.dart';
/// Screen to display the contents of a collection
@@ -25,7 +21,8 @@ class CollectionDetailScreen extends StatefulWidget {
}
class _CollectionDetailScreenState
extends BaseMediaListDetailScreen<CollectionDetailScreen> {
extends BaseMediaListDetailScreen<CollectionDetailScreen>
with StandardItemLoader<CollectionDetailScreen> {
@override
PlexMetadata get mediaItem => widget.collection;
@@ -35,69 +32,19 @@ class _CollectionDetailScreenState
@override
String get emptyMessage => t.collections.empty;
/// Get the correct PlexClient for this collection's server
PlexClient? _getClientForCollection() {
final serverId = widget.collection.serverId;
if (serverId == null) {
appLogger.w('Collection ${widget.collection.title} has no serverId, using legacy client');
return context.read<PlexClientProvider>().client;
}
final multiServerProvider = context.read<MultiServerProvider>();
final client = multiServerProvider.getClientForServer(serverId);
if (client == null) {
appLogger.w('No client found for server $serverId, using legacy client');
return context.read<PlexClientProvider>().client;
}
return client;
@override
Future<List<PlexMetadata>> fetchItems() async {
return await client.getCollectionItems(widget.collection.ratingKey);
}
@override
Future<void> loadItems() async {
if (mounted) {
setState(() {
isLoading = true;
errorMessage = null;
});
}
String getLoadErrorMessage(Object error) {
return t.collections.failedToLoadItems(error: error.toString());
}
try {
final client = this.client;
final newItems = await client.getCollectionItems(
widget.collection.ratingKey,
);
// Tag items with server info for correct client resolution
final taggedItems = newItems
.map(
(item) => item.copyWith(
serverId: widget.collection.serverId,
serverName: widget.collection.serverName,
),
)
.toList();
if (mounted) {
setState(() {
items = taggedItems;
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;
});
}
}
@override
String getLoadSuccessMessage(int itemCount) {
return 'Loaded $itemCount items for collection: ${widget.collection.title}';
}
Future<void> _deleteCollection() async {
@@ -129,9 +76,6 @@ class _CollectionDetailScreenState
if (!mounted) return;
try {
final client = _getClientForCollection();
if (client == null) return;
final success = await client.deleteCollection(
sectionId.toString(),
widget.collection.ratingKey,
@@ -176,61 +120,10 @@ class _CollectionDetailScreenState
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,
),
],
actions: buildAppBarActions(onDelete: _deleteCollection),
),
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
...buildStateSlivers(),
if (items.isNotEmpty)
SliverPadding(
padding: const EdgeInsets.fromLTRB(8, 8, 8, 8),
sliver: Consumer<SettingsProvider>(