From e7349dd28f00cb3775d868d2402f39647cd444b0 Mon Sep 17 00:00:00 2001 From: tapframe <85391825+tapframe@users.noreply.github.com> Date: Wed, 22 Jul 2026 03:44:31 +0530 Subject: [PATCH] refactor(tracking): remove shared feature coupling --- .../composeResources/values/strings.xml | 2 +- .../core/storage/LocalAccountDataCleaner.kt | 4 ++-- .../app/core/sync/ProfileSettingsSync.kt | 10 +++++----- .../com/nuvio/app/core/sync/SyncManager.kt | 12 +++++------ .../features/details/MetaDetailsRepository.kt | 20 +++++++++---------- .../app/features/details/MetaDetailsScreen.kt | 10 +++++----- .../com/nuvio/app/features/home/HomeScreen.kt | 16 +++++++-------- .../library/LibraryDisplaySettings.kt | 9 ++++++--- .../features/library/LibrarySavedContent.kt | 6 +++--- .../EpisodeReleaseNotificationsRepository.kt | 4 ++-- .../features/profiles/ProfileRepository.kt | 4 ++-- .../app/features/tracking/TrackingSettings.kt | 4 ++++ .../app/features/watched/WatchedModels.kt | 4 ++-- .../library/LibraryDisplaySettingsTest.kt | 18 +++++++++++++++-- .../app/features/watched/WatchedModelsTest.kt | 4 ++-- .../watching/application/WatchingStateTest.kt | 4 ++-- 16 files changed, 76 insertions(+), 55 deletions(-) diff --git a/composeApp/src/commonMain/composeResources/values/strings.xml b/composeApp/src/commonMain/composeResources/values/strings.xml index b170f2b4b..a4501dc07 100644 --- a/composeApp/src/commonMain/composeResources/values/strings.xml +++ b/composeApp/src/commonMain/composeResources/values/strings.xml @@ -1657,7 +1657,7 @@ Recently added Title A–Z Title Z–A - Trakt order + Tracker order Cloud Saved Library diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/core/storage/LocalAccountDataCleaner.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/core/storage/LocalAccountDataCleaner.kt index 3fd89740c..9a4b00399 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/core/storage/LocalAccountDataCleaner.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/core/storage/LocalAccountDataCleaner.kt @@ -29,7 +29,7 @@ import com.nuvio.app.features.streams.StreamBadgeSettingsRepository import com.nuvio.app.features.streams.StreamLaunchStore import com.nuvio.app.features.streams.StreamsRepository import com.nuvio.app.features.tracking.TrackingProviderRegistry -import com.nuvio.app.features.trakt.TraktSettingsRepository +import com.nuvio.app.features.tracking.TrackingSettingsRepository import com.nuvio.app.core.ui.CardDepthStyleRepository import com.nuvio.app.core.ui.PosterCardStyleRepository import com.nuvio.app.features.watchprogress.ContinueWatchingPreferencesRepository @@ -70,7 +70,7 @@ internal object LocalAccountDataCleaner { PosterCardStyleRepository.clearLocalState() CardDepthStyleRepository.clearLocalState() TrackingProviderRegistry.clearLocalState() - TraktSettingsRepository.clearLocalState() + TrackingSettingsRepository.clearLocalState() PlayerSettingsRepository.clearLocalState() StreamBadgeSettingsRepository.clearLocalState() P2pSettingsRepository.clearLocalState() diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/core/sync/ProfileSettingsSync.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/core/sync/ProfileSettingsSync.kt index 31322ad11..7e6a5472a 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/core/sync/ProfileSettingsSync.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/core/sync/ProfileSettingsSync.kt @@ -30,7 +30,7 @@ import com.nuvio.app.features.tmdb.TmdbSettingsRepository import com.nuvio.app.features.trakt.TraktCommentsStorage import com.nuvio.app.features.trakt.TraktCommentsSettings import com.nuvio.app.features.trakt.TraktSettingsStorage -import com.nuvio.app.features.trakt.TraktSettingsRepository +import com.nuvio.app.features.tracking.TrackingSettingsRepository import com.nuvio.app.features.watchprogress.ContinueWatchingPreferencesStorage import com.nuvio.app.features.watchprogress.ContinueWatchingPreferencesRepository import io.github.jan.supabase.postgrest.postgrest @@ -184,7 +184,7 @@ object ProfileSettingsSync { MetaScreenSettingsRepository.uiState.map { "meta" }, CollectionMobileSettingsRepository.uiState.map { "collection_mobile_settings" }, ContinueWatchingPreferencesRepository.uiState.map { "continue_watching" }, - TraktSettingsRepository.uiState.map { "trakt_settings" }, + TrackingSettingsRepository.uiState.map { "trakt_settings" }, TraktCommentsSettings.enabled.map { "trakt_comments" }, EpisodeReleaseNotificationsRepository.uiState.map { "episode_release_alerts" }, ) @@ -278,7 +278,7 @@ object ProfileSettingsSync { ContinueWatchingPreferencesRepository.onProfileChanged() TraktSettingsStorage.savePayload(blob.features.traktSettingsPayload) - TraktSettingsRepository.onProfileChanged() + TrackingSettingsRepository.onProfileChanged() TraktCommentsStorage.replaceFromSyncPayload(blob.features.traktCommentsSettings) TraktCommentsSettings.onProfileChanged() @@ -298,7 +298,7 @@ object ProfileSettingsSync { MetaScreenSettingsRepository.ensureLoaded() CollectionMobileSettingsRepository.ensureLoaded() ContinueWatchingPreferencesRepository.ensureLoaded() - TraktSettingsRepository.ensureLoaded() + TrackingSettingsRepository.ensureLoaded() TraktCommentsSettings.ensureLoaded() EpisodeReleaseNotificationsRepository.ensureLoaded() } @@ -321,7 +321,7 @@ object ProfileSettingsSync { "meta=${MetaScreenSettingsRepository.uiState.value}", "collection_mobile_settings=${CollectionMobileSettingsRepository.uiState.value}", "continue=${ContinueWatchingPreferencesRepository.uiState.value}", - "trakt_settings=${TraktSettingsRepository.uiState.value}", + "trakt_settings=${TrackingSettingsRepository.uiState.value}", "trakt_comments=${TraktCommentsSettings.enabled.value}", "episode_release_alerts=${EpisodeReleaseNotificationsRepository.uiState.value.isEnabled}", ).joinToString(separator = "||") diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/core/sync/SyncManager.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/core/sync/SyncManager.kt index 7a6358337..87727fc27 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/core/sync/SyncManager.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/core/sync/SyncManager.kt @@ -4,6 +4,7 @@ import co.touchlab.kermit.Logger import com.nuvio.app.core.auth.AuthRepository import com.nuvio.app.core.auth.AuthState import com.nuvio.app.core.build.AppFeaturePolicy +import com.nuvio.app.core.time.EpisodeReleaseDatePlatform import com.nuvio.app.features.addons.AddonRepository import com.nuvio.app.features.collection.CollectionSyncService import com.nuvio.app.features.home.HomeCatalogSettingsSyncService @@ -11,9 +12,8 @@ import com.nuvio.app.features.library.LibrarySourceMode import com.nuvio.app.features.library.LibraryRepository import com.nuvio.app.features.plugins.PluginRepository import com.nuvio.app.features.profiles.ProfileRepository -import com.nuvio.app.features.trakt.TraktPlatformClock -import com.nuvio.app.features.trakt.TraktSettingsRepository import com.nuvio.app.features.tracking.TrackingProviderRegistry +import com.nuvio.app.features.tracking.TrackingSettingsRepository import com.nuvio.app.features.tracking.WatchProgressSource import com.nuvio.app.features.tracking.effectiveLibrarySourceMode import com.nuvio.app.features.tracking.effectiveWatchProgressSource @@ -305,7 +305,7 @@ object SyncManager { private fun hasRecentFullPull(profileId: Int): Boolean = synchronized(pullStateLock) { lastFullPullProfileId == profileId && - TraktPlatformClock.nowEpochMs() - lastFullPullAtMs < FOREGROUND_PULL_MIN_INTERVAL_MS + EpisodeReleaseDatePlatform.nowEpochMs() - lastFullPullAtMs < FOREGROUND_PULL_MIN_INTERVAL_MS } private suspend fun pullForegroundForProfile(profileId: Int) { @@ -383,7 +383,7 @@ object SyncManager { } if (syncResult.succeeded) { synchronized(pullStateLock) { - lastFullPullAtMs = TraktPlatformClock.nowEpochMs() + lastFullPullAtMs = EpisodeReleaseDatePlatform.nowEpochMs() lastFullPullProfileId = profileId } } else { @@ -429,9 +429,9 @@ object SyncManager { } TrackingProviderRegistry.ensureLoaded() - TraktSettingsRepository.ensureLoaded() + TrackingSettingsRepository.ensureLoaded() - val settings = TraktSettingsRepository.uiState.value + val settings = TrackingSettingsRepository.uiState.value val shouldPullLibrary = effectiveLibrarySourceMode( requestedSource = settings.librarySourceMode, isProviderAuthenticated = TrackingProviderRegistry::isAuthenticated, diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/details/MetaDetailsRepository.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/details/MetaDetailsRepository.kt index 687820da5..d1820f92e 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/details/MetaDetailsRepository.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/details/MetaDetailsRepository.kt @@ -16,7 +16,7 @@ import com.nuvio.app.features.tmdb.TmdbSettingsRepository import com.nuvio.app.features.trakt.TraktAuthRepository import com.nuvio.app.features.trakt.TraktConnectionMode import com.nuvio.app.features.trakt.TraktRelatedRepository -import com.nuvio.app.features.trakt.TraktSettingsRepository +import com.nuvio.app.features.tracking.TrackingSettingsRepository import com.nuvio.app.features.trakt.shouldUseTraktMoreLikeThis import com.nuvio.app.features.watchprogress.CurrentDateProvider import kotlinx.coroutines.CancellationException @@ -408,15 +408,15 @@ object MetaDetailsRepository { fallbackItemId: String, fallbackItemType: String, ): MetaDetails { - TraktSettingsRepository.ensureLoaded() + TrackingSettingsRepository.ensureLoaded() TraktAuthRepository.ensureLoaded() TmdbSettingsRepository.ensureLoaded() - val traktSettings = TraktSettingsRepository.uiState.value + val trackingSettings = TrackingSettingsRepository.uiState.value val isTraktAuthenticated = TraktAuthRepository.uiState.value.mode == TraktConnectionMode.CONNECTED val shouldUseTrakt = shouldUseTraktMoreLikeThis( isAuthenticated = isTraktAuthenticated, - source = traktSettings.moreLikeThisSource, + source = trackingSettings.moreLikeThisSource, ) && supportsMoreLikeThis(meta, fallbackItemType) if (shouldUseTrakt) { @@ -466,32 +466,32 @@ object MetaDetailsRepository { } private fun shouldApplyMoreLikeThisSource(meta: MetaDetails): Boolean { - TraktSettingsRepository.ensureLoaded() + TrackingSettingsRepository.ensureLoaded() TraktAuthRepository.ensureLoaded() TmdbSettingsRepository.ensureLoaded() - val traktSettings = TraktSettingsRepository.uiState.value + val trackingSettings = TrackingSettingsRepository.uiState.value val isTraktAuthenticated = TraktAuthRepository.uiState.value.mode == TraktConnectionMode.CONNECTED val tmdbSettings = TmdbSettingsRepository.snapshot() return shouldUseTraktMoreLikeThis( isAuthenticated = isTraktAuthenticated, - source = traktSettings.moreLikeThisSource, + source = trackingSettings.moreLikeThisSource, ) || !tmdbSettings.enabled || !tmdbSettings.useMoreLikeThis || meta.moreLikeThisSource == null && meta.moreLikeThis.isNotEmpty() } private fun buildMetaScreenSettingsFingerprint( settings: com.nuvio.app.features.mdblist.MdbListSettings, ): String { - TraktSettingsRepository.ensureLoaded() + TrackingSettingsRepository.ensureLoaded() TraktAuthRepository.ensureLoaded() TmdbSettingsRepository.ensureLoaded() val providers = settings.enabledProvidersInPriorityOrder().joinToString(",") - val traktSettings = TraktSettingsRepository.uiState.value + val trackingSettings = TrackingSettingsRepository.uiState.value val traktAuthMode = TraktAuthRepository.uiState.value.mode val tmdbSettings = TmdbSettingsRepository.snapshot() return buildString { append("${settings.enabled}:${settings.apiKey.trim()}:$providers") - append("|more_like=${traktSettings.moreLikeThisSource}:$traktAuthMode") + append("|more_like=${trackingSettings.moreLikeThisSource}:$traktAuthMode") append("|tmdb=${tmdbSettings.enabled}:${tmdbSettings.useMoreLikeThis}:${tmdbSettings.hasApiKey}:${tmdbSettings.language}") } } diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/details/MetaDetailsScreen.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/details/MetaDetailsScreen.kt index c3b269788..a4932a04d 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/details/MetaDetailsScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/details/MetaDetailsScreen.kt @@ -116,7 +116,7 @@ import com.nuvio.app.features.trakt.TraktCommentsRepository import com.nuvio.app.features.trakt.TraktCommentsSettings import com.nuvio.app.features.trakt.TraktConnectionMode import com.nuvio.app.features.tracking.TrackingLibraryTab -import com.nuvio.app.features.trakt.TraktSettingsRepository +import com.nuvio.app.features.tracking.TrackingSettingsRepository import com.nuvio.app.features.tracking.TrackingProviderId import com.nuvio.app.features.trailer.TrailerPlaybackResolver import com.nuvio.app.features.trailer.TrailerPlaybackSource @@ -165,9 +165,9 @@ fun MetaDetailsScreen( TraktAuthRepository.ensureLoaded() TraktAuthRepository.uiState }.collectAsStateWithLifecycle() - val traktSettingsUiState by remember { - TraktSettingsRepository.ensureLoaded() - TraktSettingsRepository.uiState + val trackingSettingsUiState by remember { + TrackingSettingsRepository.ensureLoaded() + TrackingSettingsRepository.uiState }.collectAsStateWithLifecycle() val tmdbSettingsUiState by remember { TmdbSettingsRepository.ensureLoaded() @@ -292,7 +292,7 @@ fun MetaDetailsScreen( id, displayedMeta?.id, uiState.isLoading, - traktSettingsUiState.moreLikeThisSource, + trackingSettingsUiState.moreLikeThisSource, traktAuthUiState.mode, tmdbSettingsUiState.enabled, tmdbSettingsUiState.useMoreLikeThis, 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 be2bca10c..5c3d30ef6 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 @@ -50,7 +50,7 @@ import com.nuvio.app.features.home.components.HomeSkeletonRow import com.nuvio.app.features.home.components.HomeContinueWatchingSectionBottomPadding import com.nuvio.app.features.home.components.ContinueWatchingLayout import com.nuvio.app.features.trakt.TRAKT_CONTINUE_WATCHING_DAYS_CAP_ALL -import com.nuvio.app.features.trakt.TraktSettingsRepository +import com.nuvio.app.features.tracking.TrackingSettingsRepository import com.nuvio.app.features.tracking.WatchProgressSource import com.nuvio.app.features.trakt.normalizeTraktContinueWatchingDaysCap import com.nuvio.app.features.watched.WatchedItem @@ -147,9 +147,9 @@ fun HomeScreen( val effectiveWatchProgressSource by WatchProgressRepository.activeSourceState.collectAsStateWithLifecycle() val cloudLibraryUiState by CloudLibraryRepository.uiState.collectAsStateWithLifecycle() val networkStatusUiState by NetworkStatusRepository.uiState.collectAsStateWithLifecycle() - val traktSettingsUiState by remember { - TraktSettingsRepository.ensureLoaded() - TraktSettingsRepository.uiState + val trackingSettingsUiState by remember { + TrackingSettingsRepository.ensureLoaded() + TrackingSettingsRepository.uiState }.collectAsStateWithLifecycle() var observedOfflineState by remember { mutableStateOf(false) } @@ -189,7 +189,7 @@ fun HomeScreen( val effectiveWatchProgressEntries = remember( watchProgressUiState.entries, isTraktProgressActive, - traktSettingsUiState.continueWatchingDaysCap, + trackingSettingsUiState.continueWatchingDaysCap, ) { val filtered = if (isTraktProgressActive) { watchProgressUiState.entries.filter { !WatchProgressRepository.isDroppedShow(it.parentMetaId) } @@ -199,7 +199,7 @@ fun HomeScreen( filterEntriesForTraktContinueWatchingWindow( entries = filtered, isTraktProgressActive = isTraktProgressActive, - daysCap = traktSettingsUiState.continueWatchingDaysCap, + daysCap = trackingSettingsUiState.continueWatchingDaysCap, nowEpochMs = WatchProgressClock.nowEpochMs(), ) } @@ -227,12 +227,12 @@ fun HomeScreen( val recentNextUpSeedCandidates = remember( allNextUpSeedCandidates, isTraktProgressActive, - traktSettingsUiState.continueWatchingDaysCap, + trackingSettingsUiState.continueWatchingDaysCap, ) { filterHomeNextUpCandidatesForTraktContinueWatchingWindow( candidates = allNextUpSeedCandidates, isTraktProgressActive = isTraktProgressActive, - daysCap = traktSettingsUiState.continueWatchingDaysCap, + daysCap = trackingSettingsUiState.continueWatchingDaysCap, nowEpochMs = WatchProgressClock.nowEpochMs(), ) } diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/library/LibraryDisplaySettings.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/library/LibraryDisplaySettings.kt index d7f2b7752..af31a9421 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/library/LibraryDisplaySettings.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/library/LibraryDisplaySettings.kt @@ -85,7 +85,7 @@ internal data class LibraryVerticalProjection( ) internal fun availableLibrarySortOptions(sourceMode: LibrarySourceMode): List = - if (sourceMode == LibrarySourceMode.TRAKT) { + if (sourceMode.isRemoteTrackingSource) { LibrarySortOption.entries } else { LibrarySortOption.entries.filterNot { it == LibrarySortOption.DEFAULT } @@ -149,8 +149,8 @@ internal fun buildLibraryVerticalProjection( selectedType: String?, sortOption: LibrarySortOption, ): LibraryVerticalProjection { - val availableSections = if (sourceMode == LibrarySourceMode.TRAKT) sections else emptyList() - val selectedSection = if (sourceMode == LibrarySourceMode.TRAKT) { + val availableSections = if (sourceMode.isRemoteTrackingSource) sections else emptyList() + val selectedSection = if (sourceMode.isRemoteTrackingSource) { sections.firstOrNull { it.type == selectedSectionKey } ?: sections.firstOrNull() } else { null @@ -244,6 +244,9 @@ private fun libraryDisplayItemKey(item: LibraryItem): String = private fun String.normalizedLibraryType(): String = trim().lowercase() +internal val LibrarySourceMode.isRemoteTrackingSource: Boolean + get() = this != LibrarySourceMode.LOCAL + @Serializable private data class StoredLibraryDisplaySettings( @SerialName("layout_mode") val layoutMode: String = LibraryLayoutMode.HORIZONTAL.name, diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/library/LibrarySavedContent.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/library/LibrarySavedContent.kt index b5fc5c467..d3a9d6ddd 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/library/LibrarySavedContent.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/library/LibrarySavedContent.kt @@ -27,7 +27,7 @@ import nuvio.composeapp.generated.resources.library_sort_added_asc import nuvio.composeapp.generated.resources.library_sort_added_desc import nuvio.composeapp.generated.resources.library_sort_title_asc import nuvio.composeapp.generated.resources.library_sort_title_desc -import nuvio.composeapp.generated.resources.library_sort_trakt_order +import nuvio.composeapp.generated.resources.library_sort_provider_order import org.jetbrains.compose.resources.stringResource @Composable @@ -48,7 +48,7 @@ internal fun LibrarySavedControls( modifier = modifier.horizontalScroll(rememberScrollState()), horizontalArrangement = Arrangement.spacedBy(8.dp), ) { - if (layoutMode == LibraryLayoutMode.VERTICAL && sourceMode == LibrarySourceMode.TRAKT) { + if (layoutMode == LibraryLayoutMode.VERTICAL && sourceMode.isRemoteTrackingSource) { val selectedSection = verticalProjection.availableSections .firstOrNull { section -> section.type == verticalProjection.selectedSectionKey } NuvioDropdownChip( @@ -158,7 +158,7 @@ internal fun LazyItemScope.libraryContentTransitionModifier(): Modifier = @Composable private fun librarySortOptionLabel(option: LibrarySortOption): String = when (option) { - LibrarySortOption.DEFAULT -> stringResource(Res.string.library_sort_trakt_order) + LibrarySortOption.DEFAULT -> stringResource(Res.string.library_sort_provider_order) LibrarySortOption.ADDED_DESC -> stringResource(Res.string.library_sort_added_desc) LibrarySortOption.ADDED_ASC -> stringResource(Res.string.library_sort_added_asc) LibrarySortOption.TITLE_ASC -> stringResource(Res.string.library_sort_title_asc) diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/notifications/EpisodeReleaseNotificationsRepository.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/notifications/EpisodeReleaseNotificationsRepository.kt index b7bb198fd..276fb287e 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/notifications/EpisodeReleaseNotificationsRepository.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/notifications/EpisodeReleaseNotificationsRepository.kt @@ -8,7 +8,7 @@ import com.nuvio.app.features.library.LibraryItem import com.nuvio.app.features.library.LibraryRepository import com.nuvio.app.features.library.LibraryUiState import com.nuvio.app.features.profiles.ProfileRepository -import com.nuvio.app.features.trakt.TraktPlatformClock +import com.nuvio.app.core.time.EpisodeReleaseDatePlatform import com.nuvio.app.features.watchprogress.CurrentDateProvider import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -206,7 +206,7 @@ object EpisodeReleaseNotificationsRepository { } val request = EpisodeReleaseNotificationRequest( - requestId = "episode-release-test-${ProfileRepository.activeProfileId}-${TraktPlatformClock.nowEpochMs()}", + requestId = "episode-release-test-${ProfileRepository.activeProfileId}-${EpisodeReleaseDatePlatform.nowEpochMs()}", notificationTitle = target.name, notificationBody = getString(Res.string.notifications_test_preview_body), releaseDateIso = CurrentDateProvider.todayIsoDate(), diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/profiles/ProfileRepository.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/profiles/ProfileRepository.kt index 62d1b417b..70c0ebd0f 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/profiles/ProfileRepository.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/profiles/ProfileRepository.kt @@ -27,7 +27,7 @@ import com.nuvio.app.features.search.SearchHistoryRepository import com.nuvio.app.features.settings.ThemeSettingsRepository import com.nuvio.app.features.streams.StreamBadgeSettingsRepository import com.nuvio.app.features.tracking.TrackingProviderRegistry -import com.nuvio.app.features.trakt.TraktSettingsRepository +import com.nuvio.app.features.tracking.TrackingSettingsRepository import com.nuvio.app.features.tmdb.TmdbSettingsRepository import com.nuvio.app.features.watched.WatchedRepository import com.nuvio.app.features.watchprogress.ContinueWatchingPreferencesRepository @@ -155,7 +155,7 @@ object ProfileRepository { ) persist() WatchedRepository.onProfileChanged(profileIndex) - TraktSettingsRepository.onProfileChanged() + TrackingSettingsRepository.onProfileChanged() ensureTrackingProvidersRegistered() TrackingProviderRegistry.onProfileChanged() LibraryRepository.onProfileChanged(profileIndex) diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/tracking/TrackingSettings.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/tracking/TrackingSettings.kt index 3402c7824..9756a9343 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/tracking/TrackingSettings.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/tracking/TrackingSettings.kt @@ -21,6 +21,10 @@ object TrackingSettingsRepository { fun ensureLoaded() = TraktSettingsRepository.ensureLoaded() + fun onProfileChanged() = TraktSettingsRepository.onProfileChanged() + + fun clearLocalState() = TraktSettingsRepository.clearLocalState() + fun setLibrarySourceMode(source: LibrarySourceMode) = TraktSettingsRepository.setLibrarySourceMode(source) diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/watched/WatchedModels.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/watched/WatchedModels.kt index 4aae9a591..2aab015af 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/watched/WatchedModels.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/watched/WatchedModels.kt @@ -1,7 +1,7 @@ package com.nuvio.app.features.watched +import com.nuvio.app.core.time.parseZonedIsoDateTimeToEpochMs import com.nuvio.app.features.home.MetaPreview -import com.nuvio.app.features.trakt.TraktPlatformClock import com.nuvio.app.features.watching.domain.WatchingContentRef import com.nuvio.app.features.watching.domain.watchedKey import kotlinx.serialization.Serializable @@ -72,7 +72,7 @@ internal fun normalizeWatchedMarkedAtEpochMs(value: Long): Long { append(second.toString().padStart(2, '0')) append('Z') } - return TraktPlatformClock.parseIsoDateTimeToEpochMs(iso) ?: value + return parseZonedIsoDateTimeToEpochMs(iso) ?: value } fun watchedItemKey( diff --git a/composeApp/src/commonTest/kotlin/com/nuvio/app/features/library/LibraryDisplaySettingsTest.kt b/composeApp/src/commonTest/kotlin/com/nuvio/app/features/library/LibraryDisplaySettingsTest.kt index bbfdf90bb..79c4e0762 100644 --- a/composeApp/src/commonTest/kotlin/com/nuvio/app/features/library/LibraryDisplaySettingsTest.kt +++ b/composeApp/src/commonTest/kotlin/com/nuvio/app/features/library/LibraryDisplaySettingsTest.kt @@ -6,7 +6,7 @@ import kotlin.test.assertEquals class LibraryDisplaySettingsTest { @Test - fun `local default resolves to recently added while Trakt uses rank order`() { + fun `local default resolves to recently added while remote trackers preserve provider order`() { assertEquals( LibrarySortOption.ADDED_DESC, effectiveLibrarySortOption(LibrarySortOption.DEFAULT, LibrarySourceMode.LOCAL), @@ -15,6 +15,10 @@ class LibraryDisplaySettingsTest { LibrarySortOption.DEFAULT, effectiveLibrarySortOption(LibrarySortOption.DEFAULT, LibrarySourceMode.TRAKT), ) + assertEquals( + LibrarySortOption.DEFAULT, + effectiveLibrarySortOption(LibrarySortOption.DEFAULT, LibrarySourceMode.SIMKL), + ) val input = listOf( item("ranked-second", savedAt = 3L, traktRank = 2), @@ -91,7 +95,7 @@ class LibraryDisplaySettingsTest { } @Test - fun `vertical Trakt projection selects one list then filters and sorts its items`() { + fun `vertical tracker projection selects one list then filters and sorts its items`() { val watchlist = LibrarySection( type = "watchlist", displayTitle = "Watchlist", @@ -120,6 +124,16 @@ class LibraryDisplaySettingsTest { assertEquals("movie", projection.selectedType) assertEquals(listOf("a", "z"), projection.entries.map { it.item.id }) assertEquals(listOf("watchlist", "watchlist"), projection.entries.map { it.section.type }) + + val simklProjection = buildLibraryVerticalProjection( + sections = listOf(watchlist), + sourceMode = LibrarySourceMode.SIMKL, + selectedSectionKey = null, + selectedType = null, + sortOption = LibrarySortOption.DEFAULT, + ) + assertEquals(listOf("watchlist"), simklProjection.availableSections.map { it.type }) + assertEquals("watchlist", simklProjection.selectedSectionKey) } @Test diff --git a/composeApp/src/commonTest/kotlin/com/nuvio/app/features/watched/WatchedModelsTest.kt b/composeApp/src/commonTest/kotlin/com/nuvio/app/features/watched/WatchedModelsTest.kt index 657fc8b28..0383e9f30 100644 --- a/composeApp/src/commonTest/kotlin/com/nuvio/app/features/watched/WatchedModelsTest.kt +++ b/composeApp/src/commonTest/kotlin/com/nuvio/app/features/watched/WatchedModelsTest.kt @@ -1,6 +1,6 @@ package com.nuvio.app.features.watched -import com.nuvio.app.features.trakt.TraktPlatformClock +import com.nuvio.app.core.time.parseZonedIsoDateTimeToEpochMs import com.nuvio.app.features.tracking.TrackingProviderId import com.nuvio.app.features.tracking.WatchProgressSource import com.nuvio.app.features.tracking.providerId @@ -12,7 +12,7 @@ import kotlin.test.assertTrue class WatchedModelsTest { @Test fun `compact watched timestamp normalizes to epoch millis`() { - val expected = TraktPlatformClock.parseIsoDateTimeToEpochMs("2026-04-25T10:02:00Z") + val expected = parseZonedIsoDateTimeToEpochMs("2026-04-25T10:02:00Z") assertEquals(expected, normalizeWatchedMarkedAtEpochMs(20260425100200L)) } diff --git a/composeApp/src/commonTest/kotlin/com/nuvio/app/features/watching/application/WatchingStateTest.kt b/composeApp/src/commonTest/kotlin/com/nuvio/app/features/watching/application/WatchingStateTest.kt index afcf8f73b..85d22929a 100644 --- a/composeApp/src/commonTest/kotlin/com/nuvio/app/features/watching/application/WatchingStateTest.kt +++ b/composeApp/src/commonTest/kotlin/com/nuvio/app/features/watching/application/WatchingStateTest.kt @@ -1,6 +1,6 @@ package com.nuvio.app.features.watching.application -import com.nuvio.app.features.trakt.TraktPlatformClock +import com.nuvio.app.core.time.parseZonedIsoDateTimeToEpochMs import com.nuvio.app.features.watched.WatchedItem import com.nuvio.app.features.watchprogress.WatchProgressEntry import com.nuvio.app.features.watchprogress.WatchProgressSourceTraktPlayback @@ -57,7 +57,7 @@ class WatchingStateTest { @Test fun `latest completed normalizes compact watched timestamps before sorting`() { - val expected = TraktPlatformClock.parseIsoDateTimeToEpochMs("2026-04-25T10:02:00Z") + val expected = parseZonedIsoDateTimeToEpochMs("2026-04-25T10:02:00Z") val result = WatchingState.latestCompletedBySeries( progressEntries = emptyList(),