MemoryLogOutput extended LogOutput but was never wired as a Logger output (storage happens in the printer); DeletionNotifier/WatchStateNotifier's forServer/forItem filtered streams and WatchStateEvent.mediaType had no production consumers (tests now filter .stream directly); context.hiddenLibraries/profileSettings and toPlexUrl had zero call sites; MonoTokens.splashFactory was never read; OptimizedMediaImage's enableTranscoding/cacheKey chains, FocusableMediaCard.width/height/forceGridMode, TvBrowseRail's constant-zero gap functions, and media_image_helper's scaleFactor were never varied by any caller. The sha1 LRU stays (rebuild-hot artwork URLs); TvRailTrailing.none and the mono-theme copyWith stay live (lerp delegates to copyWith). Also carries the MusicPlayContext.id argument drops in the music screens and remaining sweep test updates.
87 lines
2.6 KiB
Dart
87 lines
2.6 KiB
Dart
import '../media/media_item.dart';
|
|
import '../media/ids.dart';
|
|
import 'app_logger.dart';
|
|
import 'base_notifier.dart';
|
|
import 'global_key_utils.dart';
|
|
import 'hierarchical_event_mixin.dart';
|
|
import 'media_event_keys.dart';
|
|
|
|
/// Event representing a media item deletion with parent chain for hierarchical invalidation
|
|
class DeletionEvent with HierarchicalEventMixin {
|
|
/// The id of the deleted item (Plex ratingKey, Jellyfin GUID, …).
|
|
@override
|
|
final String itemId;
|
|
|
|
/// Composite key: serverId:itemId
|
|
@override
|
|
final String globalKey;
|
|
|
|
/// Server this item belongs to
|
|
@override
|
|
final ServerId serverId;
|
|
|
|
/// Parent chain for hierarchical invalidation
|
|
/// For an episode: [seasonId, showId]
|
|
/// For a season: [showId]
|
|
/// For a movie: []
|
|
@override
|
|
final List<String> parentChain;
|
|
|
|
/// Media type of the deleted item
|
|
final String mediaType;
|
|
|
|
/// Number of leaf items (episodes) contained in the deleted item.
|
|
/// For an episode: 1. For a season: its episode count. For a show: its total episode count.
|
|
final int leafCount;
|
|
|
|
/// True if only the local download was deleted (not the server-side media).
|
|
/// Screens should only remove items for download deletions when in offline mode.
|
|
final bool isDownloadOnly;
|
|
|
|
DeletionEvent({
|
|
required this.itemId,
|
|
required this.serverId,
|
|
required this.parentChain,
|
|
required this.mediaType,
|
|
this.leafCount = 1,
|
|
this.isDownloadOnly = false,
|
|
}) : globalKey = buildGlobalKey(ServerId(serverId), itemId);
|
|
|
|
@override
|
|
String toString() => 'DeletionEvent(deleted: $globalKey, type: $mediaType, parents: $parentChain)';
|
|
}
|
|
|
|
/// Notifier for media deletion events across the app.
|
|
///
|
|
/// Singleton pattern following [WatchStateNotifier]. Screens subscribe
|
|
/// to receive events when items are deleted from the server.
|
|
class DeletionNotifier extends BaseNotifier<DeletionEvent> {
|
|
static final DeletionNotifier _instance = DeletionNotifier._internal();
|
|
|
|
factory DeletionNotifier() => _instance;
|
|
|
|
DeletionNotifier._internal();
|
|
|
|
/// Emit a deletion event with logging
|
|
@override
|
|
void notify(DeletionEvent event) {
|
|
appLogger.d('DeletionNotifier: $event');
|
|
super.notify(event);
|
|
}
|
|
|
|
void notifyDeletedItem({required MediaItem item, bool isDownloadOnly = false}) {
|
|
final serverId = serverIdForEvent(item, notifier: 'DeletionNotifier', event: 'deletion');
|
|
if (serverId == null) return;
|
|
notify(
|
|
DeletionEvent(
|
|
itemId: item.id,
|
|
serverId: serverId,
|
|
parentChain: item.parentChain,
|
|
mediaType: item.kind.id,
|
|
leafCount: item.leafCount ?? 1,
|
|
isDownloadOnly: isDownloadOnly,
|
|
),
|
|
);
|
|
}
|
|
}
|