mirror of
https://github.com/null2264/yokai.git
synced 2025-06-21 10:44:42 +00:00
Migrating titles maintains custom covers
Closes #972 Co-Authored-By: Saud-97 <39028181+Saud-97@users.noreply.github.com>
This commit is contained in:
parent
41c085210c
commit
93e56c194a
7 changed files with 107 additions and 72 deletions
|
@ -135,6 +135,7 @@ dependencies {
|
||||||
implementation("androidx.palette:palette:1.0.0")
|
implementation("androidx.palette:palette:1.0.0")
|
||||||
implementation("androidx.core:core-ktx:1.8.0")
|
implementation("androidx.core:core-ktx:1.8.0")
|
||||||
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.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")
|
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,27 @@
|
||||||
package eu.kanade.tachiyomi.ui.migration
|
package eu.kanade.tachiyomi.ui.migration
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import eu.kanade.tachiyomi.R
|
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 {
|
object MigrationFlags {
|
||||||
|
|
||||||
const val CHAPTERS = 0b001
|
private const val CHAPTERS = 0b0001
|
||||||
const val CATEGORIES = 0b010
|
private const val CATEGORIES = 0b0010
|
||||||
const val TRACK = 0b100
|
private const val TRACK = 0b0100
|
||||||
|
private const val CUSTOM_COVER = 0b1000
|
||||||
|
|
||||||
private const val CHAPTERS2 = 0x1
|
private val coverCache: CoverCache by injectLazy()
|
||||||
private const val CATEGORIES2 = 0x2
|
private val db: DatabaseHelper = Injekt.get()
|
||||||
private const val TRACK2 = 0x4
|
|
||||||
|
|
||||||
val titles get() = arrayOf(R.string.chapters, R.string.categories, R.string.tracking)
|
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)
|
||||||
val flags get() = arrayOf(CHAPTERS, CATEGORIES, TRACK)
|
|
||||||
|
|
||||||
fun hasChapters(value: Int): Boolean {
|
fun hasChapters(value: Int): Boolean {
|
||||||
return value and CHAPTERS != 0
|
return value and CHAPTERS != 0
|
||||||
|
@ -28,11 +35,52 @@ object MigrationFlags {
|
||||||
return value and TRACK != 0
|
return value and TRACK != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getEnabledFlagsPositions(value: Int): List<Int> {
|
fun hasCustomCover(value: Int): Boolean {
|
||||||
return flags.mapIndexedNotNull { index, flag -> if (value and flag != 0) index else null }
|
return value and CUSTOM_COVER != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getFlagsFromPositions(positions: Array<Int>): Int {
|
fun getEnabledFlags(value: Int): List<Boolean> {
|
||||||
return positions.fold(0) { accumulated, position -> accumulated or (1 shl position) }
|
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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,13 +4,17 @@ import android.app.Activity
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.CheckBox
|
||||||
import android.widget.CompoundButton
|
import android.widget.CompoundButton
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
import android.widget.RadioButton
|
import android.widget.RadioButton
|
||||||
import android.widget.RadioGroup
|
import android.widget.RadioGroup
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout
|
import androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
import androidx.core.view.children
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
|
import androidx.core.view.updateLayoutParams
|
||||||
import com.bluelinelabs.conductor.Controller
|
import com.bluelinelabs.conductor.Controller
|
||||||
import com.fredporciuncula.flow.preferences.Preference
|
import com.fredporciuncula.flow.preferences.Preference
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
|
@ -92,21 +96,23 @@ class MigrationBottomSheetDialog(
|
||||||
private fun initPreferences() {
|
private fun initPreferences() {
|
||||||
val flags = preferences.migrateFlags().get()
|
val flags = preferences.migrateFlags().get()
|
||||||
|
|
||||||
binding.migChapters.isChecked = MigrationFlags.hasChapters(flags)
|
val enabledFlags = MigrationFlags.getEnabledFlags(flags)
|
||||||
binding.migCategories.isChecked = MigrationFlags.hasCategories(flags)
|
MigrationFlags.titles.forEachIndexed { index, title ->
|
||||||
binding.migTracking.isChecked = MigrationFlags.hasTracks(flags)
|
val checkbox = CheckBox(context)
|
||||||
|
checkbox.id = title.hashCode()
|
||||||
binding.migChapters.setOnCheckedChangeListener { _, _ -> setFlags() }
|
checkbox.text = context.getString(title)
|
||||||
binding.migCategories.setOnCheckedChangeListener { _, _ -> setFlags() }
|
checkbox.isChecked = enabledFlags[index]
|
||||||
binding.migTracking.setOnCheckedChangeListener { _, _ -> setFlags() }
|
binding.gridFlagsLayout.addView(checkbox)
|
||||||
|
checkbox.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||||
|
marginStart = 8.dpToPx
|
||||||
|
topMargin = 8.dpToPx
|
||||||
|
}
|
||||||
|
checkbox.setOnCheckedChangeListener { _, _ -> setFlags() }
|
||||||
|
}
|
||||||
|
|
||||||
binding.extraSearchParamText.isVisible = false
|
binding.extraSearchParamText.isVisible = false
|
||||||
binding.extraSearchParam.setOnCheckedChangeListener { _, isChecked ->
|
binding.extraSearchParam.setOnCheckedChangeListener { _, isChecked ->
|
||||||
if (isChecked) {
|
binding.extraSearchParamText.isVisible = isChecked
|
||||||
binding.extraSearchParamText.isVisible = true
|
|
||||||
} else {
|
|
||||||
binding.extraSearchParamText.isVisible = false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
binding.sourceGroup.bindToPreference(preferences.useSourceWithMost())
|
binding.sourceGroup.bindToPreference(preferences.useSourceWithMost())
|
||||||
|
|
||||||
|
@ -120,10 +126,8 @@ class MigrationBottomSheetDialog(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setFlags() {
|
private fun setFlags() {
|
||||||
var flags = 0
|
val enabledBoxes = binding.gridFlagsLayout.children.toList().filterIsInstance<CheckBox>().map { it.isChecked }
|
||||||
if (binding.migChapters.isChecked) flags = flags or MigrationFlags.CHAPTERS
|
val flags = MigrationFlags.getFlagsFromPositions(enabledBoxes.toTypedArray())
|
||||||
if (binding.migCategories.isChecked) flags = flags or MigrationFlags.CATEGORIES
|
|
||||||
if (binding.migTracking.isChecked) flags = flags or MigrationFlags.TRACK
|
|
||||||
preferences.migrateFlags().set(flags)
|
preferences.migrateFlags().set(flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.ui.migration.manga.process
|
||||||
|
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
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.DatabaseHelper
|
||||||
import eu.kanade.tachiyomi.data.database.models.History
|
import eu.kanade.tachiyomi.data.database.models.History
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
|
@ -29,6 +30,7 @@ class MigrationProcessAdapter(
|
||||||
var items: List<MigrationProcessItem> = emptyList()
|
var items: List<MigrationProcessItem> = emptyList()
|
||||||
val preferences: PreferencesHelper by injectLazy()
|
val preferences: PreferencesHelper by injectLazy()
|
||||||
val sourceManager: SourceManager by injectLazy()
|
val sourceManager: SourceManager by injectLazy()
|
||||||
|
val coverCache: CoverCache by injectLazy()
|
||||||
|
|
||||||
var showOutline = preferences.outlineOnCovers().get()
|
var showOutline = preferences.outlineOnCovers().get()
|
||||||
val menuItemListener: MigrationProcessInterface = controller
|
val menuItemListener: MigrationProcessInterface = controller
|
||||||
|
@ -130,7 +132,7 @@ class MigrationProcessAdapter(
|
||||||
) {
|
) {
|
||||||
if (controller.config == null) return
|
if (controller.config == null) return
|
||||||
val flags = preferences.migrateFlags().get()
|
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 {
|
companion object {
|
||||||
|
@ -139,6 +141,7 @@ class MigrationProcessAdapter(
|
||||||
flags: Int,
|
flags: Int,
|
||||||
db: DatabaseHelper,
|
db: DatabaseHelper,
|
||||||
enhancedServices: List<EnhancedTrackService>,
|
enhancedServices: List<EnhancedTrackService>,
|
||||||
|
coverCache: CoverCache,
|
||||||
prevSource: Source?,
|
prevSource: Source?,
|
||||||
source: Source,
|
source: Source,
|
||||||
prevManga: Manga,
|
prevManga: Manga,
|
||||||
|
@ -206,6 +209,12 @@ class MigrationProcessAdapter(
|
||||||
manga.favorite = true
|
manga.favorite = true
|
||||||
if (replace) manga.date_added = prevManga.date_added
|
if (replace) manga.date_added = prevManga.date_added
|
||||||
else manga.date_added = Date().time
|
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.updateMangaFavorite(manga).executeAsBlocking()
|
||||||
db.updateMangaAdded(manga).executeAsBlocking()
|
db.updateMangaAdded(manga).executeAsBlocking()
|
||||||
db.updateMangaTitle(manga).executeAsBlocking()
|
db.updateMangaTitle(manga).executeAsBlocking()
|
||||||
|
|
|
@ -258,17 +258,17 @@ private fun showAddDuplicateDialog(
|
||||||
) {
|
) {
|
||||||
val source = sourceManager.getOrStub(libraryManga.source)
|
val source = sourceManager.getOrStub(libraryManga.source)
|
||||||
|
|
||||||
|
val titles by lazy { MigrationFlags.titles(activity, libraryManga) }
|
||||||
fun migrateManga(mDialog: DialogInterface, replace: Boolean) {
|
fun migrateManga(mDialog: DialogInterface, replace: Boolean) {
|
||||||
val listView = (mDialog as AlertDialog).listView
|
val listView = (mDialog as AlertDialog).listView
|
||||||
var flags = 0
|
val enabled = titles.indices.map { listView.isItemChecked(it) }.toTypedArray()
|
||||||
if (listView.isItemChecked(0)) flags = flags or MigrationFlags.CHAPTERS
|
val flags = MigrationFlags.getFlagsFromPositions(enabled, libraryManga)
|
||||||
if (listView.isItemChecked(1)) flags = flags or MigrationFlags.CATEGORIES
|
|
||||||
if (listView.isItemChecked(2)) flags = flags or MigrationFlags.TRACK
|
|
||||||
val enhancedServices by lazy { Injekt.get<TrackManager>().services.filterIsInstance<EnhancedTrackService>() }
|
val enhancedServices by lazy { Injekt.get<TrackManager>().services.filterIsInstance<EnhancedTrackService>() }
|
||||||
MigrationProcessAdapter.migrateMangaInternal(
|
MigrationProcessAdapter.migrateMangaInternal(
|
||||||
flags,
|
flags,
|
||||||
db,
|
db,
|
||||||
enhancedServices,
|
enhancedServices,
|
||||||
|
Injekt.get(),
|
||||||
source,
|
source,
|
||||||
sourceManager.getOrStub(newManga.source),
|
sourceManager.getOrStub(newManga.source),
|
||||||
libraryManga,
|
libraryManga,
|
||||||
|
@ -301,12 +301,9 @@ private fun showAddDuplicateDialog(
|
||||||
activity.materialAlertDialog().apply {
|
activity.materialAlertDialog().apply {
|
||||||
setTitle(R.string.migration)
|
setTitle(R.string.migration)
|
||||||
setMultiChoiceItems(
|
setMultiChoiceItems(
|
||||||
arrayOf(
|
titles,
|
||||||
activity.getString(R.string.chapters),
|
titles.map { true }.toBooleanArray(),
|
||||||
activity.getString(R.string.categories),
|
null,
|
||||||
activity.getString(R.string.tracking),
|
|
||||||
),
|
|
||||||
booleanArrayOf(true, true, true), null,
|
|
||||||
)
|
)
|
||||||
setPositiveButton(R.string.migrate) { mDialog, _ ->
|
setPositiveButton(R.string.migrate) { mDialog, _ ->
|
||||||
migrateManga(mDialog, true)
|
migrateManga(mDialog, true)
|
||||||
|
|
|
@ -34,40 +34,15 @@
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
<CheckBox
|
<com.google.android.flexbox.FlexboxLayout
|
||||||
android:id="@+id/mig_chapters"
|
android:id="@+id/grid_flags_layout"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
android:checked="true"
|
app:flexWrap="wrap"
|
||||||
android:text="@string/chapters"
|
|
||||||
app:layout_constraintStart_toStartOf="@+id/data_label"
|
app:layout_constraintStart_toStartOf="@+id/data_label"
|
||||||
app:layout_constraintTop_toBottomOf="@+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" />
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/options_label"
|
android:id="@+id/options_label"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
@ -75,8 +50,8 @@
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
android:text="@string/options"
|
android:text="@string/options"
|
||||||
style="?textAppearanceTitleSmall"
|
style="?textAppearanceTitleSmall"
|
||||||
app:layout_constraintStart_toStartOf="@+id/mig_chapters"
|
app:layout_constraintStart_toStartOf="@+id/grid_flags_layout"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/mig_chapters" />
|
app:layout_constraintTop_toBottomOf="@+id/grid_flags_layout" />
|
||||||
|
|
||||||
<RadioGroup
|
<RadioGroup
|
||||||
android:id="@+id/sourceGroup"
|
android:id="@+id/sourceGroup"
|
||||||
|
|
|
@ -564,6 +564,7 @@
|
||||||
<string name="error_saving_cover">Error saving cover</string>
|
<string name="error_saving_cover">Error saving cover</string>
|
||||||
<string name="error_sharing_cover">Error sharing cover</string>
|
<string name="error_sharing_cover">Error sharing cover</string>
|
||||||
<string name="custom_manga_info">Custom manga info</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="set_as_default">Set as default</string>
|
||||||
<string name="filter_groups">Filter scanlator groups</string>
|
<string name="filter_groups">Filter scanlator groups</string>
|
||||||
<plurals name="deleted_chapters">
|
<plurals name="deleted_chapters">
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue