From fc38e5fa861afd014f77f7e46f7a2bddcce07ef2 Mon Sep 17 00:00:00 2001 From: tapframe <85391825+tapframe@users.noreply.github.com> Date: Thu, 9 Jul 2026 21:40:37 +0530 Subject: [PATCH] fix: preserve home catalog sync keys --- .../home/HomeCatalogSettingsRepository.kt | 74 +++++++++++++++---- .../home/HomeCatalogSettingsSyncService.kt | 1 + 2 files changed, 61 insertions(+), 14 deletions(-) diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/HomeCatalogSettingsRepository.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/HomeCatalogSettingsRepository.kt index 067502d36..de504b5e8 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/HomeCatalogSettingsRepository.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/HomeCatalogSettingsRepository.kt @@ -393,7 +393,7 @@ object HomeCatalogSettingsRepository { transform: (StoredHomeCatalogPreference) -> StoredHomeCatalogPreference, ) { ensureLoaded() - val current = preferences[key] ?: return + val current = preferences[key] ?: defaultPreferenceForMissingKey(key) ?: return val updated = transform(current) if (updated == current) return preferences[key] = updated @@ -442,9 +442,12 @@ object HomeCatalogSettingsRepository { fun exportToSyncPayload(): SyncHomeCatalogPayload { ensureLoaded() + val catalogDefinitionsByKey = definitions.associateBy { it.key } + val collectionDefinitionsByKey = collectionDefinitions.associateBy { it.key } val items = preferences.values.sortedBy { it.order }.map { pref -> - val parts = pref.key.split(":") - val isCollection = pref.key.startsWith("collection_") + val catalogDefinition = catalogDefinitionsByKey[pref.key] + val collectionDefinition = collectionDefinitionsByKey[pref.key] + val isCollection = collectionDefinition != null || pref.key.startsWith("collection_") if (isCollection) { SyncCatalogItem( addonId = "", @@ -454,17 +457,20 @@ object HomeCatalogSettingsRepository { order = pref.order, customTitle = pref.customTitle, isCollection = true, - collectionId = pref.key.removePrefix("collection_"), + collectionId = collectionDefinition?.collectionId ?: pref.key.removePrefix("collection_"), + key = pref.key, ) } else { + val legacyParts = pref.key.split(':', limit = 3) SyncCatalogItem( - addonId = parts.getOrElse(0) { "" }, - type = parts.getOrElse(1) { "" }, - catalogId = parts.getOrElse(2) { "" }, + addonId = catalogDefinition?.addonIdForSync() ?: legacyParts.getOrElse(0) { "" }, + type = catalogDefinition?.type ?: legacyParts.getOrElse(1) { "" }, + catalogId = catalogDefinition?.catalogId ?: legacyParts.getOrElse(2) { "" }, enabled = pref.enabled, order = pref.order, customTitle = pref.customTitle, isCollection = false, + key = pref.key, ) } } @@ -481,12 +487,8 @@ object HomeCatalogSettingsRepository { hideCatalogUnderline = payload.hideCatalogUnderline if (payload.items.isNotEmpty()) { val existingHeroState = preferences.mapValues { it.value.heroSourceEnabled } - preferences = payload.items.associate { item -> - val key = if (item.isCollection) { - "collection_${item.collectionId}" - } else { - "${item.addonId}:${item.type}:${item.catalogId}" - } + val remotePreferences = payload.items.associate { item -> + val key = item.preferenceKey() key to StoredHomeCatalogPreference( key = key, customTitle = item.customTitle, @@ -494,7 +496,14 @@ object HomeCatalogSettingsRepository { heroSourceEnabled = existingHeroState[key] ?: true, order = item.order, ) - }.toMutableMap() + } + val remoteKeys = remotePreferences.keys + val knownKeys = knownPreferenceKeys() + val preservedPreferences = preferences.filterKeys { key -> + key !in remoteKeys && (key in knownKeys || key.requiresExplicitSyncKey()) + } + preferences = (preservedPreferences + remotePreferences).toMutableMap() + normalizePreferences() } hasLoaded = true publish() @@ -532,6 +541,43 @@ object HomeCatalogSettingsRepository { preferences[itemKey] = current.copy(order = index) } } + + private fun defaultPreferenceForMissingKey(key: String): StoredHomeCatalogPreference? { + val isCollection = collectionDefinitions.any { it.key == key } + val isCatalog = definitions.any { it.key == key } + if (!isCollection && !isCatalog) return null + + return StoredHomeCatalogPreference( + key = key, + enabled = true, + heroSourceEnabled = isCatalog && + selectedHeroSourceCount(excludingKey = key) < HERO_SOURCE_SELECTION_LIMIT, + order = _uiState.value.items.firstOrNull { it.key == key }?.order + ?: ((preferences.values.maxOfOrNull { it.order } ?: -1) + 1), + ) + } + + private fun knownPreferenceKeys(): Set = + definitions.mapTo(mutableSetOf()) { it.key }.also { keys -> + keys.addAll(collectionDefinitions.map { it.key }) + } + + private fun HomeCatalogDefinition.addonIdForSync(): String { + val suffix = ":$type:$catalogId" + return key.removeSuffix(suffix) + } + + private fun SyncCatalogItem.preferenceKey(): String = + key.ifBlank { + if (isCollection) { + "collection_$collectionId" + } else { + "$addonId:$type:$catalogId" + } + } + + private fun String.requiresExplicitSyncKey(): Boolean = + !startsWith("collection_") && count { it == ':' } > 2 } internal data class CollectionCatalogDefinition( diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/HomeCatalogSettingsSyncService.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/HomeCatalogSettingsSyncService.kt index d9edcea85..e7604ccb6 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/HomeCatalogSettingsSyncService.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/HomeCatalogSettingsSyncService.kt @@ -35,6 +35,7 @@ data class SyncCatalogItem( @SerialName("custom_title") val customTitle: String = "", @SerialName("is_collection") val isCollection: Boolean = false, @SerialName("collection_id") val collectionId: String = "", + val key: String = "", ) @Serializable