Refactor backup option flags to normal data class of booleans

(cherry picked from commit 8735836498f46f7b6dc35ff62ffb595e097d568e)

# Conflicts:
#	app/src/main/java/eu/kanade/presentation/more/settings/screen/data/CreateBackupScreen.kt
#	app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupCreateFlags.kt
#	app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupCreator.kt
#	app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/MangaBackupCreator.kt
This commit is contained in:
arkon 2023-12-28 16:44:46 -05:00 committed by Jobobby04
parent c496371553
commit e1afceb769
7 changed files with 166 additions and 101 deletions

View File

@ -29,16 +29,11 @@ import cafe.adriel.voyager.navigator.currentOrThrow
import eu.kanade.presentation.components.AppBar import eu.kanade.presentation.components.AppBar
import eu.kanade.presentation.components.WarningBanner import eu.kanade.presentation.components.WarningBanner
import eu.kanade.presentation.util.Screen import eu.kanade.presentation.util.Screen
import eu.kanade.tachiyomi.data.backup.create.BackupCreateFlags
import eu.kanade.tachiyomi.data.backup.create.BackupCreateJob import eu.kanade.tachiyomi.data.backup.create.BackupCreateJob
import eu.kanade.tachiyomi.data.backup.create.BackupCreator import eu.kanade.tachiyomi.data.backup.create.BackupCreator
import eu.kanade.tachiyomi.data.backup.create.BackupOptions
import eu.kanade.tachiyomi.util.system.DeviceUtil import eu.kanade.tachiyomi.util.system.DeviceUtil
import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.system.toast
import kotlinx.collections.immutable.PersistentSet
import kotlinx.collections.immutable.minus
import kotlinx.collections.immutable.persistentMapOf
import kotlinx.collections.immutable.persistentSetOf
import kotlinx.collections.immutable.plus
import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.update
import tachiyomi.i18n.MR import tachiyomi.i18n.MR
import tachiyomi.i18n.sy.SYMR import tachiyomi.i18n.sy.SYMR
@ -102,13 +97,13 @@ class CreateBackupScreen : Screen() {
modifier = Modifier.padding(horizontal = MaterialTheme.padding.medium), modifier = Modifier.padding(horizontal = MaterialTheme.padding.medium),
) )
} }
BackupChoices.forEach { (k, v) -> BackupOptions.entries.forEach { option ->
item { item {
LabeledCheckbox( LabeledCheckbox(
label = stringResource(v), label = stringResource(option.label),
checked = state.flags.contains(k), checked = option.getter(state.options),
onCheckedChange = { onCheckedChange = {
model.toggleFlag(k) model.toggle(option.setter, it)
}, },
modifier = Modifier.padding(horizontal = MaterialTheme.padding.medium), modifier = Modifier.padding(horizontal = MaterialTheme.padding.medium),
) )
@ -146,45 +141,32 @@ class CreateBackupScreen : Screen() {
private class CreateBackupScreenModel : StateScreenModel<CreateBackupScreenModel.State>(State()) { private class CreateBackupScreenModel : StateScreenModel<CreateBackupScreenModel.State>(State()) {
fun toggleFlag(flag: Int) { fun toggle(setter: (BackupOptions, Boolean) -> BackupOptions, enabled: Boolean) {
mutableState.update { mutableState.update {
if (it.flags.contains(flag)) { it.copy(
it.copy(flags = it.flags - flag) options = setter(it.options, enabled),
} else { )
it.copy(flags = it.flags + flag)
}
} }
} }
fun createBackup(context: Context, uri: Uri) { fun createBackup(context: Context, uri: Uri) {
val flags = state.value.flags.fold(initial = 0, operation = { a, b -> a or b }) BackupCreateJob.startNow(context, uri, state.value.options)
BackupCreateJob.startNow(context, uri, flags)
} }
@Immutable @Immutable
data class State( data class State(
val flags: PersistentSet<Int> = persistentSetOf( val options: BackupOptions = BackupOptions(
BackupCreateFlags.BACKUP_CATEGORY, libraryEntries = true,
BackupCreateFlags.BACKUP_CHAPTER, categories = true,
BackupCreateFlags.BACKUP_TRACK, chapters = true,
BackupCreateFlags.BACKUP_HISTORY, tracking = true,
history = true,
appSettings = false,
sourceSettings = false,
// SY --> // SY -->
BackupCreateFlags.BACKUP_CUSTOM_INFO, customInfo = true,
BackupCreateFlags.BACKUP_READ_MANGA, readEntries = true,
// SY <-- // SY <--
), ),
) )
} }
private val BackupChoices = persistentMapOf(
BackupCreateFlags.BACKUP_CATEGORY to MR.strings.categories,
BackupCreateFlags.BACKUP_CHAPTER to MR.strings.chapters,
BackupCreateFlags.BACKUP_TRACK to MR.strings.track,
BackupCreateFlags.BACKUP_HISTORY to MR.strings.history,
BackupCreateFlags.BACKUP_APP_PREFS to MR.strings.app_settings,
BackupCreateFlags.BACKUP_SOURCE_PREFS to MR.strings.source_settings,
// SY -->
BackupCreateFlags.BACKUP_CUSTOM_INFO to SYMR.strings.custom_entry_info,
BackupCreateFlags.BACKUP_READ_MANGA to SYMR.strings.all_read_entries,
// SY <--
)

View File

@ -1,25 +0,0 @@
package eu.kanade.tachiyomi.data.backup.create
internal object BackupCreateFlags {
const val BACKUP_CATEGORY = 0x1
const val BACKUP_CHAPTER = 0x2
const val BACKUP_HISTORY = 0x4
const val BACKUP_TRACK = 0x8
const val BACKUP_APP_PREFS = 0x10
const val BACKUP_SOURCE_PREFS = 0x20
// SY -->
const val BACKUP_CUSTOM_INFO = 0x40
const val BACKUP_READ_MANGA = 0x80
// SY <--
const val AutomaticDefaults = BACKUP_CATEGORY or
BACKUP_CHAPTER or
BACKUP_HISTORY or
BACKUP_TRACK or
BACKUP_APP_PREFS or
BACKUP_SOURCE_PREFS /* SY --> */ or
BACKUP_CUSTOM_INFO or
BACKUP_READ_MANGA
// SY <--
}

View File

@ -47,10 +47,12 @@ class BackupCreateJob(private val context: Context, workerParams: WorkerParamete
setForegroundSafely() setForegroundSafely()
val flags = inputData.getInt(BACKUP_FLAGS_KEY, BackupCreateFlags.AutomaticDefaults) val options = inputData.getBooleanArray(OPTIONS_KEY)
?.let { BackupOptions.fromBooleanArray(it) }
?: BackupOptions.AutomaticDefaults
return try { return try {
val location = BackupCreator(context, isAutoBackup).backup(uri, flags) val location = BackupCreator(context, isAutoBackup).backup(uri, options)
if (!isAutoBackup) { if (!isAutoBackup) {
notifier.showBackupComplete(UniFile.fromUri(context, location.toUri())!!) notifier.showBackupComplete(UniFile.fromUri(context, location.toUri())!!)
} }
@ -112,11 +114,11 @@ class BackupCreateJob(private val context: Context, workerParams: WorkerParamete
} }
} }
fun startNow(context: Context, uri: Uri, flags: Int) { fun startNow(context: Context, uri: Uri, options: BackupOptions) {
val inputData = workDataOf( val inputData = workDataOf(
IS_AUTO_BACKUP_KEY to false, IS_AUTO_BACKUP_KEY to false,
LOCATION_URI_KEY to uri.toString(), LOCATION_URI_KEY to uri.toString(),
BACKUP_FLAGS_KEY to flags, OPTIONS_KEY to options.toBooleanArray(),
) )
val request = OneTimeWorkRequestBuilder<BackupCreateJob>() val request = OneTimeWorkRequestBuilder<BackupCreateJob>()
.addTag(TAG_MANUAL) .addTag(TAG_MANUAL)
@ -132,4 +134,4 @@ private const val TAG_MANUAL = "$TAG_AUTO:manual"
private const val IS_AUTO_BACKUP_KEY = "is_auto_backup" // Boolean private const val IS_AUTO_BACKUP_KEY = "is_auto_backup" // Boolean
private const val LOCATION_URI_KEY = "location_uri" // String private const val LOCATION_URI_KEY = "location_uri" // String
private const val BACKUP_FLAGS_KEY = "backup_flags" // Int private const val OPTIONS_KEY = "options" // BooleanArray

View File

@ -5,10 +5,6 @@ import android.net.Uri
import com.hippo.unifile.UniFile import com.hippo.unifile.UniFile
import eu.kanade.tachiyomi.BuildConfig import eu.kanade.tachiyomi.BuildConfig
import eu.kanade.tachiyomi.data.backup.BackupFileValidator import eu.kanade.tachiyomi.data.backup.BackupFileValidator
import eu.kanade.tachiyomi.data.backup.create.BackupCreateFlags.BACKUP_APP_PREFS
import eu.kanade.tachiyomi.data.backup.create.BackupCreateFlags.BACKUP_CATEGORY
import eu.kanade.tachiyomi.data.backup.create.BackupCreateFlags.BACKUP_READ_MANGA
import eu.kanade.tachiyomi.data.backup.create.BackupCreateFlags.BACKUP_SOURCE_PREFS
import eu.kanade.tachiyomi.data.backup.create.creators.CategoriesBackupCreator import eu.kanade.tachiyomi.data.backup.create.creators.CategoriesBackupCreator
import eu.kanade.tachiyomi.data.backup.create.creators.MangaBackupCreator import eu.kanade.tachiyomi.data.backup.create.creators.MangaBackupCreator
import eu.kanade.tachiyomi.data.backup.create.creators.PreferenceBackupCreator import eu.kanade.tachiyomi.data.backup.create.creators.PreferenceBackupCreator
@ -63,7 +59,7 @@ class BackupCreator(
// SY <-- // SY <--
) { ) {
suspend fun backup(uri: Uri, flags: Int): String { suspend fun backup(uri: Uri, options: BackupOptions): String {
var file: UniFile? = null var file: UniFile? = null
try { try {
file = ( file = (
@ -90,17 +86,17 @@ class BackupCreator(
} }
val databaseManga = getFavorites.await() /* SY --> */ + val databaseManga = getFavorites.await() /* SY --> */ +
if (flags and BACKUP_READ_MANGA == BACKUP_READ_MANGA) { if (options.readEntries) {
handler.awaitList { mangasQueries.getReadMangaNotInLibrary(MangaMapper::mapManga) } handler.awaitList { mangasQueries.getReadMangaNotInLibrary(MangaMapper::mapManga) }
} else { } else {
emptyList() emptyList()
} + getMergedManga.await() // SY <-- } + getMergedManga.await() // SY <--
val backup = Backup( val backup = Backup(
backupManga = backupMangas(databaseManga, flags), backupManga = backupMangas(databaseManga, options),
backupCategories = backupCategories(flags), backupCategories = backupCategories(options),
backupSources = backupSources(databaseManga), backupSources = backupSources(databaseManga),
backupPreferences = backupAppPreferences(flags), backupPreferences = backupAppPreferences(options),
backupSourcePreferences = backupSourcePreferences(flags), backupSourcePreferences = backupSourcePreferences(options),
// SY --> // SY -->
backupSavedSearches = backupSavedSearches(), backupSavedSearches = backupSavedSearches(),
// SY <-- // SY <--
@ -136,28 +132,28 @@ class BackupCreator(
} }
} }
private suspend fun backupCategories(options: Int): List<BackupCategory> { private suspend fun backupCategories(options: BackupOptions): List<BackupCategory> {
if (options and BACKUP_CATEGORY != BACKUP_CATEGORY) return emptyList() if (!options.categories) return emptyList()
return categoriesBackupCreator.backupCategories() return categoriesBackupCreator.backupCategories()
} }
private suspend fun backupMangas(mangas: List<Manga>, flags: Int): List<BackupManga> { private suspend fun backupMangas(mangas: List<Manga>, options: BackupOptions): List<BackupManga> {
return mangaBackupCreator.backupMangas(mangas, flags) return mangaBackupCreator.backupMangas(mangas, options)
} }
private fun backupSources(mangas: List<Manga>): List<BackupSource> { private fun backupSources(mangas: List<Manga>): List<BackupSource> {
return sourcesBackupCreator.backupSources(mangas) return sourcesBackupCreator.backupSources(mangas)
} }
private fun backupAppPreferences(flags: Int): List<BackupPreference> { private fun backupAppPreferences(options: BackupOptions): List<BackupPreference> {
if (flags and BACKUP_APP_PREFS != BACKUP_APP_PREFS) return emptyList() if (!options.appSettings) return emptyList()
return preferenceBackupCreator.backupAppPreferences() return preferenceBackupCreator.backupAppPreferences()
} }
private fun backupSourcePreferences(flags: Int): List<BackupSourcePreferences> { private fun backupSourcePreferences(options: BackupOptions): List<BackupSourcePreferences> {
if (flags and BACKUP_SOURCE_PREFS != BACKUP_SOURCE_PREFS) return emptyList() if (!options.sourceSettings) return emptyList()
return preferenceBackupCreator.backupSourcePreferences() return preferenceBackupCreator.backupSourcePreferences()
} }

View File

@ -0,0 +1,115 @@
package eu.kanade.tachiyomi.data.backup.create
import dev.icerock.moko.resources.StringResource
import kotlinx.collections.immutable.persistentListOf
import tachiyomi.i18n.MR
import tachiyomi.i18n.sy.SYMR
data class BackupOptions(
val libraryEntries: Boolean = true,
val categories: Boolean = true,
val chapters: Boolean = true,
val tracking: Boolean = true,
val history: Boolean = true,
val appSettings: Boolean = true,
val sourceSettings: Boolean = true,
// SY -->
val customInfo: Boolean = true,
val readEntries: Boolean = true,
// SY <--
) {
fun toBooleanArray() = booleanArrayOf(
libraryEntries,
categories,
chapters,
tracking,
history,
appSettings,
sourceSettings,
// SY -->
customInfo,
readEntries,
// SY <--
)
companion object {
val AutomaticDefaults = BackupOptions(
libraryEntries = true,
categories = true,
chapters = true,
tracking = true,
history = true,
appSettings = true,
sourceSettings = true,
// SY -->
customInfo = true,
readEntries = true,
// SY <--
)
fun fromBooleanArray(booleanArray: BooleanArray) = BackupOptions(
libraryEntries = booleanArray[0],
categories = booleanArray[1],
chapters = booleanArray[2],
tracking = booleanArray[3],
history = booleanArray[4],
appSettings = booleanArray[5],
sourceSettings = booleanArray[6],
// SY -->
customInfo = booleanArray[7],
readEntries = booleanArray[8],
// SY <--
)
val entries = persistentListOf<BackupOptionEntry>(
BackupOptionEntry(
label = MR.strings.categories,
getter = BackupOptions::categories,
setter = { options, enabled -> options.copy(categories = enabled) },
),
BackupOptionEntry(
label = MR.strings.chapters,
getter = BackupOptions::chapters,
setter = { options, enabled -> options.copy(chapters = enabled) },
),
BackupOptionEntry(
label = MR.strings.track,
getter = BackupOptions::tracking,
setter = { options, enabled -> options.copy(tracking = enabled) },
),
BackupOptionEntry(
label = MR.strings.history,
getter = BackupOptions::history,
setter = { options, enabled -> options.copy(history = enabled) },
),
BackupOptionEntry(
label = MR.strings.app_settings,
getter = BackupOptions::appSettings,
setter = { options, enabled -> options.copy(appSettings = enabled) },
),
BackupOptionEntry(
label = MR.strings.source_settings,
getter = BackupOptions::sourceSettings,
setter = { options, enabled -> options.copy(sourceSettings = enabled) },
),
// SY -->
BackupOptionEntry(
label = SYMR.strings.custom_entry_info,
getter = BackupOptions::customInfo,
setter = { options, enabled -> options.copy(customInfo = enabled) },
),
BackupOptionEntry(
label = SYMR.strings.all_read_entries,
getter = BackupOptions::readEntries,
setter = { options, enabled -> options.copy(readEntries = enabled) },
),
// SY <--
)
}
}
data class BackupOptionEntry(
val label: StringResource,
val getter: (BackupOptions) -> Boolean,
val setter: (BackupOptions, Boolean) -> BackupOptions,
)

View File

@ -1,7 +1,6 @@
package eu.kanade.tachiyomi.data.backup.create.creators package eu.kanade.tachiyomi.data.backup.create.creators
import eu.kanade.tachiyomi.data.backup.create.BackupCreateFlags import eu.kanade.tachiyomi.data.backup.create.BackupOptions
import eu.kanade.tachiyomi.data.backup.create.BackupCreateFlags.BACKUP_CUSTOM_INFO
import eu.kanade.tachiyomi.data.backup.models.BackupChapter import eu.kanade.tachiyomi.data.backup.models.BackupChapter
import eu.kanade.tachiyomi.data.backup.models.BackupFlatMetadata import eu.kanade.tachiyomi.data.backup.models.BackupFlatMetadata
import eu.kanade.tachiyomi.data.backup.models.BackupHistory import eu.kanade.tachiyomi.data.backup.models.BackupHistory
@ -35,17 +34,17 @@ class MangaBackupCreator(
// SY <-- // SY <--
) { ) {
suspend fun backupMangas(mangas: List<Manga>, flags: Int): List<BackupManga> { suspend fun backupMangas(mangas: List<Manga>, options: BackupOptions): List<BackupManga> {
return mangas.map { return mangas.map {
backupManga(it, flags) backupManga(it, options)
} }
} }
private suspend fun backupManga(manga: Manga, options: Int): BackupManga { private suspend fun backupManga(manga: Manga, options: BackupOptions): BackupManga {
// Entry for this manga // Entry for this manga
val mangaObject = manga.toBackupManga( val mangaObject = manga.toBackupManga(
// SY --> // SY -->
if (options and BACKUP_CUSTOM_INFO == BACKUP_CUSTOM_INFO) { if (options.customInfo) {
getCustomMangaInfo.get(manga.id) getCustomMangaInfo.get(manga.id)
} else { } else {
null null
@ -67,8 +66,7 @@ class MangaBackupCreator(
} }
// SY <-- // SY <--
// Check if user wants chapter information in backup if (options.chapters) {
if (options and BackupCreateFlags.BACKUP_CHAPTER == BackupCreateFlags.BACKUP_CHAPTER) {
// Backup all the chapters // Backup all the chapters
handler.awaitList { handler.awaitList {
chaptersQueries.getChaptersByMangaId( chaptersQueries.getChaptersByMangaId(
@ -81,8 +79,7 @@ class MangaBackupCreator(
?.let { mangaObject.chapters = it } ?.let { mangaObject.chapters = it }
} }
// Check if user wants category information in backup if (options.categories) {
if (options and BackupCreateFlags.BACKUP_CATEGORY == BackupCreateFlags.BACKUP_CATEGORY) {
// Backup categories for this manga // Backup categories for this manga
val categoriesForManga = getCategories.await(manga.id) val categoriesForManga = getCategories.await(manga.id)
if (categoriesForManga.isNotEmpty()) { if (categoriesForManga.isNotEmpty()) {
@ -90,16 +87,14 @@ class MangaBackupCreator(
} }
} }
// Check if user wants track information in backup if (options.tracking) {
if (options and BackupCreateFlags.BACKUP_TRACK == BackupCreateFlags.BACKUP_TRACK) {
val tracks = handler.awaitList { manga_syncQueries.getTracksByMangaId(manga.id, backupTrackMapper) } val tracks = handler.awaitList { manga_syncQueries.getTracksByMangaId(manga.id, backupTrackMapper) }
if (tracks.isNotEmpty()) { if (tracks.isNotEmpty()) {
mangaObject.tracking = tracks mangaObject.tracking = tracks
} }
} }
// Check if user wants history information in backup if (options.history) {
if (options and BackupCreateFlags.BACKUP_HISTORY == BackupCreateFlags.BACKUP_HISTORY) {
val historyByMangaId = getHistory.await(manga.id) val historyByMangaId = getHistory.await(manga.id)
if (historyByMangaId.isNotEmpty()) { if (historyByMangaId.isNotEmpty()) {
val history = historyByMangaId.map { history -> val history = historyByMangaId.map { history ->

View File

@ -40,7 +40,7 @@ class PreferenceBackupCreator(
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
private fun Map<String, *>.toBackupPreferences(): List<BackupPreference> { private fun Map<String, *>.toBackupPreferences(): List<BackupPreference> {
return this.filterKeys { return this.filterKeys {
!Preference.isPrivate(it) && !Preference.isAppState(it) !Preference.isAppState(it) && !Preference.isPrivate(it)
} }
.mapNotNull { (key, value) -> .mapNotNull { (key, value) ->
when (value) { when (value) {