Add source preferences to backups

Closes #1857

Co-authored-by: jmir1 <jmir1@users.noreply.github.com>
(cherry picked from commit 0f42b9f1544b188362d1c0046c8ff853827ed270)

# Conflicts:
#	app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBackupScreen.kt
#	app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupConst.kt
#	app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt
#	app/src/main/java/eu/kanade/tachiyomi/data/backup/models/Backup.kt
This commit is contained in:
arkon 2023-10-08 16:02:03 -04:00 committed by Jobobby04
parent 92daa4ea28
commit b9fe9f7f52
9 changed files with 67 additions and 20 deletions

View File

@ -148,6 +148,7 @@ object SettingsBackupScreen : SearchableSettings {
BackupConst.BACKUP_TRACK to R.string.track,
BackupConst.BACKUP_HISTORY to R.string.history,
BackupConst.BACKUP_APP_PREFS to R.string.app_settings,
BackupConst.BACKUP_SOURCE_PREFS to R.string.source_settings,
// SY -->
BackupConst.BACKUP_CUSTOM_INFO to R.string.custom_entry_info,
BackupConst.BACKUP_READ_MANGA to R.string.all_read_entries,

View File

@ -17,13 +17,16 @@ internal object BackupConst {
const val BACKUP_APP_PREFS = 0x10
const val BACKUP_APP_PREFS_MASK = 0x10
const val BACKUP_SOURCE_PREFS = 0x20
const val BACKUP_SOURCE_PREFS_MASK = 0x20
// SY -->
const val BACKUP_CUSTOM_INFO = 0x20
const val BACKUP_CUSTOM_INFO_MASK = 0x20
const val BACKUP_CUSTOM_INFO = 0x40
const val BACKUP_CUSTOM_INFO_MASK = 0x40
const val BACKUP_READ_MANGA = 0x40
const val BACKUP_READ_MANGA_MASK = 0x40
const val BACKUP_READ_MANGA = 0x80
const val BACKUP_READ_MANGA_MASK = 0x80
const val BACKUP_ALL = 0x7F
const val BACKUP_ALL = 0xFF
// SY <--
}

View File

@ -18,6 +18,8 @@ import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_HISTORY
import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_HISTORY_MASK
import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_READ_MANGA
import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_READ_MANGA_MASK
import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_SOURCE_PREFS
import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_SOURCE_PREFS_MASK
import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_TRACK
import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_TRACK_MASK
import eu.kanade.tachiyomi.data.backup.models.Backup
@ -28,6 +30,7 @@ import eu.kanade.tachiyomi.data.backup.models.BackupManga
import eu.kanade.tachiyomi.data.backup.models.BackupMergedMangaReference
import eu.kanade.tachiyomi.data.backup.models.BackupPreference
import eu.kanade.tachiyomi.data.backup.models.BackupSavedSearch
import eu.kanade.tachiyomi.data.backup.models.BackupSourcePreferences
import eu.kanade.tachiyomi.data.backup.models.BackupSerializer
import eu.kanade.tachiyomi.data.backup.models.BackupSource
import eu.kanade.tachiyomi.data.backup.models.BooleanPreferenceValue
@ -41,8 +44,11 @@ import eu.kanade.tachiyomi.data.backup.models.backupChapterMapper
import eu.kanade.tachiyomi.data.backup.models.backupMergedMangaReferenceMapper
import eu.kanade.tachiyomi.data.backup.models.backupSavedSearchMapper
import eu.kanade.tachiyomi.data.backup.models.backupTrackMapper
import eu.kanade.tachiyomi.source.ConfigurableSource
import eu.kanade.tachiyomi.source.model.copyFrom
import eu.kanade.tachiyomi.source.online.MetadataSource
import eu.kanade.tachiyomi.source.preferenceKey
import eu.kanade.tachiyomi.source.sourcePreferences
import eu.kanade.tachiyomi.util.system.hasPermission
import exh.source.MERGED_SOURCE_ID
import exh.source.getMainSource
@ -130,6 +136,7 @@ class BackupManager(
emptyList(),
prepExtensionInfoForSync(databaseManga),
backupAppPreferences(flags),
backupSourcePreferences(flags),
// SY -->
backupSavedSearches(),
// SY <--
@ -299,12 +306,28 @@ class BackupManager(
return mangaObject
}
@Suppress("UNCHECKED_CAST")
private fun backupAppPreferences(flags: Int): List<BackupPreference> {
if (flags and BACKUP_APP_PREFS_MASK != BACKUP_APP_PREFS) return emptyList()
return preferenceStore.getAll()
.filterKeys { !Preference.isPrivate(it) }
return preferenceStore.getAll().toBackupPreferences()
}
private fun backupSourcePreferences(flags: Int): List<BackupSourcePreferences> {
if (flags and BACKUP_SOURCE_PREFS_MASK != BACKUP_SOURCE_PREFS) return emptyList()
return sourceManager.getOnlineSources()
.filterIsInstance<ConfigurableSource>()
.map {
BackupSourcePreferences(
it.preferenceKey(),
it.sourcePreferences().all.toBackupPreferences()
)
}
}
@Suppress("UNCHECKED_CAST")
private fun Map<String, *>.toBackupPreferences(): List<BackupPreference> {
return this.filterKeys { !Preference.isPrivate(it) }
.mapNotNull { (key, value) ->
when (value) {
is Int -> BackupPreference(key, IntPreferenceValue(value))

View File

@ -12,18 +12,21 @@ import eu.kanade.tachiyomi.data.backup.models.BackupMergedMangaReference
import eu.kanade.tachiyomi.data.backup.models.BackupPreference
import eu.kanade.tachiyomi.data.backup.models.BackupSavedSearch
import eu.kanade.tachiyomi.data.backup.models.BackupSource
import eu.kanade.tachiyomi.data.backup.models.BackupSourcePreferences
import eu.kanade.tachiyomi.data.backup.models.BooleanPreferenceValue
import eu.kanade.tachiyomi.data.backup.models.FloatPreferenceValue
import eu.kanade.tachiyomi.data.backup.models.IntPreferenceValue
import eu.kanade.tachiyomi.data.backup.models.LongPreferenceValue
import eu.kanade.tachiyomi.data.backup.models.StringPreferenceValue
import eu.kanade.tachiyomi.data.backup.models.StringSetPreferenceValue
import eu.kanade.tachiyomi.source.sourcePreferences
import eu.kanade.tachiyomi.util.BackupUtil
import eu.kanade.tachiyomi.util.system.createFileInCacheDir
import exh.EXHMigrations
import exh.source.MERGED_SOURCE_ID
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.isActive
import tachiyomi.core.preference.AndroidPreferenceStore
import tachiyomi.core.preference.PreferenceStore
import tachiyomi.domain.chapter.model.Chapter
import tachiyomi.domain.manga.interactor.FetchInterval
@ -126,6 +129,7 @@ class BackupRestorer(
return coroutineScope {
restoreAppPreferences(backup.backupPreferences)
restoreSourcePreferences(backup.backupSourcePreferences)
// Restore individual manga, sort by merged source so that merged source manga go last and merged references get the proper ids
backup.backupManga /* SY --> */.sortedBy { it.source == MERGED_SOURCE_ID } /* SY <-- */.forEach {
@ -268,9 +272,22 @@ class BackupRestorer(
}
private fun restoreAppPreferences(preferences: List<BackupPreference>) {
val prefs = preferenceStore.getAll()
restorePreferences(preferences, preferenceStore)
}
preferences.forEach { (key, value) ->
private fun restoreSourcePreferences(preferences: List<BackupSourcePreferences>) {
preferences.forEach {
val sourcePrefs = AndroidPreferenceStore(context, sourcePreferences(it.sourceKey))
restorePreferences(it.prefs, sourcePrefs)
}
}
private fun restorePreferences(
toRestore: List<BackupPreference>,
preferenceStore: PreferenceStore,
) {
val prefs = preferenceStore.getAll()
toRestore.forEach { (key, value) ->
when (value) {
is IntPreferenceValue -> {
if (prefs[key] is Int?) {
@ -306,13 +323,6 @@ class BackupRestorer(
}
}
/**
* Called to update dialog in [BackupConst]
*
* @param progress restore progress
* @param amount total restoreAmount of manga
* @param title title of restored manga
*/
private fun showRestoreProgress(progress: Int, amount: Int, title: String, contentTitle: String) {
notifier.showRestoreProgress(title, contentTitle, progress, amount)
}

View File

@ -14,6 +14,7 @@ data class Backup(
@ProtoNumber(100) var backupBrokenSources: List<BrokenBackupSource> = emptyList(),
@ProtoNumber(101) var backupSources: List<BackupSource> = emptyList(),
@ProtoNumber(104) var backupPreferences: List<BackupPreference> = emptyList(),
@ProtoNumber(105) var backupSourcePreferences: List<BackupSourcePreferences> = emptyList(),
// SY specific values
@ProtoNumber(600) var backupSavedSearches: List<BackupSavedSearch> = emptyList(),
) {

View File

@ -9,6 +9,12 @@ data class BackupPreference(
@ProtoNumber(2) val value: PreferenceValue,
)
@Serializable
data class BackupSourcePreferences(
@ProtoNumber(1) val sourceKey: String,
@ProtoNumber(2) val prefs: List<BackupPreference>,
)
@Serializable
sealed class PreferenceValue

View File

@ -15,10 +15,9 @@ import tachiyomi.core.preference.AndroidPreference.StringSetPrimitive
class AndroidPreferenceStore(
context: Context,
private val sharedPreferences: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context),
) : PreferenceStore {
private val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
private val keyFlow = sharedPreferences.keyFlow
override fun getString(key: String, defaultValue: String): Preference<String> {

View File

@ -494,6 +494,7 @@
<string name="backup_in_progress">Backup is already in progress</string>
<string name="backup_choice">What do you want to backup?</string>
<string name="app_settings">App settings</string>
<string name="source_settings">Source settings</string>
<string name="creating_backup">Creating backup</string>
<string name="creating_backup_error">Backup failed</string>
<string name="missing_storage_permission">Storage permissions not granted</string>

View File

@ -19,8 +19,11 @@ interface ConfigurableSource : Source {
fun setupPreferenceScreen(screen: PreferenceScreen)
}
private fun ConfigurableSource.preferenceKey(): String = "source_$id"
fun ConfigurableSource.preferenceKey(): String = "source_$id"
// TODO: use getSourcePreferences once all extensions are on ext-lib 1.5
fun ConfigurableSource.sourcePreferences(): SharedPreferences =
Injekt.get<Application>().getSharedPreferences(preferenceKey(), Context.MODE_PRIVATE)
fun sourcePreferences(key: String): SharedPreferences =
Injekt.get<Application>().getSharedPreferences(key, Context.MODE_PRIVATE)