From 707d9854ec56c5641488ba1f32f35cd2d83a9955 Mon Sep 17 00:00:00 2001 From: Cuong-Tran Date: Tue, 25 Feb 2025 05:04:39 +0700 Subject: [PATCH] Change backup proto & improve code of backup/restore category related preferences (mihonapp/mihon#1726) Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com> (cherry picked from commit e1724d1aa0e3340e1404cfd80bd264831d86a879) --- CHANGELOG.md | 1 + .../creators/PreferenceBackupCreator.kt | 49 +------ .../data/backup/models/BackupCategory.kt | 2 + .../data/backup/restore/BackupRestorer.kt | 15 +-- .../restore/restorers/PreferenceRestorer.kt | 126 ++++++++---------- .../core/common/preference/Preference.kt | 4 + .../download/service/DownloadPreferences.kt | 35 ++--- .../library/service/LibraryPreferences.kt | 32 ++--- 8 files changed, 91 insertions(+), 173 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ba9e282c..49f10e4a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ The format is a modified version of [Keep a Changelog](https://keepachangelog.co - Fix Bangumi and MAL tracking 401 errors due to Mihon sending expired credentials ([@MajorTanya](https://github.com/MajorTanya)) ([#1681](https://github.com/mihonapp/mihon/pull/1681), [#1682](https://github.com/mihonapp/mihon/pull/1682)) - Fix certain Infinix devices being unable to use any "Open link in browser" actions, including tracker setup ([@MajorTanya](https://github.com/MajorTanya)) ([#1684](https://github.com/mihonapp/mihon/pull/1684)) - Fix App's preferences referencing deleted categories ([@cuong-tran](https://github.com/cuong-tran)) ([#1734](https://github.com/mihonapp/mihon/pull/1734)) +- Fix backup/restore of category related preferences ([@cuong-tran](https://github.com/cuong-tran)) ([#1726](https://github.com/mihonapp/mihon/pull/1726)) ### Other - Add zoned "Current time" to debug info and include year & timezone in logcat output ([@MajorTanya](https://github.com/MajorTanya)) ([#1672](https://github.com/mihonapp/mihon/pull/1672)) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/PreferenceBackupCreator.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/PreferenceBackupCreator.kt index 3a380ce49..5b72ce384 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/PreferenceBackupCreator.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/PreferenceBackupCreator.kt @@ -13,14 +13,6 @@ import eu.kanade.tachiyomi.source.preferenceKey import eu.kanade.tachiyomi.source.sourcePreferences import tachiyomi.core.common.preference.Preference import tachiyomi.core.common.preference.PreferenceStore -import tachiyomi.domain.category.interactor.GetCategories -import tachiyomi.domain.download.service.DownloadPreferences.Companion.DOWNLOAD_NEW_CATEGORIES_EXCLUDE_PREF_KEY -import tachiyomi.domain.download.service.DownloadPreferences.Companion.DOWNLOAD_NEW_CATEGORIES_PREF_KEY -import tachiyomi.domain.download.service.DownloadPreferences.Companion.REMOVE_EXCLUDE_CATEGORIES_PREF_KEY -import tachiyomi.domain.library.service.LibraryPreferences -import tachiyomi.domain.library.service.LibraryPreferences.Companion.DEFAULT_CATEGORY_PREF_KEY -import tachiyomi.domain.library.service.LibraryPreferences.Companion.LIBRARY_UPDATE_CATEGORIES_EXCLUDE_PREF_KEY -import tachiyomi.domain.library.service.LibraryPreferences.Companion.LIBRARY_UPDATE_CATEGORIES_PREF_KEY import tachiyomi.domain.source.service.SourceManager import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get @@ -29,48 +21,9 @@ class PreferenceBackupCreator( private val sourceManager: SourceManager = Injekt.get(), private val preferenceStore: PreferenceStore = Injekt.get(), ) { - // KMK --> - private val getCategories by lazy { Injekt.get() } - private val libraryPreferences by lazy { Injekt.get() } - // <-- - - /* KMK --> */ suspend /* KMK <-- */ fun createApp(includePrivatePreferences: Boolean): List { - // KMK --> - val allCategories = getCategories.await() - // KMK <-- + fun createApp(includePrivatePreferences: Boolean): List { return preferenceStore.getAll().toBackupPreferences() - // KMK --> - .map { backupPreference -> - when (backupPreference.key) { - // Convert CategoryId to CategoryOrder - DEFAULT_CATEGORY_PREF_KEY -> { - val id = (backupPreference.value as IntPreferenceValue).value.toLong() - val value = allCategories.find { it.id == id }?.order?.toInt() - ?: libraryPreferences.defaultCategory().defaultValue() - BackupPreference( - backupPreference.key, - IntPreferenceValue(value), - ) - } - // Convert CategoryId to CategoryOrder - LIBRARY_UPDATE_CATEGORIES_PREF_KEY, LIBRARY_UPDATE_CATEGORIES_EXCLUDE_PREF_KEY, - DOWNLOAD_NEW_CATEGORIES_PREF_KEY, DOWNLOAD_NEW_CATEGORIES_EXCLUDE_PREF_KEY, - REMOVE_EXCLUDE_CATEGORIES_PREF_KEY, - -> { - val categoryIds = (backupPreference.value as StringSetPreferenceValue).value - val categories = allCategories.associateBy({ it.id.toString() }, { it.order.toString() }) - BackupPreference( - backupPreference.key, - StringSetPreferenceValue( - categoryIds.mapNotNull { categories[it] }.toSet(), - ), - ) - } - else -> backupPreference - } - } - // KMK <-- .withPrivatePreferences(includePrivatePreferences) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupCategory.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupCategory.kt index b70baad8e..4a90d4602 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupCategory.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupCategory.kt @@ -8,6 +8,7 @@ import tachiyomi.domain.category.model.Category class BackupCategory( @ProtoNumber(1) var name: String, @ProtoNumber(2) var order: Long = 0, + @ProtoNumber(3) var id: Long = 0, // @ProtoNumber(3) val updateInterval: Int = 0, 1.x value not used in 0.x @ProtoNumber(100) var flags: Long = 0, // KMK --> @@ -30,6 +31,7 @@ class BackupCategory( val backupCategoryMapper = { category: Category -> BackupCategory( + id = category.id, name = category.name, order = category.order, flags = category.flags, diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/BackupRestorer.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/BackupRestorer.kt index 676432d2b..1c4959d8d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/BackupRestorer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/BackupRestorer.kt @@ -117,12 +117,7 @@ class BackupRestorer( } // SY <-- if (options.appSettings) { - restoreAppPreferences( - backup.backupPreferences, - // KMK -> - if (options.categories) backup.backupCategories else emptyList(), - // KMK <-- - ) + restoreAppPreferences(backup.backupPreferences, backup.backupCategories.takeIf { options.categories }) } if (options.sourceSettings) { restoreSourcePreferences(backup.backupSourcePreferences) @@ -197,16 +192,12 @@ class BackupRestorer( private fun CoroutineScope.restoreAppPreferences( preferences: List, - // KMK --> - backupCategories: List, - // KMK <-- + categories: List?, ) = launch { ensureActive() preferenceRestorer.restoreApp( preferences, - // KMK --> - backupCategories, - // KMK <-- + categories, ) restoreProgress += 1 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/PreferenceRestorer.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/PreferenceRestorer.kt index 1bd157ae7..2d73533c6 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/PreferenceRestorer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/PreferenceRestorer.kt @@ -1,7 +1,7 @@ package eu.kanade.tachiyomi.data.backup.restore.restorers import android.content.Context -import eu.kanade.domain.source.service.SourcePreferences.Companion.PINNED_SOURCES_PREF_KEY +import eu.kanade.domain.source.service.SourcePreferences import eu.kanade.tachiyomi.data.backup.create.BackupCreateJob import eu.kanade.tachiyomi.data.backup.models.BackupCategory import eu.kanade.tachiyomi.data.backup.models.BackupPreference @@ -19,38 +19,27 @@ import exh.EXHMigrations import exh.log.xLogE import tachiyomi.core.common.preference.AndroidPreferenceStore import tachiyomi.core.common.preference.PreferenceStore +import tachiyomi.core.common.preference.plusAssign import tachiyomi.domain.category.interactor.GetCategories -import tachiyomi.domain.download.service.DownloadPreferences.Companion.DOWNLOAD_NEW_CATEGORIES_EXCLUDE_PREF_KEY -import tachiyomi.domain.download.service.DownloadPreferences.Companion.DOWNLOAD_NEW_CATEGORIES_PREF_KEY -import tachiyomi.domain.download.service.DownloadPreferences.Companion.REMOVE_EXCLUDE_CATEGORIES_PREF_KEY +import tachiyomi.domain.category.model.Category +import tachiyomi.domain.download.service.DownloadPreferences import tachiyomi.domain.library.service.LibraryPreferences -import tachiyomi.domain.library.service.LibraryPreferences.Companion.DEFAULT_CATEGORY_PREF_KEY -import tachiyomi.domain.library.service.LibraryPreferences.Companion.LIBRARY_UPDATE_CATEGORIES_EXCLUDE_PREF_KEY -import tachiyomi.domain.library.service.LibraryPreferences.Companion.LIBRARY_UPDATE_CATEGORIES_PREF_KEY import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get class PreferenceRestorer( private val context: Context, + private val getCategories: GetCategories = Injekt.get(), private val preferenceStore: PreferenceStore = Injekt.get(), ) { - // KMK --> - private val getCategories by lazy { Injekt.get() } - private val libraryPreferences by lazy { Injekt.get() } - // <-- - - /* KMK --> */ suspend /* KMK <-- */ fun restoreApp( + suspend fun restoreApp( preferences: List, - // KMK --> - backupCategories: List, - // KMK <-- + backupCategories: List?, ) { restorePreferences( preferences, preferenceStore, - // KMK --> backupCategories, - // KMK <-- ) LibraryUpdateJob.setupTask(context) @@ -60,52 +49,35 @@ class PreferenceRestorer( // KMK <-- } - /* KMK --> */ suspend /* KMK <-- */ fun restoreSource(preferences: List) { + suspend fun restoreSource(preferences: List) { preferences.forEach { val sourcePrefs = AndroidPreferenceStore(context, sourcePreferences(it.sourceKey)) restorePreferences(it.prefs, sourcePrefs) } } - private /* KMK --> */ suspend /* KMK <-- */ fun restorePreferences( + private suspend fun restorePreferences( toRestore: List, preferenceStore: PreferenceStore, - // KMK --> - backupCategories: List = emptyList(), - // KMK <-- + backupCategories: List? = null, ) { - // KMK --> - val allCategories = getCategories.await() + val allCategories = if (backupCategories != null) getCategories.await() else emptyList() val categoriesByName = allCategories.associateBy { it.name } - val backupCategoriesByOrder = backupCategories.associateBy { it.order.toString() } - // KMK <-- + val backupCategoriesById = backupCategories?.associateBy { it.id.toString() }.orEmpty() val prefs = preferenceStore.getAll() toRestore.forEach { (key, value) -> - // KMK --> try { - // KMK <-- when (value) { is IntPreferenceValue -> { if (prefs[key] is Int?) { - // KMK --> - when (key) { - // Convert CategoryOrder to CategoryId - DEFAULT_CATEGORY_PREF_KEY -> { - if (backupCategories.isNotEmpty()) { - val order = value.value.toLong() - val newValue = backupCategories.find { it.order == order } - ?.let { - categoriesByName[it.name]?.id?.toInt() - } - ?: libraryPreferences.defaultCategory().defaultValue() - - preferenceStore.getInt(key).set(newValue) - } - } - else -> - // KMK <-- - preferenceStore.getInt(key).set(value.value) + val newValue = if (key == LibraryPreferences.DEFAULT_CATEGORY_PREF_KEY) { + backupCategoriesById[value.value.toString()] + ?.let { categoriesByName[it.name]?.id?.toInt() } + } else { + value.value } + + newValue?.let { preferenceStore.getInt(key).set(it) } } } is LongPreferenceValue -> { @@ -130,37 +102,53 @@ class PreferenceRestorer( } is StringSetPreferenceValue -> { if (prefs[key] is Set<*>?) { - // KMK --> - when (key) { - PINNED_SOURCES_PREF_KEY -> { - EXHMigrations.migratePinnedSources(value.value) + val restored = restoreCategoriesPreference( + key, + value.value, + preferenceStore, + backupCategoriesById, + categoriesByName, + ) + if (!restored) { + // KMK --> + when (key) { + SourcePreferences.PINNED_SOURCES_PREF_KEY -> + EXHMigrations.migratePinnedSources(value.value) + else -> + // KMK <-- + preferenceStore.getStringSet(key).set(value.value) } - // Convert CategoryOrder to CategoryId - LIBRARY_UPDATE_CATEGORIES_PREF_KEY, LIBRARY_UPDATE_CATEGORIES_EXCLUDE_PREF_KEY, - DOWNLOAD_NEW_CATEGORIES_PREF_KEY, DOWNLOAD_NEW_CATEGORIES_EXCLUDE_PREF_KEY, - REMOVE_EXCLUDE_CATEGORIES_PREF_KEY, - -> { - val newValue = value.value.mapNotNull { order -> - backupCategoriesByOrder[order]?.let { backupCategory -> - categoriesByName[backupCategory.name]?.id?.toString() - } - }.toSet() - if (newValue.isNotEmpty()) { - preferenceStore.getStringSet(key).set(newValue) - } - } - else -> - // KMK <-- - preferenceStore.getStringSet(key).set(value.value) } } } } - // KMK --> } catch (e: Exception) { + // KMK --> xLogE("Failed to restore preference <$key>", e) // KMK <-- } } } + + private fun restoreCategoriesPreference( + key: String, + value: Set, + preferenceStore: PreferenceStore, + backupCategoriesById: Map, + categoriesByName: Map, + ): Boolean { + val categoryPreferences = LibraryPreferences.categoryPreferenceKeys + DownloadPreferences.categoryPreferenceKeys + if (key !in categoryPreferences) return false + + val ids = value.mapNotNull { + backupCategoriesById[it]?.name?.let { name -> + categoriesByName[name]?.id?.toString() + } + } + + if (ids.isNotEmpty()) { + preferenceStore.getStringSet(key) += ids + } + return true + } } diff --git a/core/common/src/main/kotlin/tachiyomi/core/common/preference/Preference.kt b/core/common/src/main/kotlin/tachiyomi/core/common/preference/Preference.kt index f75384491..e3ac0f1d3 100644 --- a/core/common/src/main/kotlin/tachiyomi/core/common/preference/Preference.kt +++ b/core/common/src/main/kotlin/tachiyomi/core/common/preference/Preference.kt @@ -57,6 +57,10 @@ operator fun Preference>.plusAssign(item: T) { set(get() + item) } +operator fun Preference>.plusAssign(items: Iterable) { + set(get() + items) +} + operator fun Preference>.minusAssign(item: T) { set(get() - item) } diff --git a/domain/src/main/java/tachiyomi/domain/download/service/DownloadPreferences.kt b/domain/src/main/java/tachiyomi/domain/download/service/DownloadPreferences.kt index 2261bc5c2..e86478d86 100644 --- a/domain/src/main/java/tachiyomi/domain/download/service/DownloadPreferences.kt +++ b/domain/src/main/java/tachiyomi/domain/download/service/DownloadPreferences.kt @@ -26,38 +26,29 @@ class DownloadPreferences( fun removeBookmarkedChapters() = preferenceStore.getBoolean("pref_remove_bookmarked", false) - fun removeExcludeCategories() = preferenceStore.getStringSet( - // KMK --> - REMOVE_EXCLUDE_CATEGORIES_PREF_KEY, - // KMK <-- - emptySet(), - ) + fun removeExcludeCategories() = preferenceStore.getStringSet(REMOVE_EXCLUDE_CATEGORIES_PREF_KEY, emptySet()) fun downloadNewChapters() = preferenceStore.getBoolean("download_new", false) - fun downloadNewChapterCategories() = preferenceStore.getStringSet( - // KMK --> - DOWNLOAD_NEW_CATEGORIES_PREF_KEY, - // KMK <-- - emptySet(), - ) + fun downloadNewChapterCategories() = preferenceStore.getStringSet(DOWNLOAD_NEW_CATEGORIES_PREF_KEY, emptySet()) - fun downloadNewChapterCategoriesExclude() = preferenceStore.getStringSet( - // KMK --> - DOWNLOAD_NEW_CATEGORIES_EXCLUDE_PREF_KEY, - // KMK <-- - emptySet(), - ) + fun downloadNewChapterCategoriesExclude() = + preferenceStore.getStringSet(DOWNLOAD_NEW_CATEGORIES_EXCLUDE_PREF_KEY, emptySet()) fun downloadNewUnreadChaptersOnly() = preferenceStore.getBoolean("download_new_unread_chapters_only", false) // KMK --> fun downloadCacheRenewInterval() = preferenceStore.getInt("download_cache_renew_interval", 1) + // KMK <-- companion object { - const val REMOVE_EXCLUDE_CATEGORIES_PREF_KEY = "remove_exclude_categories" - const val DOWNLOAD_NEW_CATEGORIES_PREF_KEY = "download_new_categories" - const val DOWNLOAD_NEW_CATEGORIES_EXCLUDE_PREF_KEY = "download_new_categories_exclude" + private const val REMOVE_EXCLUDE_CATEGORIES_PREF_KEY = "remove_exclude_categories" + private const val DOWNLOAD_NEW_CATEGORIES_PREF_KEY = "download_new_categories" + private const val DOWNLOAD_NEW_CATEGORIES_EXCLUDE_PREF_KEY = "download_new_categories_exclude" + val categoryPreferenceKeys = setOf( + REMOVE_EXCLUDE_CATEGORIES_PREF_KEY, + DOWNLOAD_NEW_CATEGORIES_PREF_KEY, + DOWNLOAD_NEW_CATEGORIES_EXCLUDE_PREF_KEY, + ) } - // KMK <-- } diff --git a/domain/src/main/java/tachiyomi/domain/library/service/LibraryPreferences.kt b/domain/src/main/java/tachiyomi/domain/library/service/LibraryPreferences.kt index 6e02b1cc8..b1455b3a9 100644 --- a/domain/src/main/java/tachiyomi/domain/library/service/LibraryPreferences.kt +++ b/domain/src/main/java/tachiyomi/domain/library/service/LibraryPreferences.kt @@ -144,12 +144,7 @@ class LibraryPreferences( // region Category - fun defaultCategory() = preferenceStore.getInt( - // KMK --> - DEFAULT_CATEGORY_PREF_KEY, - // KMK <-- - -1, - ) + fun defaultCategory() = preferenceStore.getInt(DEFAULT_CATEGORY_PREF_KEY, -1) fun lastUsedCategory() = preferenceStore.getInt(Preference.appStateKey("last_used_category"), 0) @@ -163,19 +158,9 @@ class LibraryPreferences( fun showHiddenCategories() = preferenceStore.getBoolean("hide_hidden_categories", false) // KMK <-- - fun updateCategories() = preferenceStore.getStringSet( - // KMK --> - LIBRARY_UPDATE_CATEGORIES_PREF_KEY, - // KMK <-- - emptySet(), - ) + fun updateCategories() = preferenceStore.getStringSet(LIBRARY_UPDATE_CATEGORIES_PREF_KEY, emptySet()) - fun updateCategoriesExclude() = preferenceStore.getStringSet( - // KMK --> - LIBRARY_UPDATE_CATEGORIES_EXCLUDE_PREF_KEY, - // KMK <-- - emptySet(), - ) + fun updateCategoriesExclude() = preferenceStore.getStringSet(LIBRARY_UPDATE_CATEGORIES_EXCLUDE_PREF_KEY, emptySet()) // endregion @@ -268,10 +253,13 @@ class LibraryPreferences( const val MANGA_NON_READ = "manga_started" const val MANGA_OUTSIDE_RELEASE_PERIOD = "manga_outside_release_period" - // KMK --> const val DEFAULT_CATEGORY_PREF_KEY = "default_category" - const val LIBRARY_UPDATE_CATEGORIES_PREF_KEY = "library_update_categories" - const val LIBRARY_UPDATE_CATEGORIES_EXCLUDE_PREF_KEY = "library_update_categories_exclude" - // KMK <-- + private const val LIBRARY_UPDATE_CATEGORIES_PREF_KEY = "library_update_categories" + private const val LIBRARY_UPDATE_CATEGORIES_EXCLUDE_PREF_KEY = "library_update_categories_exclude" + val categoryPreferenceKeys = setOf( + DEFAULT_CATEGORY_PREF_KEY, + LIBRARY_UPDATE_CATEGORIES_PREF_KEY, + LIBRARY_UPDATE_CATEGORIES_EXCLUDE_PREF_KEY, + ) } }