From 32a26951f73a8c88505ce57f4eaf72452bc055b7 Mon Sep 17 00:00:00 2001 From: tapframe <85391825+tapframe@users.noreply.github.com> Date: Fri, 12 Jun 2026 20:07:28 +0530 Subject: [PATCH] Refresh watch progress when clearing CW cache --- .../composeResources/values/strings.xml | 2 +- .../com/nuvio/app/features/home/HomeScreen.kt | 11 ++++++- .../features/settings/AdvancedSettingsPage.kt | 9 ++++++ .../ContinueWatchingEnrichmentCache.kt | 6 ++++ .../watchprogress/WatchProgressRepository.kt | 29 +++++++++++++++++++ 5 files changed, 55 insertions(+), 2 deletions(-) diff --git a/composeApp/src/commonMain/composeResources/values/strings.xml b/composeApp/src/commonMain/composeResources/values/strings.xml index be681d8d9..a79ad5e75 100644 --- a/composeApp/src/commonMain/composeResources/values/strings.xml +++ b/composeApp/src/commonMain/composeResources/values/strings.xml @@ -449,7 +449,7 @@ Remember Last Profile Remember last selected profile at startup Clear Continue Watching Cache - Remove cached thumbnails, titles, and enrichment data for Continue Watching + Remove cached Continue Watching data and refresh watch progress Cache cleared APP LICENSE DATA & SERVICES diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/HomeScreen.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/HomeScreen.kt index 0d90dfad7..de8b49839 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/HomeScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/HomeScreen.kt @@ -281,11 +281,20 @@ fun HomeScreen( } val profileState by ProfileRepository.state.collectAsStateWithLifecycle() val activeProfileId = profileState.activeProfile?.profileIndex ?: 1 + val cwCacheClearVersion by ContinueWatchingEnrichmentCache.cacheCleared.collectAsStateWithLifecycle() var nextUpItemsBySeries by remember(activeProfileId) { mutableStateOf>>(emptyMap()) } var processedNextUpContentIds by remember(activeProfileId) { mutableStateOf>(emptySet()) } - val cachedSnapshots = remember(activeProfileId) { ContinueWatchingEnrichmentCache.getSnapshots() } + LaunchedEffect(activeProfileId, cwCacheClearVersion) { + if (cwCacheClearVersion == 0) return@LaunchedEffect + nextUpItemsBySeries = emptyMap() + processedNextUpContentIds = emptySet() + } + + val cachedSnapshots = remember(activeProfileId, cwCacheClearVersion) { + ContinueWatchingEnrichmentCache.getSnapshots() + } val shouldValidateMissingNextUpSeeds = remember( isTraktProgressActive, watchProgressUiState.hasLoadedRemoteProgress, diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/AdvancedSettingsPage.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/AdvancedSettingsPage.kt index fc9f77cc1..2bffab37c 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/AdvancedSettingsPage.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/AdvancedSettingsPage.kt @@ -3,10 +3,13 @@ package com.nuvio.app.features.settings import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import com.nuvio.app.features.profiles.ProfileRepository import com.nuvio.app.features.watchprogress.ContinueWatchingEnrichmentCache +import com.nuvio.app.features.watchprogress.WatchProgressRepository +import kotlinx.coroutines.launch import nuvio.composeapp.generated.resources.Res import nuvio.composeapp.generated.resources.settings_advanced_clear_cw_cache import nuvio.composeapp.generated.resources.settings_advanced_clear_cw_cache_done @@ -43,6 +46,7 @@ internal fun LazyListScope.advancedSettingsContent( isTablet = isTablet, ) { SettingsGroup(isTablet = isTablet) { + val scope = rememberCoroutineScope() var cleared by rememberSaveable { mutableStateOf(false) } SettingsNavigationRow( title = stringResource(Res.string.settings_advanced_clear_cw_cache), @@ -56,6 +60,11 @@ internal fun LazyListScope.advancedSettingsContent( if (!cleared) { ContinueWatchingEnrichmentCache.clearAll() cleared = true + scope.launch { + WatchProgressRepository.forceSnapshotRefreshFromServer( + ProfileRepository.activeProfileId, + ) + } } }, ) diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/watchprogress/ContinueWatchingEnrichmentCache.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/watchprogress/ContinueWatchingEnrichmentCache.kt index 00226f24f..d9d5a5aac 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/watchprogress/ContinueWatchingEnrichmentCache.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/watchprogress/ContinueWatchingEnrichmentCache.kt @@ -1,6 +1,9 @@ package com.nuvio.app.features.watchprogress import com.nuvio.app.core.storage.ProfileScopedKey +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow import kotlinx.serialization.Serializable import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json @@ -63,6 +66,8 @@ internal object ContinueWatchingEnrichmentCache { private const val storageKey = "cw_enrichment_cache" private var lastPayloadHash: Int? = null + private val _cacheCleared = MutableStateFlow(0) + val cacheCleared: StateFlow = _cacheCleared.asStateFlow() fun getNextUpSnapshot(): List = loadPayload()?.nextUp ?: emptyList() @@ -98,6 +103,7 @@ internal object ContinueWatchingEnrichmentCache { fun clearAll() { ContinueWatchingEnrichmentStorage.removePayload(ProfileScopedKey.of(storageKey)) lastPayloadHash = null + _cacheCleared.value += 1 } private fun loadPayload(): CachedEnrichmentPayload? { diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/watchprogress/WatchProgressRepository.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/watchprogress/WatchProgressRepository.kt index bc695a47f..478dcabda 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/watchprogress/WatchProgressRepository.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/watchprogress/WatchProgressRepository.kt @@ -251,6 +251,35 @@ object WatchProgressRepository { } } + suspend fun forceSnapshotRefreshFromServer(profileId: Int) { + ensureLoaded() + if (currentProfileId != profileId) { + loadFromDisk(profileId) + } + + if (shouldUseTraktProgress()) { + log.d { "Force refreshing Trakt watch progress for profile $profileId" } + runCatching { TraktProgressRepository.refreshNow() } + .onFailure { error -> + if (error is CancellationException) throw error + log.e(error) { "Failed to force refresh Trakt progress" } + } + publish() + return + } + + val authState = AuthRepository.state.value + if (authState !is AuthState.Authenticated || authState.isAnonymous) { + log.d { "Skipping force watch progress refresh because Nuvio Sync is not authenticated" } + return + } + + deltaCursorEventId = 0L + deltaInitialized = false + persist() + pullFromServer(profileId) + } + private suspend fun pullSupabaseDeltaFromServer( profileId: Int, pullStartedEpochMs: Long,