refactor(tracking): remove shared feature coupling

This commit is contained in:
tapframe 2026-07-22 03:44:31 +05:30
parent eb5bf78c37
commit e7349dd28f
16 changed files with 76 additions and 55 deletions

View file

@ -1657,7 +1657,7 @@
<string name="library_sort_added_desc">Recently added</string>
<string name="library_sort_title_asc">Title AZ</string>
<string name="library_sort_title_desc">Title ZA</string>
<string name="library_sort_trakt_order">Trakt order</string>
<string name="library_sort_provider_order">Tracker order</string>
<string name="library_source_cloud">Cloud</string>
<string name="library_source_saved">Saved</string>
<string name="library_title">Library</string>

View file

@ -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()

View file

@ -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 = "||")

View file

@ -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,

View file

@ -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}")
}
}

View file

@ -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,

View file

@ -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(),
)
}

View file

@ -85,7 +85,7 @@ internal data class LibraryVerticalProjection(
)
internal fun availableLibrarySortOptions(sourceMode: LibrarySourceMode): List<LibrarySortOption> =
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,

View file

@ -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)

View file

@ -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(),

View file

@ -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)

View file

@ -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)

View file

@ -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(

View file

@ -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

View file

@ -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))
}

View file

@ -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(),