From 93e56c194ab45ab5477fef604d4b9ca5fa29bb98 Mon Sep 17 00:00:00 2001 From: Jays2Kings Date: Sun, 21 Aug 2022 03:26:05 -0400 Subject: [PATCH] Migrating titles maintains custom covers Closes #972 Co-Authored-By: Saud-97 <39028181+Saud-97@users.noreply.github.com> --- app/build.gradle.kts | 1 + .../tachiyomi/ui/migration/MigrationFlags.kt | 74 +++++++++++++++---- .../design/MigrationBottomSheetDialog.kt | 36 +++++---- .../manga/process/MigrationProcessAdapter.kt | 11 ++- .../kanade/tachiyomi/util/MangaExtensions.kt | 17 ++--- .../res/layout/migration_bottom_sheet.xml | 39 ++-------- app/src/main/res/values/strings.xml | 1 + 7 files changed, 107 insertions(+), 72 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 4fc3d1bea3..33579a77ba 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -135,6 +135,7 @@ dependencies { implementation("androidx.palette:palette:1.0.0") implementation("androidx.core:core-ktx:1.8.0") implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.0") + implementation("com.google.android.flexbox:flexbox:3.0.0") implementation("androidx.constraintlayout:constraintlayout:2.1.4") diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/MigrationFlags.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/MigrationFlags.kt index cf2ed6dfe5..075519d88a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/MigrationFlags.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/MigrationFlags.kt @@ -1,20 +1,27 @@ package eu.kanade.tachiyomi.ui.migration +import android.content.Context import eu.kanade.tachiyomi.R +import eu.kanade.tachiyomi.data.cache.CoverCache +import eu.kanade.tachiyomi.data.database.DatabaseHelper +import eu.kanade.tachiyomi.data.database.models.Manga +import eu.kanade.tachiyomi.util.system.toInt +import uy.kohesive.injekt.Injekt +import uy.kohesive.injekt.api.get +import uy.kohesive.injekt.injectLazy object MigrationFlags { - const val CHAPTERS = 0b001 - const val CATEGORIES = 0b010 - const val TRACK = 0b100 + private const val CHAPTERS = 0b0001 + private const val CATEGORIES = 0b0010 + private const val TRACK = 0b0100 + private const val CUSTOM_COVER = 0b1000 - private const val CHAPTERS2 = 0x1 - private const val CATEGORIES2 = 0x2 - private const val TRACK2 = 0x4 + private val coverCache: CoverCache by injectLazy() + private val db: DatabaseHelper = Injekt.get() - val titles get() = arrayOf(R.string.chapters, R.string.categories, R.string.tracking) - - val flags get() = arrayOf(CHAPTERS, CATEGORIES, TRACK) + val titles get() = arrayOf(R.string.chapters, R.string.categories, R.string.tracking, R.string.custom_cover) + val flags get() = arrayOf(CHAPTERS, CATEGORIES, TRACK, CUSTOM_COVER) fun hasChapters(value: Int): Boolean { return value and CHAPTERS != 0 @@ -28,11 +35,52 @@ object MigrationFlags { return value and TRACK != 0 } - fun getEnabledFlagsPositions(value: Int): List { - return flags.mapIndexedNotNull { index, flag -> if (value and flag != 0) index else null } + fun hasCustomCover(value: Int): Boolean { + return value and CUSTOM_COVER != 0 } - fun getFlagsFromPositions(positions: Array): Int { - return positions.fold(0) { accumulated, position -> accumulated or (1 shl position) } + fun getEnabledFlags(value: Int): List { + return flags.map { flag -> value and flag != 0 } + } + + fun getFlagsFromPositions(positions: Array, manga: Manga?): Int { + val flags = flags(manga) + return positions.foldIndexed(0) { index, accumulated, enabled -> + accumulated or (if (enabled) flags[index] else 0) + } + } + + fun getFlagsFromPositions(positions: Array): Int { + return positions.foldIndexed(0) { index, accumulated, enabled -> + accumulated or (enabled.toInt() shl index) + } + } + + fun flags(manga: Manga?): Array { + val flags = arrayOf(CHAPTERS, CATEGORIES).toMutableList() + if (manga != null) { + if (db.getTracks(manga).executeAsBlocking().isNotEmpty()) { + flags.add(TRACK) + } + + if (coverCache.getCustomCoverFile(manga).exists()) { + flags.add(CUSTOM_COVER) + } + } + return flags.toTypedArray() + } + + private fun titleForFlag(flag: Int): Int { + return when (flag) { + CHAPTERS -> R.string.chapters + CATEGORIES -> R.string.categories + TRACK -> R.string.tracking + CUSTOM_COVER -> R.string.custom_cover + else -> 0 + } + } + + fun titles(context: Context, manga: Manga?): Array { + return flags(manga).map { context.getString(titleForFlag(it)) }.toTypedArray() } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/design/MigrationBottomSheetDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/design/MigrationBottomSheetDialog.kt index f778a88de1..8b29cdd31d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/design/MigrationBottomSheetDialog.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/design/MigrationBottomSheetDialog.kt @@ -4,13 +4,17 @@ import android.app.Activity import android.content.res.Configuration import android.os.Bundle import android.view.LayoutInflater +import android.view.ViewGroup +import android.widget.CheckBox import android.widget.CompoundButton import android.widget.LinearLayout import android.widget.RadioButton import android.widget.RadioGroup import android.widget.Toast import androidx.constraintlayout.widget.ConstraintLayout +import androidx.core.view.children import androidx.core.view.isVisible +import androidx.core.view.updateLayoutParams import com.bluelinelabs.conductor.Controller import com.fredporciuncula.flow.preferences.Preference import eu.kanade.tachiyomi.R @@ -92,21 +96,23 @@ class MigrationBottomSheetDialog( private fun initPreferences() { val flags = preferences.migrateFlags().get() - binding.migChapters.isChecked = MigrationFlags.hasChapters(flags) - binding.migCategories.isChecked = MigrationFlags.hasCategories(flags) - binding.migTracking.isChecked = MigrationFlags.hasTracks(flags) - - binding.migChapters.setOnCheckedChangeListener { _, _ -> setFlags() } - binding.migCategories.setOnCheckedChangeListener { _, _ -> setFlags() } - binding.migTracking.setOnCheckedChangeListener { _, _ -> setFlags() } + val enabledFlags = MigrationFlags.getEnabledFlags(flags) + MigrationFlags.titles.forEachIndexed { index, title -> + val checkbox = CheckBox(context) + checkbox.id = title.hashCode() + checkbox.text = context.getString(title) + checkbox.isChecked = enabledFlags[index] + binding.gridFlagsLayout.addView(checkbox) + checkbox.updateLayoutParams { + marginStart = 8.dpToPx + topMargin = 8.dpToPx + } + checkbox.setOnCheckedChangeListener { _, _ -> setFlags() } + } binding.extraSearchParamText.isVisible = false binding.extraSearchParam.setOnCheckedChangeListener { _, isChecked -> - if (isChecked) { - binding.extraSearchParamText.isVisible = true - } else { - binding.extraSearchParamText.isVisible = false - } + binding.extraSearchParamText.isVisible = isChecked } binding.sourceGroup.bindToPreference(preferences.useSourceWithMost()) @@ -120,10 +126,8 @@ class MigrationBottomSheetDialog( } private fun setFlags() { - var flags = 0 - if (binding.migChapters.isChecked) flags = flags or MigrationFlags.CHAPTERS - if (binding.migCategories.isChecked) flags = flags or MigrationFlags.CATEGORIES - if (binding.migTracking.isChecked) flags = flags or MigrationFlags.TRACK + val enabledBoxes = binding.gridFlagsLayout.children.toList().filterIsInstance().map { it.isChecked } + val flags = MigrationFlags.getFlagsFromPositions(enabledBoxes.toTypedArray()) preferences.migrateFlags().set(flags) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigrationProcessAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigrationProcessAdapter.kt index 4d12cb7303..c140db33fb 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigrationProcessAdapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigrationProcessAdapter.kt @@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.ui.migration.manga.process import android.view.MenuItem import eu.davidea.flexibleadapter.FlexibleAdapter +import eu.kanade.tachiyomi.data.cache.CoverCache import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.database.models.History import eu.kanade.tachiyomi.data.database.models.Manga @@ -29,6 +30,7 @@ class MigrationProcessAdapter( var items: List = emptyList() val preferences: PreferencesHelper by injectLazy() val sourceManager: SourceManager by injectLazy() + val coverCache: CoverCache by injectLazy() var showOutline = preferences.outlineOnCovers().get() val menuItemListener: MigrationProcessInterface = controller @@ -130,7 +132,7 @@ class MigrationProcessAdapter( ) { if (controller.config == null) return val flags = preferences.migrateFlags().get() - migrateMangaInternal(flags, db, enhancedServices, prevSource, source, prevManga, manga, replace) + migrateMangaInternal(flags, db, enhancedServices, coverCache, prevSource, source, prevManga, manga, replace) } companion object { @@ -139,6 +141,7 @@ class MigrationProcessAdapter( flags: Int, db: DatabaseHelper, enhancedServices: List, + coverCache: CoverCache, prevSource: Source?, source: Source, prevManga: Manga, @@ -206,6 +209,12 @@ class MigrationProcessAdapter( manga.favorite = true if (replace) manga.date_added = prevManga.date_added else manga.date_added = Date().time + + // Update custom cover + if (MigrationFlags.hasCustomCover(flags) && coverCache.getCustomCoverFile(prevManga).exists()) { + coverCache.setCustomCoverToCache(manga, coverCache.getCustomCoverFile(prevManga).inputStream()) + } + db.updateMangaFavorite(manga).executeAsBlocking() db.updateMangaAdded(manga).executeAsBlocking() db.updateMangaTitle(manga).executeAsBlocking() diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/MangaExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/MangaExtensions.kt index 3d488a4956..214098fa23 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/MangaExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/MangaExtensions.kt @@ -258,17 +258,17 @@ private fun showAddDuplicateDialog( ) { val source = sourceManager.getOrStub(libraryManga.source) + val titles by lazy { MigrationFlags.titles(activity, libraryManga) } fun migrateManga(mDialog: DialogInterface, replace: Boolean) { val listView = (mDialog as AlertDialog).listView - var flags = 0 - if (listView.isItemChecked(0)) flags = flags or MigrationFlags.CHAPTERS - if (listView.isItemChecked(1)) flags = flags or MigrationFlags.CATEGORIES - if (listView.isItemChecked(2)) flags = flags or MigrationFlags.TRACK + val enabled = titles.indices.map { listView.isItemChecked(it) }.toTypedArray() + val flags = MigrationFlags.getFlagsFromPositions(enabled, libraryManga) val enhancedServices by lazy { Injekt.get().services.filterIsInstance() } MigrationProcessAdapter.migrateMangaInternal( flags, db, enhancedServices, + Injekt.get(), source, sourceManager.getOrStub(newManga.source), libraryManga, @@ -301,12 +301,9 @@ private fun showAddDuplicateDialog( activity.materialAlertDialog().apply { setTitle(R.string.migration) setMultiChoiceItems( - arrayOf( - activity.getString(R.string.chapters), - activity.getString(R.string.categories), - activity.getString(R.string.tracking), - ), - booleanArrayOf(true, true, true), null, + titles, + titles.map { true }.toBooleanArray(), + null, ) setPositiveButton(R.string.migrate) { mDialog, _ -> migrateManga(mDialog, true) diff --git a/app/src/main/res/layout/migration_bottom_sheet.xml b/app/src/main/res/layout/migration_bottom_sheet.xml index 0fb6e607fc..60fb5b5bae 100644 --- a/app/src/main/res/layout/migration_bottom_sheet.xml +++ b/app/src/main/res/layout/migration_bottom_sheet.xml @@ -34,39 +34,14 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> - - - - - + app:layout_constraintTop_toBottomOf="@+id/data_label"/> + app:layout_constraintStart_toStartOf="@+id/grid_flags_layout" + app:layout_constraintTop_toBottomOf="@+id/grid_flags_layout" /> Error saving cover Error sharing cover Custom manga info + sCustom cover Set as default Filter scanlator groups