refactor: centralize globalKey construction via buildGlobalKey()
This commit is contained in:
@@ -7,6 +7,7 @@ import 'package:path/path.dart' as p;
|
||||
import 'tables.dart';
|
||||
import '../models/download_models.dart';
|
||||
import '../utils/app_logger.dart';
|
||||
import '../utils/global_key_utils.dart';
|
||||
|
||||
part 'app_database.g.dart';
|
||||
|
||||
@@ -99,7 +100,7 @@ class AppDatabase extends _$AppDatabase {
|
||||
required int duration,
|
||||
required bool shouldMarkWatched,
|
||||
}) async {
|
||||
final globalKey = '$serverId:$ratingKey';
|
||||
final globalKey = buildGlobalKey(serverId, ratingKey);
|
||||
final now = DateTime.now().millisecondsSinceEpoch;
|
||||
|
||||
// Check for existing progress entry
|
||||
@@ -144,7 +145,7 @@ class AppDatabase extends _$AppDatabase {
|
||||
required String ratingKey,
|
||||
required String actionType, // 'watched' or 'unwatched'
|
||||
}) async {
|
||||
final globalKey = '$serverId:$ratingKey';
|
||||
final globalKey = buildGlobalKey(serverId, ratingKey);
|
||||
final now = DateTime.now().millisecondsSinceEpoch;
|
||||
|
||||
// Remove conflicting actions (opposite action type and progress)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
import 'mixins/multi_server_fields.dart';
|
||||
import '../utils/global_key_utils.dart';
|
||||
|
||||
part 'plex_library.g.dart';
|
||||
|
||||
@@ -26,7 +27,7 @@ class PlexLibrary with MultiServerFields {
|
||||
final String? serverName;
|
||||
|
||||
/// Global unique identifier across all servers (serverId:key)
|
||||
String get globalKey => serverId != null ? '$serverId:$key' : key;
|
||||
String get globalKey => serverId != null ? buildGlobalKey(serverId!, key) : key;
|
||||
|
||||
PlexLibrary({
|
||||
required this.key,
|
||||
|
||||
@@ -4,6 +4,7 @@ import '../services/settings_service.dart' show EpisodePosterMode;
|
||||
import '../widgets/plex_optimized_image.dart' show kBlurArtwork, obfuscateText;
|
||||
import 'mixins/multi_server_fields.dart';
|
||||
import 'plex_role.dart';
|
||||
import '../utils/global_key_utils.dart';
|
||||
|
||||
part 'plex_metadata.g.dart';
|
||||
|
||||
@@ -111,7 +112,7 @@ class PlexMetadata with MultiServerFields {
|
||||
final String? clearLogo;
|
||||
|
||||
/// Global unique identifier across all servers (serverId:ratingKey)
|
||||
String get globalKey => serverId != null ? '$serverId:$ratingKey' : ratingKey;
|
||||
String get globalKey => serverId != null ? buildGlobalKey(serverId!, ratingKey) : ratingKey;
|
||||
|
||||
/// Parsed media type enum for type-safe comparisons
|
||||
PlexMediaType get mediaType {
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
import '../widgets/plex_optimized_image.dart' show kBlurArtwork, obfuscateText;
|
||||
import 'mixins/multi_server_fields.dart';
|
||||
import '../utils/global_key_utils.dart';
|
||||
|
||||
part 'plex_playlist.g.dart';
|
||||
|
||||
@@ -65,7 +66,7 @@ class PlexPlaylist with MultiServerFields {
|
||||
bool get isEditable => !smart;
|
||||
|
||||
/// Get globally unique key across all servers
|
||||
String get globalKey => serverId != null ? '$serverId:$ratingKey' : ratingKey;
|
||||
String get globalKey => serverId != null ? buildGlobalKey(serverId!, ratingKey) : ratingKey;
|
||||
|
||||
// Properties for MediaCard compatibility with PlexMetadata interface
|
||||
|
||||
|
||||
@@ -172,7 +172,7 @@ class DownloadProvider extends ChangeNotifier {
|
||||
// Load show metadata
|
||||
final showRatingKey = episode.grandparentRatingKey;
|
||||
if (showRatingKey != null) {
|
||||
final showGlobalKey = '$serverId:$showRatingKey';
|
||||
final showGlobalKey = buildGlobalKey(serverId, showRatingKey);
|
||||
if (!_metadata.containsKey(showGlobalKey)) {
|
||||
final showMetadata = allMetadata[showGlobalKey];
|
||||
if (showMetadata != null) {
|
||||
@@ -187,7 +187,7 @@ class DownloadProvider extends ChangeNotifier {
|
||||
// Load season metadata
|
||||
final seasonRatingKey = episode.parentRatingKey;
|
||||
if (seasonRatingKey != null) {
|
||||
final seasonGlobalKey = '$serverId:$seasonRatingKey';
|
||||
final seasonGlobalKey = buildGlobalKey(serverId, seasonRatingKey);
|
||||
if (!_metadata.containsKey(seasonGlobalKey)) {
|
||||
final seasonMetadata = allMetadata[seasonGlobalKey];
|
||||
if (seasonMetadata != null) {
|
||||
@@ -270,7 +270,7 @@ class DownloadProvider extends ChangeNotifier {
|
||||
final showRatingKey = meta.grandparentRatingKey;
|
||||
if (showRatingKey != null && !shows.containsKey(showRatingKey)) {
|
||||
// Try to get stored show metadata first
|
||||
final showGlobalKey = '${meta.serverId}:$showRatingKey';
|
||||
final showGlobalKey = buildGlobalKey(meta.serverId!, showRatingKey);
|
||||
final storedShow = _metadata[showGlobalKey];
|
||||
|
||||
if (storedShow != null && storedShow.type == 'show') {
|
||||
@@ -384,7 +384,7 @@ class DownloadProvider extends ChangeNotifier {
|
||||
required List<DownloadProgress> episodes,
|
||||
required String entityType,
|
||||
}) {
|
||||
final globalKey = '$serverId:$ratingKey';
|
||||
final globalKey = buildGlobalKey(serverId, ratingKey);
|
||||
|
||||
// DIAGNOSTIC: Check all sources of episode count
|
||||
final meta = _metadata[globalKey];
|
||||
@@ -604,7 +604,7 @@ class DownloadProvider extends ChangeNotifier {
|
||||
/// For shows and seasons, fetches all child episodes and queues them.
|
||||
/// Returns the number of items queued.
|
||||
Future<int> queueDownload(PlexMetadata metadata, PlexClient client) async {
|
||||
final globalKey = '${metadata.serverId}:${metadata.ratingKey}';
|
||||
final globalKey = metadata.globalKey;
|
||||
|
||||
// Check if downloads are blocked on cellular
|
||||
if (await DownloadManagerService.shouldBlockDownloadOnCellular()) {
|
||||
@@ -646,7 +646,7 @@ class DownloadProvider extends ChangeNotifier {
|
||||
|
||||
/// Queue a single movie or episode for download
|
||||
Future<void> _queueSingleDownload(PlexMetadata metadata, PlexClient client) async {
|
||||
final globalKey = '${metadata.serverId}:${metadata.ratingKey}';
|
||||
final globalKey = metadata.globalKey;
|
||||
|
||||
// Don't re-queue if already downloading or completed
|
||||
if (_downloads.containsKey(globalKey)) {
|
||||
@@ -697,7 +697,7 @@ class DownloadProvider extends ChangeNotifier {
|
||||
// Fetch and store show metadata if not already stored
|
||||
final showRatingKey = episode.grandparentRatingKey;
|
||||
if (showRatingKey != null) {
|
||||
final showGlobalKey = '$serverId:$showRatingKey';
|
||||
final showGlobalKey = buildGlobalKey(serverId, showRatingKey);
|
||||
|
||||
// Try to use existing metadata (set when queueing an entire show)
|
||||
PlexMetadata? showMetadata = _metadata[showGlobalKey];
|
||||
@@ -734,7 +734,7 @@ class DownloadProvider extends ChangeNotifier {
|
||||
// Fetch and store season metadata if not already stored
|
||||
final seasonRatingKey = episode.parentRatingKey;
|
||||
if (seasonRatingKey != null) {
|
||||
final seasonGlobalKey = '$serverId:$seasonRatingKey';
|
||||
final seasonGlobalKey = buildGlobalKey(serverId, seasonRatingKey);
|
||||
PlexMetadata? seasonMetadata = _metadata[seasonGlobalKey];
|
||||
|
||||
if (seasonMetadata == null) {
|
||||
@@ -768,7 +768,7 @@ class DownloadProvider extends ChangeNotifier {
|
||||
|
||||
/// Queue all episodes from a TV show for download
|
||||
Future<int> _queueShowDownload(PlexMetadata show, PlexClient client) async {
|
||||
final globalKey = '${show.serverId}:${show.ratingKey}';
|
||||
final globalKey = show.globalKey;
|
||||
int count = 0;
|
||||
final seasons = await client.getChildren(show.ratingKey);
|
||||
|
||||
@@ -804,7 +804,7 @@ class DownloadProvider extends ChangeNotifier {
|
||||
|
||||
/// Queue all episodes from a season for download
|
||||
Future<int> _queueSeasonDownload(PlexMetadata season, PlexClient client) async {
|
||||
final globalKey = '${season.serverId}:${season.ratingKey}';
|
||||
final globalKey = season.globalKey;
|
||||
int count = 0;
|
||||
final episodes = await client.getChildren(season.ratingKey);
|
||||
|
||||
@@ -883,7 +883,7 @@ class DownloadProvider extends ChangeNotifier {
|
||||
if (episode.type == 'episode') {
|
||||
final episodeWithServer = episode.serverId != null ? episode : episode.copyWith(serverId: season.serverId);
|
||||
|
||||
final episodeGlobalKey = '${episodeWithServer.serverId}:${episodeWithServer.ratingKey}';
|
||||
final episodeGlobalKey = episodeWithServer.globalKey;
|
||||
|
||||
// Only queue if NOT already downloaded or in progress
|
||||
final progress = _downloads[episodeGlobalKey];
|
||||
|
||||
@@ -5,6 +5,7 @@ import '../services/offline_watch_sync_service.dart';
|
||||
import '../services/plex_api_cache.dart';
|
||||
import '../utils/watch_state_notifier.dart';
|
||||
import 'download_provider.dart';
|
||||
import '../utils/global_key_utils.dart';
|
||||
|
||||
/// Provider for offline watch status UI state.
|
||||
///
|
||||
@@ -174,7 +175,7 @@ class OfflineWatchProvider extends ChangeNotifier {
|
||||
required bool isNowWatched,
|
||||
required WatchStateChangeType changeType,
|
||||
}) {
|
||||
final globalKey = '$serverId:$ratingKey';
|
||||
final globalKey = buildGlobalKey(serverId, ratingKey);
|
||||
final metadata = _downloadProvider.getMetadata(globalKey);
|
||||
if (metadata != null) {
|
||||
WatchStateNotifier().notifyWatched(metadata: metadata, isNowWatched: isNowWatched);
|
||||
|
||||
@@ -6,6 +6,7 @@ import 'package:plezy/widgets/app_icon.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import '../focus/key_event_utils.dart';
|
||||
import '../utils/global_key_utils.dart';
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import '../../services/plex_client.dart';
|
||||
import '../utils/plex_image_helper.dart';
|
||||
@@ -81,8 +82,6 @@ class _DiscoverScreenState extends State<DiscoverScreen>
|
||||
bool _isAutoScrollPaused = false;
|
||||
HiddenLibrariesProvider? _hiddenLibrariesProvider;
|
||||
|
||||
String _toGlobalKey(String ratingKey, String serverId) => '$serverId:$ratingKey';
|
||||
|
||||
// WatchStateAware: watch on-deck items and their parent shows/seasons
|
||||
@override
|
||||
Set<String>? get watchedRatingKeys {
|
||||
@@ -106,12 +105,12 @@ class _DiscoverScreenState extends State<DiscoverScreen>
|
||||
final serverId = item.serverId;
|
||||
if (serverId == null) return null;
|
||||
|
||||
keys.add(_toGlobalKey(item.ratingKey, serverId));
|
||||
keys.add(buildGlobalKey(serverId, item.ratingKey));
|
||||
if (item.parentRatingKey != null) {
|
||||
keys.add(_toGlobalKey(item.parentRatingKey!, serverId));
|
||||
keys.add(buildGlobalKey(serverId, item.parentRatingKey!));
|
||||
}
|
||||
if (item.grandparentRatingKey != null) {
|
||||
keys.add(_toGlobalKey(item.grandparentRatingKey!, serverId));
|
||||
keys.add(buildGlobalKey(serverId, item.grandparentRatingKey!));
|
||||
}
|
||||
}
|
||||
return keys;
|
||||
|
||||
@@ -32,6 +32,7 @@ import '../../../mixins/grid_focus_node_mixin.dart';
|
||||
import '../../../mixins/item_updatable.dart';
|
||||
import '../../../mixins/deletion_aware.dart';
|
||||
import '../../../utils/deletion_notifier.dart';
|
||||
import '../../../utils/global_key_utils.dart';
|
||||
import '../../../utils/platform_detector.dart';
|
||||
import '../../../i18n/strings.g.dart';
|
||||
import '../../main_screen.dart';
|
||||
@@ -61,7 +62,7 @@ class _LibraryBrowseTabState extends BaseLibraryTabState<PlexMetadata, LibraryBr
|
||||
PlexClient get client => getClientForLibrary();
|
||||
|
||||
String _toGlobalKey(String ratingKey, {String? serverId}) =>
|
||||
'${serverId ?? widget.library.serverId ?? ''}:$ratingKey';
|
||||
buildGlobalKey(serverId ?? widget.library.serverId ?? '', ratingKey);
|
||||
|
||||
@override
|
||||
String? get deletionServerId => widget.library.serverId;
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import '../utils/global_key_utils.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
@@ -106,7 +107,7 @@ class _MediaDetailScreenState extends State<MediaDetailScreen> with WatchStateAw
|
||||
final _seasonsSectionKey = GlobalKey();
|
||||
|
||||
String _toGlobalKey(String ratingKey, {String? serverId}) =>
|
||||
'${serverId ?? widget.metadata.serverId ?? ''}:$ratingKey';
|
||||
buildGlobalKey(serverId ?? widget.metadata.serverId ?? '', ratingKey);
|
||||
|
||||
// WatchStateAware: watch the show/movie and all season ratingKeys
|
||||
@override
|
||||
@@ -424,7 +425,7 @@ class _MediaDetailScreenState extends State<MediaDetailScreen> with WatchStateAw
|
||||
if (!widget.isOffline)
|
||||
Consumer<DownloadProvider>(
|
||||
builder: (context, downloadProvider, _) {
|
||||
final globalKey = '${metadata.serverId}:${metadata.ratingKey}';
|
||||
final globalKey = metadata.globalKey;
|
||||
final progress = downloadProvider.getProgress(globalKey);
|
||||
final isQueueing = downloadProvider.isQueueing(globalKey);
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import 'package:provider/provider.dart';
|
||||
import '../../services/plex_client.dart';
|
||||
import '../main.dart';
|
||||
import '../focus/focusable_wrapper.dart';
|
||||
import '../utils/global_key_utils.dart';
|
||||
import '../focus/key_event_utils.dart';
|
||||
import '../focus/dpad_navigator.dart';
|
||||
import '../focus/input_mode_tracker.dart';
|
||||
@@ -55,7 +56,7 @@ class _SeasonDetailScreenState extends State<SeasonDetailScreen>
|
||||
bool _suppressNextBackKeyUp = false;
|
||||
bool _routeSubscribed = false;
|
||||
|
||||
String _toGlobalKey(String ratingKey, {String? serverId}) => '${serverId ?? widget.season.serverId ?? ''}:$ratingKey';
|
||||
String _toGlobalKey(String ratingKey, {String? serverId}) => buildGlobalKey(serverId ?? widget.season.serverId ?? '', ratingKey);
|
||||
|
||||
// WatchStateAware: watch all episode ratingKeys
|
||||
@override
|
||||
@@ -270,7 +271,7 @@ class _SeasonDetailScreenState extends State<SeasonDetailScreen>
|
||||
String? localPosterPath;
|
||||
if (widget.isOffline && episode.serverId != null) {
|
||||
final downloadProvider = context.read<DownloadProvider>();
|
||||
final globalKey = '${episode.serverId}:${episode.ratingKey}';
|
||||
final globalKey = episode.globalKey;
|
||||
// Get the artwork reference and convert to local file path
|
||||
final artworkRef = downloadProvider.getArtworkPaths(globalKey);
|
||||
localPosterPath = artworkRef?.getLocalPath(DownloadStorageService.instance, episode.serverId!);
|
||||
@@ -499,7 +500,7 @@ class _EpisodeCardState extends State<_EpisodeCard> {
|
||||
|
||||
// Only show download status in online mode
|
||||
if (!widget.isOffline && widget.episode.serverId != null) {
|
||||
final globalKey = '${widget.episode.serverId}:${widget.episode.ratingKey}';
|
||||
final globalKey = widget.episode.globalKey;
|
||||
final progress = downloadProvider.getProgress(globalKey);
|
||||
final isQueueing = downloadProvider.isQueueing(globalKey);
|
||||
|
||||
|
||||
@@ -951,7 +951,7 @@ class VideoPlayerScreenState extends State<VideoPlayerScreen> with WidgetsBindin
|
||||
// since the user may have watched further since downloading.
|
||||
Duration? resumePosition;
|
||||
if (widget.isOffline) {
|
||||
final globalKey = '${widget.metadata.serverId}:${widget.metadata.ratingKey}';
|
||||
final globalKey = widget.metadata.globalKey;
|
||||
final localOffset = await offlineWatchService!.getLocalViewOffset(globalKey);
|
||||
if (localOffset != null && localOffset > 0) {
|
||||
resumePosition = Duration(milliseconds: localOffset);
|
||||
@@ -1103,7 +1103,7 @@ class VideoPlayerScreenState extends State<VideoPlayerScreen> with WidgetsBindin
|
||||
// Debug: log metadata info
|
||||
appLogger.d('Offline playback - serverId: ${widget.metadata.serverId}, ratingKey: ${widget.metadata.ratingKey}');
|
||||
|
||||
final globalKey = '${widget.metadata.serverId}:${widget.metadata.ratingKey}';
|
||||
final globalKey = widget.metadata.globalKey;
|
||||
appLogger.d('Looking up video with globalKey: $globalKey');
|
||||
|
||||
final videoPath = await downloadProvider.getVideoFilePath(globalKey);
|
||||
|
||||
@@ -5,6 +5,7 @@ import '../models/plex_hub.dart';
|
||||
import '../models/plex_library.dart';
|
||||
import '../models/plex_metadata.dart';
|
||||
import '../utils/app_logger.dart';
|
||||
import '../utils/global_key_utils.dart';
|
||||
import 'multi_server_manager.dart';
|
||||
import 'plex_auth_service.dart';
|
||||
|
||||
@@ -45,7 +46,7 @@ class DataAggregationService {
|
||||
filteredOnDeck = allOnDeck.where((item) {
|
||||
final librarySectionId = item.librarySectionID;
|
||||
if (librarySectionId == null) return true; // Keep if no section ID
|
||||
final globalKey = '${item.serverId}:$librarySectionId';
|
||||
final globalKey = buildGlobalKey(item.serverId!, librarySectionId.toString());
|
||||
return !hiddenLibraryKeys.contains(globalKey);
|
||||
}).toList();
|
||||
}
|
||||
@@ -118,7 +119,7 @@ class DataAggregationService {
|
||||
// Build the global key for the item's library section
|
||||
final librarySectionId = item.librarySectionID;
|
||||
if (librarySectionId == null) return true; // Keep if no section ID
|
||||
final globalKey = '$serverId:$librarySectionId';
|
||||
final globalKey = buildGlobalKey(serverId, librarySectionId.toString());
|
||||
return !hiddenLibraryKeys.contains(globalKey);
|
||||
}).toList();
|
||||
|
||||
|
||||
@@ -430,7 +430,7 @@ class DownloadManagerService {
|
||||
bool downloadSubtitles = true,
|
||||
bool downloadArtwork = true,
|
||||
}) async {
|
||||
final globalKey = '${metadata.serverId}:${metadata.ratingKey}';
|
||||
final globalKey = metadata.globalKey;
|
||||
|
||||
// Check if already downloading or completed
|
||||
final existing = await _database.getDownloadedMedia(globalKey);
|
||||
@@ -1252,12 +1252,13 @@ class DownloadManagerService {
|
||||
|
||||
if (metadata == null) {
|
||||
// Fallback: Try database record
|
||||
final downloadRecord = await _database.getDownloadedMedia('$serverId:$ratingKey');
|
||||
final gk = buildGlobalKey(serverId, ratingKey);
|
||||
final downloadRecord = await _database.getDownloadedMedia(gk);
|
||||
if (downloadRecord?.videoFilePath != null) {
|
||||
await _deleteByFilePath(downloadRecord!);
|
||||
return;
|
||||
}
|
||||
appLogger.w('Cannot delete - no metadata for $serverId:$ratingKey');
|
||||
appLogger.w('Cannot delete - no metadata for $gk');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1433,12 +1434,12 @@ class DownloadManagerService {
|
||||
}) async {
|
||||
for (int i = 0; i < episodes.length; i++) {
|
||||
final episode = episodes[i];
|
||||
final episodeGlobalKey = '$serverId:${episode.ratingKey}';
|
||||
final episodeGlobalKey = buildGlobalKey(serverId, episode.ratingKey);
|
||||
|
||||
// Emit progress update
|
||||
_emitDeletionProgress(
|
||||
DeletionProgress(
|
||||
globalKey: '$serverId:$parentKey',
|
||||
globalKey: buildGlobalKey(serverId, parentKey),
|
||||
itemTitle: parentTitle,
|
||||
currentItem: i + 1,
|
||||
totalItems: episodes.length,
|
||||
@@ -1551,7 +1552,7 @@ class DownloadManagerService {
|
||||
final otherEpisodes = await _database.getEpisodesBySeason(seasonKey);
|
||||
|
||||
// Check if any episodes besides this one
|
||||
return otherEpisodes.any((e) => e.globalKey != '${episode.serverId}:${episode.ratingKey}');
|
||||
return otherEpisodes.any((e) => e.globalKey != episode.globalKey);
|
||||
}
|
||||
|
||||
/// Check if show artwork is in use
|
||||
@@ -1562,7 +1563,7 @@ class DownloadManagerService {
|
||||
final showEpisodes = await _database.getEpisodesByShow(showKey);
|
||||
|
||||
// Check if any episodes belong to this show besides the current item
|
||||
return showEpisodes.any((item) => item.globalKey != '${metadata.serverId}:${metadata.ratingKey}');
|
||||
return showEpisodes.any((item) => item.globalKey != metadata.globalKey);
|
||||
}
|
||||
|
||||
/// Find file with any extension
|
||||
|
||||
@@ -6,6 +6,7 @@ import 'package:drift/drift.dart';
|
||||
import '../database/app_database.dart';
|
||||
import '../models/plex_metadata.dart';
|
||||
import '../utils/plex_cache_parser.dart';
|
||||
import '../utils/global_key_utils.dart';
|
||||
|
||||
/// Key-value cache for Plex API responses using Drift/SQLite.
|
||||
/// Stores raw JSON responses keyed by serverId:endpoint format.
|
||||
@@ -152,7 +153,7 @@ class PlexApiCache {
|
||||
final json = PlexCacheParser.extractFirstMetadata(data);
|
||||
if (json == null) continue;
|
||||
final metadata = PlexMetadata.fromJsonWithImages(json).copyWith(serverId: serverId);
|
||||
result['$serverId:$ratingKey'] = metadata;
|
||||
result[buildGlobalKey(serverId, ratingKey)] = metadata;
|
||||
} catch (_) {
|
||||
// Skip malformed entries
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import '../models/plex_metadata.dart';
|
||||
import 'app_logger.dart';
|
||||
import 'base_notifier.dart';
|
||||
import 'global_key_utils.dart';
|
||||
import 'hierarchical_event_mixin.dart';
|
||||
|
||||
/// Event representing a media item deletion with parent chain for hierarchical invalidation
|
||||
@@ -42,7 +43,7 @@ class DeletionEvent with HierarchicalEventMixin {
|
||||
required this.mediaType,
|
||||
this.leafCount = 1,
|
||||
this.isDownloadOnly = false,
|
||||
}) : globalKey = '$serverId:$ratingKey';
|
||||
}) : globalKey = buildGlobalKey(serverId, ratingKey);
|
||||
|
||||
@override
|
||||
String toString() => 'DeletionEvent(deleted: $globalKey, type: $mediaType, parents: $parentChain)';
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
/// Builds a globalKey string from [serverId] and [ratingKey].
|
||||
String buildGlobalKey(String serverId, String ratingKey) => '$serverId:$ratingKey';
|
||||
|
||||
/// Parses a globalKey string (format: "serverId:ratingKey") into its components.
|
||||
///
|
||||
/// Returns `null` if the key does not contain a colon separator.
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'global_key_utils.dart';
|
||||
|
||||
/// Mixin providing hierarchical event matching methods.
|
||||
///
|
||||
/// Events that represent changes to media items often need to check if they
|
||||
@@ -24,7 +26,7 @@ mixin HierarchicalEventMixin {
|
||||
|
||||
/// Check if this event affects a specific globalKey.
|
||||
bool affectsGlobalKey(String globalKey) =>
|
||||
this.globalKey == globalKey || parentChain.any((pk) => '$serverId:$pk' == globalKey);
|
||||
this.globalKey == globalKey || parentChain.any((pk) => buildGlobalKey(serverId, pk) == globalKey);
|
||||
|
||||
/// Check if this event affects any item in a collection.
|
||||
bool affectsAnyOf(Iterable<String> ratingKeys) => ratingKeys.any(affectsItem);
|
||||
|
||||
@@ -77,7 +77,7 @@ Future<bool?> navigateToVideoPlayer(
|
||||
|
||||
if (isOffline) {
|
||||
// Offline mode: resolve local file path for the external player
|
||||
final globalKey = '${metadata.serverId}:${metadata.ratingKey}';
|
||||
final globalKey = metadata.globalKey;
|
||||
final videoPath = await downloadProvider.getVideoFilePath(globalKey);
|
||||
if (videoPath != null && context.mounted) {
|
||||
final videoUrl = videoPath.contains('://') ? videoPath : 'file://$videoPath';
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import '../models/plex_metadata.dart';
|
||||
import 'app_logger.dart';
|
||||
import 'base_notifier.dart';
|
||||
import 'global_key_utils.dart';
|
||||
import 'hierarchical_event_mixin.dart';
|
||||
|
||||
/// Types of watch state changes
|
||||
@@ -47,7 +48,7 @@ class WatchStateEvent with HierarchicalEventMixin {
|
||||
required this.mediaType,
|
||||
this.viewOffset,
|
||||
this.isNowWatched,
|
||||
}) : globalKey = '$serverId:$ratingKey';
|
||||
}) : globalKey = buildGlobalKey(serverId, ratingKey);
|
||||
|
||||
@override
|
||||
String toString() => 'WatchStateEvent($changeType, $globalKey, parents: $parentChain)';
|
||||
|
||||
@@ -149,7 +149,7 @@ class MediaCardState extends State<MediaCard> {
|
||||
if (metadata.serverId == null) return null;
|
||||
|
||||
final downloadProvider = context.read<DownloadProvider>();
|
||||
final globalKey = '${metadata.serverId}:${metadata.ratingKey}';
|
||||
final globalKey = metadata.globalKey;
|
||||
|
||||
// Get artwork reference and resolve to local path using hash (includes serverId)
|
||||
final artwork = downloadProvider.getArtworkPaths(globalKey);
|
||||
|
||||
@@ -263,7 +263,7 @@ class MediaContextMenuState extends State<MediaContextMenu> {
|
||||
mediaType == PlexMediaType.show ||
|
||||
mediaType == PlexMediaType.season) {
|
||||
final downloadProvider = Provider.of<DownloadProvider>(context, listen: false);
|
||||
final globalKey = '${metadata.serverId}:${metadata.ratingKey}';
|
||||
final globalKey = metadata.globalKey;
|
||||
final isDownloaded = downloadProvider.isDownloaded(globalKey);
|
||||
|
||||
if (isDownloaded) {
|
||||
@@ -1063,7 +1063,7 @@ class MediaContextMenuState extends State<MediaContextMenu> {
|
||||
|
||||
// Check if the item is downloaded and use local file path if available
|
||||
final downloadProvider = Provider.of<DownloadProvider>(context, listen: false);
|
||||
final globalKey = '${metadata.serverId}:${metadata.ratingKey}';
|
||||
final globalKey = metadata.globalKey;
|
||||
if (downloadProvider.isDownloaded(globalKey)) {
|
||||
final videoPath = await downloadProvider.getVideoFilePath(globalKey);
|
||||
if (videoPath != null && context.mounted) {
|
||||
@@ -1107,7 +1107,7 @@ class MediaContextMenuState extends State<MediaContextMenu> {
|
||||
Future<void> _handleDeleteDownload(BuildContext context) async {
|
||||
final downloadProvider = Provider.of<DownloadProvider>(context, listen: false);
|
||||
final metadata = widget.item as PlexMetadata;
|
||||
final globalKey = '${metadata.serverId}:${metadata.ratingKey}';
|
||||
final globalKey = metadata.globalKey;
|
||||
|
||||
// Show confirmation dialog
|
||||
final confirmed = await showDeleteConfirmation(
|
||||
|
||||
Reference in New Issue
Block a user