Migrating titles maintains custom covers

Closes #972

Co-Authored-By: Saud-97 <39028181+Saud-97@users.noreply.github.com>
This commit is contained in:
Jays2Kings 2022-08-21 03:26:05 -04:00
parent 41c085210c
commit 93e56c194a
7 changed files with 107 additions and 72 deletions

View file

@ -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")

View file

@ -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<Int> {
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>): Int {
return positions.fold(0) { accumulated, position -> accumulated or (1 shl position) }
fun getEnabledFlags(value: Int): List<Boolean> {
return flags.map { flag -> value and flag != 0 }
}
fun getFlagsFromPositions(positions: Array<Boolean>, 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<Boolean>): Int {
return positions.foldIndexed(0) { index, accumulated, enabled ->
accumulated or (enabled.toInt() shl index)
}
}
fun flags(manga: Manga?): Array<Int> {
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<String> {
return flags(manga).map { context.getString(titleForFlag(it)) }.toTypedArray()
}
}

View file

@ -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<ViewGroup.MarginLayoutParams> {
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<CheckBox>().map { it.isChecked }
val flags = MigrationFlags.getFlagsFromPositions(enabledBoxes.toTypedArray())
preferences.migrateFlags().set(flags)
}

View file

@ -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<MigrationProcessItem> = 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<EnhancedTrackService>,
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()

View file

@ -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<TrackManager>().services.filterIsInstance<EnhancedTrackService>() }
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)

View file

@ -34,39 +34,14 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<CheckBox
android:id="@+id/mig_chapters"
android:layout_width="wrap_content"
<com.google.android.flexbox.FlexboxLayout
android:id="@+id/grid_flags_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:checked="true"
android:text="@string/chapters"
app:flexWrap="wrap"
app:layout_constraintStart_toStartOf="@+id/data_label"
app:layout_constraintTop_toBottomOf="@+id/data_label" />
<CheckBox
android:id="@+id/mig_categories"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:checked="true"
android:text="@string/categories"
app:layout_constraintBottom_toBottomOf="@+id/mig_chapters"
app:layout_constraintStart_toEndOf="@+id/mig_chapters"
app:layout_constraintTop_toTopOf="@+id/mig_chapters" />
<CheckBox
android:id="@+id/mig_tracking"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:checked="true"
android:text="@string/tracking"
app:layout_constraintBottom_toBottomOf="@+id/mig_categories"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toEndOf="@+id/mig_categories"
app:layout_constraintTop_toTopOf="@+id/mig_categories" />
app:layout_constraintTop_toBottomOf="@+id/data_label"/>
<TextView
android:id="@+id/options_label"
@ -75,8 +50,8 @@
android:layout_marginTop="8dp"
android:text="@string/options"
style="?textAppearanceTitleSmall"
app:layout_constraintStart_toStartOf="@+id/mig_chapters"
app:layout_constraintTop_toBottomOf="@+id/mig_chapters" />
app:layout_constraintStart_toStartOf="@+id/grid_flags_layout"
app:layout_constraintTop_toBottomOf="@+id/grid_flags_layout" />
<RadioGroup
android:id="@+id/sourceGroup"

View file

@ -564,6 +564,7 @@
<string name="error_saving_cover">Error saving cover</string>
<string name="error_sharing_cover">Error sharing cover</string>
<string name="custom_manga_info">Custom manga info</string>
s<string name="custom_cover">Custom cover</string>
<string name="set_as_default">Set as default</string>
<string name="filter_groups">Filter scanlator groups</string>
<plurals name="deleted_chapters">