feat: continue watching in library
This commit is contained in:
@@ -3,6 +3,7 @@ import 'dart:convert';
|
||||
import 'package:dio/dio.dart';
|
||||
|
||||
import '../config/plex_config.dart';
|
||||
import '../models/play_queue_response.dart';
|
||||
import '../models/plex_file_info.dart';
|
||||
import '../models/plex_filter.dart';
|
||||
import '../models/plex_hub.dart';
|
||||
@@ -13,7 +14,6 @@ import '../models/plex_metadata.dart';
|
||||
import '../models/plex_playlist.dart';
|
||||
import '../models/plex_sort.dart';
|
||||
import '../models/plex_video_playback_data.dart';
|
||||
import '../models/play_queue_response.dart';
|
||||
import '../network/endpoint_failover_interceptor.dart';
|
||||
import '../utils/app_logger.dart';
|
||||
import '../utils/log_redaction_manager.dart';
|
||||
@@ -603,6 +603,16 @@ class PlexClient {
|
||||
return [];
|
||||
}
|
||||
|
||||
/// Get on deck items filtered by a specific library section
|
||||
Future<List<PlexMetadata>> getOnDeckForLibrary(String sectionId) async {
|
||||
final allOnDeck = await getOnDeck();
|
||||
|
||||
// Filter items to only include those from the specified library section
|
||||
return allOnDeck.where((item) {
|
||||
return item.librarySectionID == int.tryParse(sectionId);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
/// Get children of a metadata item (e.g., seasons for a show, episodes for a season)
|
||||
Future<List<PlexMetadata>> getChildren(String ratingKey) async {
|
||||
final response = await _dio.get('/library/metadata/$ratingKey/children');
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../../models/plex_hub.dart';
|
||||
import '../../widgets/hub_section.dart';
|
||||
import '../../widgets/hub_navigation_controller.dart';
|
||||
|
||||
import '../../client/plex_client.dart';
|
||||
import '../../i18n/strings.g.dart';
|
||||
import '../../mixins/item_updatable.dart';
|
||||
import '../../models/plex_hub.dart';
|
||||
import '../../models/plex_metadata.dart';
|
||||
import '../../widgets/hub_navigation_controller.dart';
|
||||
import '../../widgets/hub_section.dart';
|
||||
import 'base_library_tab.dart';
|
||||
|
||||
/// Recommended tab for library screen
|
||||
/// Shows library-specific hubs and recommendations
|
||||
/// Shows library-specific hubs and recommendations, including dedicated Continue Watching
|
||||
class LibraryRecommendedTab extends BaseLibraryTab<PlexHub> {
|
||||
const LibraryRecommendedTab({super.key, required super.library});
|
||||
|
||||
@@ -15,7 +19,8 @@ class LibraryRecommendedTab extends BaseLibraryTab<PlexHub> {
|
||||
}
|
||||
|
||||
class _LibraryRecommendedTabState
|
||||
extends BaseLibraryTabState<PlexHub, LibraryRecommendedTab> {
|
||||
extends BaseLibraryTabState<PlexHub, LibraryRecommendedTab>
|
||||
with ItemUpdatable {
|
||||
final HubNavigationController _hubNavigationController =
|
||||
HubNavigationController();
|
||||
|
||||
@@ -26,10 +31,27 @@ class _LibraryRecommendedTabState
|
||||
}
|
||||
|
||||
/// Focus the first item in the first hub
|
||||
@override
|
||||
void focusFirstItem() {
|
||||
_hubNavigationController.focusHub(0, 0);
|
||||
}
|
||||
|
||||
@override
|
||||
PlexClient get client => getClientForLibrary();
|
||||
|
||||
@override
|
||||
void updateItemInLists(String ratingKey, PlexMetadata updatedMetadata) {
|
||||
// Update the item in any hub that contains it
|
||||
for (final hub in items) {
|
||||
final itemIndex = hub.items.indexWhere(
|
||||
(item) => item.ratingKey == ratingKey,
|
||||
);
|
||||
if (itemIndex != -1) {
|
||||
hub.items[itemIndex] = updatedMetadata;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
IconData get emptyIcon => Icons.recommend;
|
||||
|
||||
@@ -44,8 +66,47 @@ class _LibraryRecommendedTabState
|
||||
// Use server-specific client for this library
|
||||
final client = getClientForLibrary();
|
||||
|
||||
// Hubs are now tagged with server info at the source
|
||||
return await client.getLibraryHubs(widget.library.key, limit: 12);
|
||||
// Load both continue watching items and regular hubs in parallel
|
||||
final results = await Future.wait([
|
||||
client.getOnDeckForLibrary(widget.library.key),
|
||||
client.getLibraryHubs(widget.library.key, limit: 12),
|
||||
]);
|
||||
|
||||
final continueWatchingItems = results[0] as List<PlexMetadata>;
|
||||
final hubs = results[1] as List<PlexHub>;
|
||||
|
||||
// Filter out any existing Continue Watching hubs since we're adding our own
|
||||
final filteredHubs = hubs.where((hub) {
|
||||
final title = hub.title.toLowerCase();
|
||||
final hubId = hub.hubIdentifier?.toLowerCase() ?? '';
|
||||
return !title.contains('continue watching') &&
|
||||
!title.contains('on deck') &&
|
||||
!hubId.contains('ondeck') &&
|
||||
!hubId.contains('continue');
|
||||
}).toList();
|
||||
|
||||
final finalHubs = <PlexHub>[];
|
||||
|
||||
// Add Continue Watching as the first hub if there are items
|
||||
if (continueWatchingItems.isNotEmpty) {
|
||||
final continueWatchingHub = PlexHub(
|
||||
hubKey: 'library_continue_watching_${widget.library.key}',
|
||||
title: t.discover.continueWatching,
|
||||
type: 'mixed',
|
||||
hubIdentifier: '_library_continue_watching_',
|
||||
size: continueWatchingItems.length,
|
||||
more: false,
|
||||
items: continueWatchingItems,
|
||||
serverId: widget.library.serverId,
|
||||
serverName: widget.library.serverName,
|
||||
);
|
||||
finalHubs.add(continueWatchingHub);
|
||||
}
|
||||
|
||||
// Add the filtered regular hubs
|
||||
finalHubs.addAll(filteredHubs);
|
||||
|
||||
return finalHubs;
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -57,16 +118,30 @@ class _LibraryRecommendedTabState
|
||||
itemCount: items.length,
|
||||
itemBuilder: (context, index) {
|
||||
final hub = items[index];
|
||||
final isContinueWatching =
|
||||
hub.hubIdentifier == '_library_continue_watching_';
|
||||
|
||||
return HubSection(
|
||||
hub: hub,
|
||||
icon: _getHubIcon(hub),
|
||||
navigationOrder: index,
|
||||
isInContinueWatching: isContinueWatching,
|
||||
onRefresh: updateItem,
|
||||
onRemoveFromContinueWatching: isContinueWatching
|
||||
? _refreshContinueWatching
|
||||
: null,
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Refresh the Continue Watching section
|
||||
void _refreshContinueWatching() {
|
||||
// Reload all data to refresh the continue watching section
|
||||
loadItems();
|
||||
}
|
||||
|
||||
IconData _getHubIcon(PlexHub hub) {
|
||||
final title = hub.title.toLowerCase();
|
||||
if (title.contains('continue watching') || title.contains('on deck')) {
|
||||
|
||||
Reference in New Issue
Block a user