fix(ui): refresh stale watch state
This commit is contained in:
@@ -46,11 +46,13 @@ import '../../../services/storage_service.dart';
|
||||
import '../../../services/settings_service.dart';
|
||||
import '../../../mixins/grid_focus_node_mixin.dart';
|
||||
import '../../../mixins/item_updatable.dart';
|
||||
import '../../../mixins/watch_state_aware.dart';
|
||||
import '../../../mixins/deletion_aware.dart';
|
||||
import '../../../mixins/paginated_item_loader.dart';
|
||||
import '../../../widgets/skeleton_media_card.dart';
|
||||
import '../../../utils/deletion_notifier.dart';
|
||||
import '../../../utils/global_key_utils.dart';
|
||||
import '../../../utils/watch_state_notifier.dart';
|
||||
import '../../../utils/platform_detector.dart';
|
||||
import '../../../i18n/strings.g.dart';
|
||||
import '../../main_screen.dart';
|
||||
@@ -81,7 +83,13 @@ class LibraryBrowseTab extends BaseLibraryTab<MediaItem> {
|
||||
}
|
||||
|
||||
class _LibraryBrowseTabState extends BaseLibraryTabState<MediaItem, LibraryBrowseTab>
|
||||
with ItemUpdatable, LibraryTabFocusMixin, GridFocusNodeMixin, DeletionAware, PaginatedItemLoader<LibraryBrowseTab> {
|
||||
with
|
||||
ItemUpdatable,
|
||||
LibraryTabFocusMixin,
|
||||
GridFocusNodeMixin,
|
||||
WatchStateAware,
|
||||
DeletionAware,
|
||||
PaginatedItemLoader<LibraryBrowseTab> {
|
||||
@override
|
||||
String? get itemServerId => widget.library.serverId;
|
||||
|
||||
@@ -91,6 +99,25 @@ class _LibraryBrowseTabState extends BaseLibraryTabState<MediaItem, LibraryBrows
|
||||
@override
|
||||
String? get deletionServerId => widget.library.serverId;
|
||||
|
||||
@override
|
||||
String? get watchStateServerId => widget.library.serverId;
|
||||
|
||||
@override
|
||||
Set<String>? get watchedIds => loadedItems.values.map((e) => e.id).toSet();
|
||||
|
||||
@override
|
||||
Set<String>? get watchedGlobalKeys {
|
||||
if (loadedItems.isEmpty) return <String>{};
|
||||
|
||||
final keys = <String>{};
|
||||
for (final item in loadedItems.values) {
|
||||
final serverId = item.serverId ?? widget.library.serverId;
|
||||
if (serverId == null) return null;
|
||||
keys.add(_toGlobalKey(item.id, serverId: serverId));
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
@override
|
||||
Set<String>? get deletionIds => loadedItems.values.map((e) => e.id).toSet();
|
||||
|
||||
@@ -107,6 +134,21 @@ class _LibraryBrowseTabState extends BaseLibraryTabState<MediaItem, LibraryBrows
|
||||
return keys;
|
||||
}
|
||||
|
||||
@override
|
||||
void onWatchStateChanged(WatchStateEvent event) {
|
||||
if (event.changeType == WatchStateChangeType.progressUpdate ||
|
||||
event.changeType == WatchStateChangeType.removedFromContinueWatching) {
|
||||
return;
|
||||
}
|
||||
|
||||
final affectedIds = {event.itemId, ...event.parentChain};
|
||||
for (final item in loadedItems.values) {
|
||||
if (affectedIds.contains(item.id)) {
|
||||
unawaited(updateItem(item.id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void onDeletionEvent(DeletionEvent event) {
|
||||
// If we have an item that matches the rating key exactly, remove it and rebuild indices
|
||||
@@ -154,14 +196,12 @@ class _LibraryBrowseTabState extends BaseLibraryTabState<MediaItem, LibraryBrows
|
||||
|
||||
@override
|
||||
void updateItemInLists(String itemId, MediaItem updatedMetadata) {
|
||||
setState(() {
|
||||
for (final entry in loadedItems.entries) {
|
||||
if (entry.value.id == itemId) {
|
||||
loadedItems[entry.key] = updatedMetadata;
|
||||
break;
|
||||
}
|
||||
for (final entry in loadedItems.entries) {
|
||||
if (entry.value.id == itemId) {
|
||||
loadedItems[entry.key] = updatedMetadata;
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Browse-specific state (not in base class)
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
|
||||
@@ -5,7 +7,10 @@ import '../../../i18n/strings.g.dart';
|
||||
import '../../../media/media_hub.dart';
|
||||
import '../../../media/media_item.dart';
|
||||
import '../../../mixins/item_updatable.dart';
|
||||
import '../../../mixins/watch_state_aware.dart';
|
||||
import '../../../utils/global_key_utils.dart';
|
||||
import '../../../utils/provider_extensions.dart';
|
||||
import '../../../utils/watch_state_notifier.dart';
|
||||
import '../../../widgets/hub_section.dart';
|
||||
import '../../main_screen.dart';
|
||||
import 'base_library_tab.dart';
|
||||
@@ -26,13 +31,45 @@ class LibraryRecommendedTab extends BaseLibraryTab<MediaHub> {
|
||||
State<LibraryRecommendedTab> createState() => _LibraryRecommendedTabState();
|
||||
}
|
||||
|
||||
class _LibraryRecommendedTabState extends BaseLibraryTabState<MediaHub, LibraryRecommendedTab> with ItemUpdatable {
|
||||
class _LibraryRecommendedTabState extends BaseLibraryTabState<MediaHub, LibraryRecommendedTab>
|
||||
with ItemUpdatable, WatchStateAware {
|
||||
/// GlobalKeys for each hub section to enable vertical navigation
|
||||
final List<GlobalKey<HubSectionState>> _hubKeys = [];
|
||||
|
||||
@override
|
||||
String? get itemServerId => widget.library.serverId;
|
||||
|
||||
@override
|
||||
String? get watchStateServerId => widget.library.serverId;
|
||||
|
||||
@override
|
||||
Set<String>? get watchedIds {
|
||||
final keys = <String>{};
|
||||
for (final hub in items) {
|
||||
for (final item in hub.items) {
|
||||
keys.add(item.id);
|
||||
if (item.parentId != null) keys.add(item.parentId!);
|
||||
if (item.grandparentId != null) keys.add(item.grandparentId!);
|
||||
}
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
@override
|
||||
Set<String>? get watchedGlobalKeys {
|
||||
final keys = <String>{};
|
||||
for (final hub in items) {
|
||||
for (final item in hub.items) {
|
||||
final serverId = item.serverId ?? widget.library.serverId;
|
||||
if (serverId == null) return null;
|
||||
keys.add(buildGlobalKey(serverId, item.id));
|
||||
if (item.parentId != null) keys.add(buildGlobalKey(serverId, item.parentId!));
|
||||
if (item.grandparentId != null) keys.add(buildGlobalKey(serverId, item.grandparentId!));
|
||||
}
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
@override
|
||||
void updateItemInLists(String itemId, MediaItem updatedItem) {
|
||||
// Update the item in any hub that contains it. MediaHub items are
|
||||
@@ -48,6 +85,43 @@ class _LibraryRecommendedTabState extends BaseLibraryTabState<MediaHub, LibraryR
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void onWatchStateChanged(WatchStateEvent event) {
|
||||
if (event.changeType == WatchStateChangeType.progressUpdate) return;
|
||||
|
||||
if (event.changeType == WatchStateChangeType.removedFromContinueWatching) {
|
||||
_removeContinueWatchingItem(event.itemId);
|
||||
unawaited(loadItems());
|
||||
return;
|
||||
}
|
||||
|
||||
final affectedIds = {event.itemId, ...event.parentChain};
|
||||
final refreshIds = <String>{};
|
||||
for (final hub in items) {
|
||||
for (final item in hub.items) {
|
||||
if (affectedIds.contains(item.id)) {
|
||||
refreshIds.add(item.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (final itemId in refreshIds) {
|
||||
unawaited(updateItem(itemId));
|
||||
}
|
||||
}
|
||||
|
||||
void _removeContinueWatchingItem(String itemId) {
|
||||
setState(() {
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
final hub = items[i];
|
||||
if (!_isContinueWatchingHub(hub)) continue;
|
||||
final newItems = hub.items.where((item) => item.id != itemId).toList();
|
||||
if (newItems.length != hub.items.length) {
|
||||
items[i] = hub.copyWith(items: newItems, size: newItems.length);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
IconData get emptyIcon => Symbols.recommend_rounded;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user