Fixes and such for integration to AZ
This commit is contained in:
parent
18f90587f2
commit
aefa7a1a4a
@ -5,7 +5,7 @@ import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.util.await
|
||||
import exh.util.await
|
||||
import info.debatty.java.stringsimilarity.NormalizedLevenshtein
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
@ -22,10 +22,10 @@ class MigrationMangaDialog<T>(bundle: Bundle? = null) : DialogController(bundle)
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||
val confirmRes = if (copy) R.string.confirm_copy else R.string.confirm_migration
|
||||
val confirmString = applicationContext?.getString(confirmRes, mangaSet, (
|
||||
if (mangaSkipped > 0)
|
||||
" " + applicationContext?.getString(R.string.skipping_x, mangaSkipped) ?: ""
|
||||
val confirmRes = if (copy) R.plurals.copy_manga else R.plurals.migrate_manga
|
||||
val confirmString = applicationContext?.resources?.getQuantityString(confirmRes, mangaSet,
|
||||
mangaSet, (
|
||||
if (mangaSkipped > 0) " " + applicationContext?.getString(R.string.skipping_, mangaSkipped)
|
||||
else "")) ?: ""
|
||||
return MaterialDialog.Builder(activity!!)
|
||||
.content(confirmString)
|
||||
|
@ -1,34 +1,16 @@
|
||||
package eu.kanade.tachiyomi.ui.migration
|
||||
|
||||
import android.os.Bundle
|
||||
import com.jakewharton.rxrelay.BehaviorRelay
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.database.models.MangaCategory
|
||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchCardItem
|
||||
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchItem
|
||||
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchPresenter
|
||||
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
|
||||
import rx.Observable
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
import rx.schedulers.Schedulers
|
||||
import eu.kanade.tachiyomi.ui.source.globalsearch.GlobalSearchCardItem
|
||||
import eu.kanade.tachiyomi.ui.source.globalsearch.GlobalSearchItem
|
||||
import eu.kanade.tachiyomi.ui.source.globalsearch.GlobalSearchPresenter
|
||||
|
||||
class SearchPresenter(
|
||||
initialQuery: String? = "",
|
||||
private val manga: Manga
|
||||
) : GlobalSearchPresenter(initialQuery) {
|
||||
|
||||
private val replacingMangaRelay = BehaviorRelay.create<Boolean>()
|
||||
|
||||
override fun onCreate(savedState: Bundle?) {
|
||||
super.onCreate(savedState)
|
||||
|
||||
replacingMangaRelay.subscribeLatestCache({ controller, isReplacingManga -> (controller as? SearchController)?.renderIsReplacingManga(isReplacingManga) })
|
||||
}
|
||||
|
||||
override fun getEnabledSources(): List<CatalogueSource> {
|
||||
// Put the source of the selected manga at the top
|
||||
return super.getEnabledSources()
|
||||
@ -39,106 +21,4 @@ class SearchPresenter(
|
||||
// Set the catalogue search item as highlighted if the source matches that of the selected manga
|
||||
return GlobalSearchItem(source, results, source.id == manga.source)
|
||||
}
|
||||
|
||||
override fun networkToLocalManga(sManga: SManga, sourceId: Long): Manga {
|
||||
val localManga = super.networkToLocalManga(sManga, sourceId)
|
||||
// For migration, displayed title should always match source rather than local DB
|
||||
localManga.title = sManga.title
|
||||
return localManga
|
||||
}
|
||||
|
||||
fun migrateManga(prevManga: Manga, manga: Manga, replace: Boolean) {
|
||||
val source = sourceManager.get(manga.source) ?: return
|
||||
|
||||
replacingMangaRelay.call(true)
|
||||
|
||||
Observable.defer { source.fetchChapterList(manga) }
|
||||
.onErrorReturn { emptyList() }
|
||||
.doOnNext { migrateMangaInternal(source, it, prevManga, manga, replace) }
|
||||
.onErrorReturn { emptyList() }
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.doOnUnsubscribe { replacingMangaRelay.call(false) }
|
||||
.subscribe()
|
||||
}
|
||||
|
||||
private fun migrateMangaInternal(
|
||||
source: Source,
|
||||
sourceChapters: List<SChapter>,
|
||||
prevManga: Manga,
|
||||
manga: Manga,
|
||||
replace: Boolean
|
||||
) {
|
||||
val flags = preferences.migrateFlags().get()
|
||||
val migrateChapters = MigrationFlags.hasChapters(flags)
|
||||
val migrateCategories = MigrationFlags.hasCategories(flags)
|
||||
val migrateTracks = MigrationFlags.hasTracks(flags)
|
||||
|
||||
db.inTransaction {
|
||||
// Update chapters read
|
||||
if (migrateChapters) {
|
||||
try {
|
||||
syncChaptersWithSource(db, sourceChapters, manga, source)
|
||||
} catch (e: Exception) {
|
||||
// Worst case, chapters won't be synced
|
||||
}
|
||||
|
||||
val prevMangaChapters = db.getChapters(prevManga).executeAsBlocking()
|
||||
val maxChapterRead = prevMangaChapters
|
||||
.filter { it.read }
|
||||
.maxBy { it.chapter_number }?.chapter_number
|
||||
val bookmarkedChapters = prevMangaChapters
|
||||
.filter { it.bookmark && it.isRecognizedNumber }
|
||||
.map { it.chapter_number }
|
||||
if (maxChapterRead != null) {
|
||||
val dbChapters = db.getChapters(manga).executeAsBlocking()
|
||||
for (chapter in dbChapters) {
|
||||
if (chapter.isRecognizedNumber) {
|
||||
if (chapter.chapter_number <= maxChapterRead) {
|
||||
chapter.read = true
|
||||
}
|
||||
if (chapter.chapter_number in bookmarkedChapters) {
|
||||
chapter.bookmark = true
|
||||
}
|
||||
}
|
||||
}
|
||||
db.insertChapters(dbChapters).executeAsBlocking()
|
||||
}
|
||||
}
|
||||
|
||||
// Update categories
|
||||
if (migrateCategories) {
|
||||
val categories = db.getCategoriesForManga(prevManga).executeAsBlocking()
|
||||
val mangaCategories = categories.map { MangaCategory.create(manga, it) }
|
||||
db.setMangaCategories(mangaCategories, listOf(manga))
|
||||
}
|
||||
|
||||
// Update track
|
||||
if (migrateTracks) {
|
||||
val tracks = db.getTracks(prevManga).executeAsBlocking()
|
||||
for (track in tracks) {
|
||||
track.id = null
|
||||
track.manga_id = manga.id!!
|
||||
}
|
||||
db.insertTracks(tracks).executeAsBlocking()
|
||||
}
|
||||
|
||||
// Update favorite status
|
||||
if (replace) {
|
||||
prevManga.favorite = false
|
||||
db.updateMangaFavorite(prevManga).executeAsBlocking()
|
||||
}
|
||||
manga.favorite = true
|
||||
db.updateMangaFavorite(manga).executeAsBlocking()
|
||||
|
||||
// Update reading preferences
|
||||
manga.chapter_flags = prevManga.chapter_flags
|
||||
db.updateFlags(manga).executeAsBlocking()
|
||||
manga.viewer = prevManga.viewer
|
||||
db.updateMangaViewer(manga).executeAsBlocking()
|
||||
|
||||
// SearchPresenter#networkToLocalManga may have updated the manga title, so ensure db gets updated title
|
||||
db.updateMangaTitle(manga).executeAsBlocking()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ import eu.davidea.flexibleadapter.items.AbstractHeaderItem
|
||||
import eu.davidea.flexibleadapter.items.IFlexible
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder
|
||||
import kotlinx.android.synthetic.main.source_main_controller_card_header.title
|
||||
import kotlinx.android.synthetic.main.source_main_controller_card.title
|
||||
|
||||
/**
|
||||
* Item that contains the selection header.
|
||||
@ -18,7 +18,7 @@ class SelectionHeader : AbstractHeaderItem<SelectionHeader.Holder>() {
|
||||
* Returns the layout resource of this item.
|
||||
*/
|
||||
override fun getLayoutRes(): Int {
|
||||
return R.layout.source_main_controller_card_header
|
||||
return R.layout.source_main_controller_card
|
||||
}
|
||||
|
||||
/**
|
||||
@ -35,14 +35,14 @@ class SelectionHeader : AbstractHeaderItem<SelectionHeader.Holder>() {
|
||||
adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>,
|
||||
holder: Holder,
|
||||
position: Int,
|
||||
payloads: List<Any?>?
|
||||
payloads: MutableList<Any?>?
|
||||
) {
|
||||
// Intentionally empty
|
||||
}
|
||||
|
||||
class Holder(view: View, adapter: FlexibleAdapter<*>) : BaseFlexibleViewHolder(view, adapter) {
|
||||
class Holder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>) : BaseFlexibleViewHolder(view, adapter) {
|
||||
init {
|
||||
title.text = view.context.getString(R.string.migration_selection_prompt)
|
||||
title.text = view.context.getString(R.string.select_a_source_to_migrate_from)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,12 +19,12 @@ import eu.kanade.tachiyomi.ui.base.controller.BaseController
|
||||
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
||||
import eu.kanade.tachiyomi.ui.migration.manga.process.MigrationListController
|
||||
import eu.kanade.tachiyomi.ui.migration.manga.process.MigrationProcedureConfig
|
||||
import eu.kanade.tachiyomi.util.view.doOnApplyWindowInsets
|
||||
import eu.kanade.tachiyomi.util.view.marginBottom
|
||||
import eu.kanade.tachiyomi.util.view.updateLayoutParams
|
||||
import eu.kanade.tachiyomi.util.view.updatePaddingRelative
|
||||
import kotlinx.android.synthetic.main.pre_migration_controller.fab
|
||||
import kotlinx.android.synthetic.main.pre_migration_controller.recycler
|
||||
import exh.util.applyWindowInsetsForController
|
||||
import exh.util.doOnApplyWindowInsets
|
||||
import exh.util.marginBottom
|
||||
import exh.util.updateLayoutParams
|
||||
import exh.util.updatePaddingRelative
|
||||
import kotlinx.android.synthetic.main.pre_migration_controller.*
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
class PreMigrationController(bundle: Bundle? = null) : BaseController(bundle), FlexibleAdapter
|
||||
@ -48,6 +48,7 @@ class PreMigrationController(bundle: Bundle? = null) : BaseController(bundle), F
|
||||
|
||||
override fun onViewCreated(view: View) {
|
||||
super.onViewCreated(view)
|
||||
view.applyWindowInsetsForController()
|
||||
|
||||
val ourAdapter = adapter ?: MigrationSourceAdapter(
|
||||
getEnabledSources().map { MigrationSourceItem(it, isEnabled(it.id.toString())) },
|
||||
@ -99,7 +100,7 @@ class PreMigrationController(bundle: Bundle? = null) : BaseController(bundle), F
|
||||
config.toList(),
|
||||
extraSearchParams = extraParam
|
||||
)
|
||||
).withFadeTransaction())
|
||||
).withFadeTransaction().tag(MigrationListController.TAG))
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
@ -129,7 +130,7 @@ class PreMigrationController(bundle: Bundle? = null) : BaseController(bundle), F
|
||||
private fun getEnabledSources(): List<HttpSource> {
|
||||
val languages = prefs.enabledLanguages().getOrDefault()
|
||||
val sourcesSaved = prefs.migrationSources().getOrDefault().split("/")
|
||||
var sources = sourceManager.getCatalogueSources()
|
||||
var sources = sourceManager.getVisibleCatalogueSources()
|
||||
.filterIsInstance<HttpSource>()
|
||||
.filter { it.lang in languages }
|
||||
.sortedBy { "(${it.lang}) ${it.name}" }
|
||||
|
@ -31,12 +31,14 @@ import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||
import eu.kanade.tachiyomi.ui.migration.MigrationMangaDialog
|
||||
import eu.kanade.tachiyomi.ui.migration.SearchController
|
||||
import eu.kanade.tachiyomi.ui.migration.manga.design.PreMigrationController
|
||||
import eu.kanade.tachiyomi.util.await
|
||||
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
|
||||
import eu.kanade.tachiyomi.util.lang.launchUI
|
||||
import eu.kanade.tachiyomi.util.system.executeOnIO
|
||||
import eu.kanade.tachiyomi.util.system.getResourceColor
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import eu.kanade.tachiyomi.util.view.RecyclerWindowInsetsListener
|
||||
import exh.util.RecyclerWindowInsetsListener
|
||||
import exh.util.applyWindowInsetsForController
|
||||
import exh.util.await
|
||||
import exh.util.executeOnIO
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlinx.android.synthetic.main.chapters_controller.*
|
||||
@ -55,8 +57,7 @@ import timber.log.Timber
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
class MigrationListController(bundle: Bundle? = null) : BaseController(bundle),
|
||||
MigrationProcessAdapter.MigrationProcessInterface,
|
||||
CoroutineScope {
|
||||
MigrationProcessAdapter.MigrationProcessInterface, CoroutineScope {
|
||||
|
||||
init {
|
||||
setHasOptionsMenu(true)
|
||||
@ -74,7 +75,8 @@ class MigrationListController(bundle: Bundle? = null) : BaseController(bundle),
|
||||
|
||||
private val smartSearchEngine = SmartSearchEngine(coroutineContext, config?.extraSearchParams)
|
||||
|
||||
private var migrationsJob: Job? = null
|
||||
var migrationsJob: Job? = null
|
||||
private set
|
||||
private var migratingManga: MutableList<MigratingManga>? = null
|
||||
private var selectedPosition: Int? = null
|
||||
private var manaulMigrations = 0
|
||||
@ -84,12 +86,15 @@ class MigrationListController(bundle: Bundle? = null) : BaseController(bundle),
|
||||
}
|
||||
|
||||
override fun getTitle(): String? {
|
||||
return resources?.getString(R.string.migration) + " (${adapter?.items?.count { it.manga
|
||||
.migrationStatus != MigrationStatus.RUNNUNG }}/${adapter?.itemCount ?: 0})"
|
||||
return resources?.getString(R.string.migration) + " (${adapter?.items?.count {
|
||||
it.manga.migrationStatus != MigrationStatus.RUNNUNG
|
||||
}}/${adapter?.itemCount ?: 0})"
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View) {
|
||||
|
||||
super.onViewCreated(view)
|
||||
view.applyWindowInsetsForController()
|
||||
setTitle()
|
||||
val config = this.config ?: return
|
||||
|
||||
@ -101,7 +106,7 @@ class MigrationListController(bundle: Bundle? = null) : BaseController(bundle),
|
||||
new
|
||||
}
|
||||
|
||||
adapter = MigrationProcessAdapter(this, view.context)
|
||||
adapter = MigrationProcessAdapter(this)
|
||||
|
||||
recycler.adapter = adapter
|
||||
recycler.layoutManager = LinearLayoutManager(view.context)
|
||||
@ -117,23 +122,14 @@ class MigrationListController(bundle: Bundle? = null) : BaseController(bundle),
|
||||
}
|
||||
}
|
||||
|
||||
fun migrationFailure() {
|
||||
activity?.let {
|
||||
MaterialDialog.Builder(it)
|
||||
.title("Migration failure")
|
||||
.content("An unknown error occured while migrating this manga!")
|
||||
.positiveText("Ok")
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun runMigrations(mangas: List<MigratingManga>) {
|
||||
private suspend fun runMigrations(mangas: List<MigratingManga>) {
|
||||
val useSourceWithMost = preferences.useSourceWithMost().getOrDefault()
|
||||
val useSmartSearch = preferences.smartMigration().getOrDefault()
|
||||
|
||||
val sources = preferences.migrationSources().getOrDefault().split("/").mapNotNull {
|
||||
val value = it.toLongOrNull() ?: return
|
||||
sourceManager.get(value) as? CatalogueSource }
|
||||
sourceManager.get(value) as? CatalogueSource
|
||||
}
|
||||
if (config == null) return
|
||||
for (manga in mangas) {
|
||||
if (migrationsJob?.isCancelled == true) {
|
||||
@ -173,11 +169,23 @@ class MigrationListController(bundle: Bundle? = null) : BaseController(bundle),
|
||||
}
|
||||
|
||||
if (searchResult != null) {
|
||||
val localManga = smartSearchEngine.networkToLocalManga(searchResult, source.id)
|
||||
val chapters = source.fetchChapterList(localManga).toSingle().await(
|
||||
Schedulers.io())
|
||||
val localManga =
|
||||
smartSearchEngine.networkToLocalManga(
|
||||
searchResult,
|
||||
source.id
|
||||
)
|
||||
val chapters =
|
||||
source.fetchChapterList(localManga).toSingle()
|
||||
.await(
|
||||
Schedulers.io()
|
||||
)
|
||||
try {
|
||||
syncChaptersWithSource(db, chapters, localManga, source)
|
||||
syncChaptersWithSource(
|
||||
db,
|
||||
chapters,
|
||||
localManga,
|
||||
source
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
return@async null
|
||||
}
|
||||
@ -239,10 +247,9 @@ class MigrationListController(bundle: Bundle? = null) : BaseController(bundle),
|
||||
|
||||
if (result != null && result.thumbnail_url == null) {
|
||||
try {
|
||||
val newManga = sourceManager.getOrStub(result.source)
|
||||
.fetchMangaDetails(result)
|
||||
.toSingle()
|
||||
.await()
|
||||
val newManga =
|
||||
sourceManager.getOrStub(result.source).fetchMangaDetails(result)
|
||||
.toSingle().await()
|
||||
result.copyFrom(newManga)
|
||||
|
||||
db.insertManga(result).executeAsBlocking()
|
||||
@ -253,8 +260,8 @@ class MigrationListController(bundle: Bundle? = null) : BaseController(bundle),
|
||||
}
|
||||
}
|
||||
|
||||
manga.migrationStatus = if (result == null) MigrationStatus.MANGA_NOT_FOUND else
|
||||
MigrationStatus.MANGA_FOUND
|
||||
manga.migrationStatus =
|
||||
if (result == null) MigrationStatus.MANGA_NOT_FOUND else MigrationStatus.MANGA_FOUND
|
||||
adapter?.sourceFinished()
|
||||
manga.searchResult.initialize(result?.id)
|
||||
}
|
||||
@ -286,8 +293,7 @@ class MigrationListController(bundle: Bundle? = null) : BaseController(bundle),
|
||||
ids.removeAt(index)
|
||||
config.mangaIds = ids
|
||||
val index2 = migratingManga?.indexOf(item.manga) ?: return
|
||||
if (index2 > -1)
|
||||
migratingManga?.removeAt(index2)
|
||||
if (index2 > -1) migratingManga?.removeAt(index2)
|
||||
}
|
||||
}
|
||||
|
||||
@ -296,8 +302,9 @@ class MigrationListController(bundle: Bundle? = null) : BaseController(bundle),
|
||||
val res = resources
|
||||
if (res != null) {
|
||||
activity?.toast(
|
||||
res.getQuantityString(R.plurals.manga_migrated,
|
||||
manaulMigrations, manaulMigrations)
|
||||
res.getQuantityString(
|
||||
R.plurals.manga_migrated, manaulMigrations, manaulMigrations
|
||||
)
|
||||
)
|
||||
}
|
||||
router.popCurrentController()
|
||||
@ -366,7 +373,7 @@ class MigrationListController(bundle: Bundle? = null) : BaseController(bundle),
|
||||
adapter?.notifyDataSetChanged()
|
||||
} else {
|
||||
migratingManga.manga.migrationStatus = MigrationStatus.MANGA_NOT_FOUND
|
||||
activity?.toast(R.string.error_fetching_migration, Toast.LENGTH_LONG)
|
||||
activity?.toast(R.string.no_chapters_found_for_migration, Toast.LENGTH_LONG)
|
||||
adapter?.notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
@ -411,7 +418,7 @@ class MigrationListController(bundle: Bundle? = null) : BaseController(bundle),
|
||||
|
||||
override fun handleBack(): Boolean {
|
||||
activity?.let {
|
||||
MaterialDialog.Builder(it).title(R.string.stop_migration)
|
||||
MaterialDialog.Builder(it).title(R.string.stop_migrating)
|
||||
.positiveText(R.string.action_stop)
|
||||
.negativeText(android.R.string.cancel)
|
||||
.onPositive { _, _ ->
|
||||
@ -441,12 +448,16 @@ class MigrationListController(bundle: Bundle? = null) : BaseController(bundle),
|
||||
|
||||
if (adapter?.itemCount == 1) {
|
||||
menuMigrate.icon = VectorDrawableCompat.create(
|
||||
resources!!, R.drawable.ic_done, null
|
||||
resources!!, R.drawable.ic_done_24dp, null
|
||||
)
|
||||
}
|
||||
val translucentWhite = ColorUtils.setAlphaComponent(Color.WHITE, 127)
|
||||
menuCopy.icon?.setTint(if (allMangasDone) Color.WHITE else translucentWhite)
|
||||
menuMigrate?.icon?.setTint(if (allMangasDone) Color.WHITE else translucentWhite)
|
||||
|
||||
menuCopy.icon.mutate()
|
||||
menuMigrate.icon.mutate()
|
||||
val tintColor = activity?.getResourceColor(R.attr.colorPrimary) ?: Color.WHITE
|
||||
val translucentWhite = ColorUtils.setAlphaComponent(tintColor, 127)
|
||||
menuCopy.icon?.setTint(if (allMangasDone) tintColor else translucentWhite)
|
||||
menuMigrate?.icon?.setTint(if (allMangasDone) tintColor else translucentWhite)
|
||||
menuCopy.isEnabled = allMangasDone
|
||||
menuMigrate.isEnabled = allMangasDone
|
||||
}
|
||||
@ -455,10 +466,18 @@ class MigrationListController(bundle: Bundle? = null) : BaseController(bundle),
|
||||
val totalManga = adapter?.itemCount ?: 0
|
||||
val mangaSkipped = adapter?.mangasSkipped() ?: 0
|
||||
when (item.itemId) {
|
||||
R.id.action_copy_manga -> MigrationMangaDialog(this, true, totalManga, mangaSkipped)
|
||||
.showDialog(router)
|
||||
R.id.action_migrate_manga -> MigrationMangaDialog(this, false, totalManga, mangaSkipped)
|
||||
.showDialog(router)
|
||||
R.id.action_copy_manga -> MigrationMangaDialog(
|
||||
this,
|
||||
true,
|
||||
totalManga,
|
||||
mangaSkipped
|
||||
).showDialog(router)
|
||||
R.id.action_migrate_manga -> MigrationMangaDialog(
|
||||
this,
|
||||
false,
|
||||
totalManga,
|
||||
mangaSkipped
|
||||
).showDialog(router)
|
||||
else -> return super.onOptionsItemSelected(item)
|
||||
}
|
||||
return true
|
||||
|
@ -1,6 +1,5 @@
|
||||
package eu.kanade.tachiyomi.ui.migration.manga.process
|
||||
|
||||
import android.content.Context
|
||||
import android.view.MenuItem
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
@ -16,8 +15,7 @@ import kotlinx.coroutines.withContext
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
class MigrationProcessAdapter(
|
||||
val controller: MigrationListController,
|
||||
context: Context
|
||||
val controller: MigrationListController
|
||||
) : FlexibleAdapter<MigrationProcessItem>(null, controller, true) {
|
||||
|
||||
private val db: DatabaseHelper by injectLazy()
|
||||
@ -73,7 +71,8 @@ class MigrationProcessAdapter(
|
||||
launchUI {
|
||||
val manga = getItem(position)?.manga ?: return@launchUI
|
||||
db.inTransaction {
|
||||
val toMangaObj = db.getManga(manga.searchResult.get() ?: return@launchUI).executeAsBlocking()
|
||||
val toMangaObj =
|
||||
db.getManga(manga.searchResult.get() ?: return@launchUI).executeAsBlocking()
|
||||
?: return@launchUI
|
||||
migrateMangaInternal(
|
||||
manga.manga() ?: return@launchUI, toMangaObj, !copy
|
||||
@ -135,8 +134,8 @@ class MigrationProcessAdapter(
|
||||
db.updateMangaFavorite(prevManga).executeAsBlocking()
|
||||
}
|
||||
manga.favorite = true
|
||||
// SearchPresenter#networkToLocalManga may have updated the manga title, so ensure db gets updated title
|
||||
|
||||
db.updateMangaFavorite(manga).executeAsBlocking()
|
||||
db.updateMangaTitle(manga).executeAsBlocking()
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
@ -152,10 +152,10 @@ class MigrationProcessHolder(
|
||||
val latestChapter = mangaChapters.maxBy { it.chapter_number }?.chapter_number ?: -1f
|
||||
|
||||
if (latestChapter > 0f) {
|
||||
manga_last_chapter_label.text = context.getString(R.string.latest_x,
|
||||
manga_last_chapter_label.text = context.getString(R.string.latest_,
|
||||
DecimalFormat("#.#").format(latestChapter))
|
||||
} else {
|
||||
manga_last_chapter_label.text = context.getString(R.string.latest_x,
|
||||
manga_last_chapter_label.text = context.getString(R.string.latest_,
|
||||
context.getString(R.string.unknown))
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package eu.kanade.tachiyomi.util.system
|
||||
package exh.util
|
||||
|
||||
import com.pushtorefresh.storio.sqlite.operations.get.PreparedGetListOfObjects
|
||||
import com.pushtorefresh.storio.sqlite.operations.get.PreparedGetObject
|
101
app/src/main/java/exh/util/ViewExtensions.kt
Normal file
101
app/src/main/java/exh/util/ViewExtensions.kt
Normal file
@ -0,0 +1,101 @@
|
||||
package exh.util
|
||||
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.WindowInsets
|
||||
import android.widget.FrameLayout
|
||||
import androidx.annotation.Px
|
||||
|
||||
inline val View.marginTop: Int
|
||||
get() = (layoutParams as? ViewGroup.MarginLayoutParams)?.topMargin ?: 0
|
||||
|
||||
inline val View.marginBottom: Int
|
||||
get() = (layoutParams as? ViewGroup.MarginLayoutParams)?.bottomMargin ?: 0
|
||||
|
||||
inline val View.marginRight: Int
|
||||
get() = (layoutParams as? ViewGroup.MarginLayoutParams)?.rightMargin ?: 0
|
||||
|
||||
inline val View.marginLeft: Int
|
||||
get() = (layoutParams as? ViewGroup.MarginLayoutParams)?.leftMargin ?: 0
|
||||
|
||||
fun View.doOnApplyWindowInsets(f: (View, WindowInsets, ViewPaddingState) -> Unit) {
|
||||
// Create a snapshot of the view's padding state
|
||||
val paddingState = createStateForView(this)
|
||||
setOnApplyWindowInsetsListener { v, insets ->
|
||||
f(v, insets, paddingState)
|
||||
insets
|
||||
}
|
||||
requestApplyInsetsWhenAttached()
|
||||
}
|
||||
|
||||
object ControllerViewWindowInsetsListener : View.OnApplyWindowInsetsListener {
|
||||
override fun onApplyWindowInsets(v: View, insets: WindowInsets): WindowInsets {
|
||||
v.updateLayoutParams<FrameLayout.LayoutParams> {
|
||||
val attrsArray = intArrayOf(android.R.attr.actionBarSize)
|
||||
val array = v.context.obtainStyledAttributes(attrsArray)
|
||||
topMargin = insets.systemWindowInsetTop + array.getDimensionPixelSize(0, 0)
|
||||
array.recycle()
|
||||
}
|
||||
return insets
|
||||
}
|
||||
}
|
||||
|
||||
fun View.requestApplyInsetsWhenAttached() {
|
||||
if (isAttachedToWindow) {
|
||||
requestApplyInsets()
|
||||
} else {
|
||||
addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener {
|
||||
override fun onViewAttachedToWindow(v: View) {
|
||||
v.requestApplyInsets()
|
||||
}
|
||||
|
||||
override fun onViewDetachedFromWindow(v: View) = Unit
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <reified T : ViewGroup.LayoutParams> View.updateLayoutParams(block: T.() -> Unit) {
|
||||
val params = layoutParams as T
|
||||
block(params)
|
||||
layoutParams = params
|
||||
}
|
||||
|
||||
fun View.applyWindowInsetsForController() {
|
||||
setOnApplyWindowInsetsListener(ControllerViewWindowInsetsListener)
|
||||
requestApplyInsetsWhenAttached()
|
||||
}
|
||||
|
||||
inline fun View.updatePaddingRelative(
|
||||
@Px start: Int = paddingStart,
|
||||
@Px top: Int = paddingTop,
|
||||
@Px end: Int = paddingEnd,
|
||||
@Px bottom: Int = paddingBottom
|
||||
) {
|
||||
setPaddingRelative(start, top, end, bottom)
|
||||
}
|
||||
|
||||
private fun createStateForView(view: View) = ViewPaddingState(
|
||||
view.paddingLeft,
|
||||
view.paddingTop,
|
||||
view.paddingRight,
|
||||
view.paddingBottom,
|
||||
view.paddingStart,
|
||||
view.paddingEnd
|
||||
)
|
||||
|
||||
data class ViewPaddingState(
|
||||
val left: Int,
|
||||
val top: Int,
|
||||
val right: Int,
|
||||
val bottom: Int,
|
||||
val start: Int,
|
||||
val end: Int
|
||||
)
|
||||
|
||||
object RecyclerWindowInsetsListener : View.OnApplyWindowInsetsListener {
|
||||
override fun onApplyWindowInsets(v: View, insets: WindowInsets): WindowInsets {
|
||||
v.updatePaddingRelative(bottom = insets.systemWindowInsetBottom)
|
||||
// v.updatePaddingRelative(bottom = v.paddingBottom + insets.systemWindowInsetBottom)
|
||||
return insets
|
||||
}
|
||||
}
|
@ -333,12 +333,18 @@
|
||||
app:layout_constraintTop_toBottomOf="@id/manga_genres_tags_wrapper" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/smartsearch_merge_btn"
|
||||
style="@style/Widget.AppCompat.Button.Colored"
|
||||
android:id="@+id/merge_btn"
|
||||
style="@style/Widget.MaterialComponents.Button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:text="Merge with current" />
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/manga_info_toggle"
|
||||
android:text="@string/merge"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"/>
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
|
@ -357,12 +357,14 @@
|
||||
android:textSize="12sp" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/smartsearch_replace_btn"
|
||||
style="@style/Widget.AppCompat.Button.Colored"
|
||||
android:id="@+id/merge_btn"
|
||||
style="@style/Widget.MaterialComponents.Button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:text="Migrate from current" />
|
||||
android:text="@string/merge"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
@ -488,17 +488,6 @@
|
||||
<string name="download_unread">Unread</string>
|
||||
<string name="confirm_delete_chapters">Are you sure you want to delete the selected chapters?</string>
|
||||
<string name="invalid_download_dir">Invalid download location</string>
|
||||
<string name="confirm_migration">Migrate %1$d%2$s manga?</string>
|
||||
<string name="confirm_copy">Copy %1$d%2$s manga?</string>
|
||||
<string name="skipping_x">(skipping %1$d)</string>
|
||||
<plurals name="manga_migrated">
|
||||
<item quantity="one">%d manga migrated</item>
|
||||
<item quantity="other">%d manga migrated</item>
|
||||
</plurals>
|
||||
<string name="error_fetching_migration">No chapters found, this manga cannot be used for
|
||||
migration</string>
|
||||
<string name="no_alternatives_found">No Alternatives Found</string>
|
||||
<string name="stop_migration">Stop migrating?</string>
|
||||
|
||||
<!-- Tracking Screen -->
|
||||
<string name="manga_tracking_tab">Tracking</string>
|
||||
@ -567,18 +556,6 @@
|
||||
<!-- History fragment -->
|
||||
<string name="recent_manga_time">Ch. %1$s - %2$s</string>
|
||||
|
||||
<!-- Source migration screen -->
|
||||
<string name="migration_info">Tap to select the source to migrate from</string>
|
||||
<string name="migration_dialog_what_to_include">Select data to include</string>
|
||||
<string name="migration_selection_prompt">Select a source to migrate from</string>
|
||||
<string name="select">Select</string>
|
||||
<string name="migrate">Migrate</string>
|
||||
<string name="migrate_">Migrate %1$s</string>
|
||||
<string name="copy">Copy</string>
|
||||
<string name="migrating">Migrating…</string>
|
||||
<string name="migration">Migration</string>
|
||||
<string name="latest_x">Latest: %1$s</string>
|
||||
|
||||
<!-- Downloads activity and service -->
|
||||
<string name="download_queue_error">Could not download chapters. You can try again in the downloads section</string>
|
||||
|
||||
@ -662,18 +639,50 @@
|
||||
<string name="channel_downloader">Downloader</string>
|
||||
<string name="channel_new_chapters">Chapter updates</string>
|
||||
<string name="channel_ext_updates">Extension updates</string>
|
||||
<string name="channel_backup_restore">Backup and restore</string>
|
||||
<string name="channel_backup_restore_progress">Progress</string>
|
||||
<string name="channel_backup_restore_complete">Complete</string>
|
||||
<string name="data_to_include_in_migration">Data to include in migration</string>
|
||||
<string name="search_parameter">Search parameter (e.g. language:english)</string>
|
||||
<string name="include_extra_search_parameter">Include extra search parameter when searching</string>
|
||||
|
||||
<!-- Migration -->
|
||||
<string name="source_migration">Source migration</string>
|
||||
<string name="migration">Migration</string>
|
||||
<string name="skip_pre_migration">Skip pre-migration</string>
|
||||
<string name="pre_migration_skip_toast">To show this screen again, go to Settings -> Library.</string>
|
||||
<string name="select_a_source_to_migrate_from">Select a source to migrate from</string>
|
||||
<string name="use_intelligent_search">Search title + keywords of title</string>
|
||||
<string name="migrating_to">migrating to</string>
|
||||
<string name="data_to_include_in_migration">Data to include in migration</string>
|
||||
<string name="search_parameter_eg">Search parameter (e.g. language:english)</string>
|
||||
<string name="include_extra_search_parameter">Include extra search parameter when searching</string>
|
||||
<string name="use_most_chapters">Use source with the most chapters (slower)</string>
|
||||
<string name="use_first_source">Use first source with alternative</string>
|
||||
<string name="skip_this_step_next_time">Skip this step next time</string>
|
||||
<string name="pre_migration_skip_toast">To show this screen again, go to Settings -> Library.</string>
|
||||
<string name="search_parameter">Search parameter (e.g. language:english)</string>
|
||||
<string name="include_extra_search_parameter">Include extra search parameter when searching</string>
|
||||
<string name="to_show_again_setting_library">To show this screen again, go to Settings -> Library.</string>
|
||||
<string name="latest_">Latest: %1$s</string>
|
||||
<string name="migrating_to">migrating to</string>
|
||||
<string name="dont_migrate">Don\'t migrate</string>
|
||||
<string name="search_manually">Search manually</string>
|
||||
<string name="migrate_now">Migrate now</string>
|
||||
<string name="copy_now">Copy now</string>
|
||||
<string name="select">Select</string>
|
||||
<string name="migrate">Migrate</string>
|
||||
<string name="migrate_">Migrate %1$s</string>
|
||||
<string name="copy_value">Copy</string>
|
||||
<string name="no_chapters_found_for_migration">No chapters found, this manga cannot be used for
|
||||
migration</string>
|
||||
<string name="no_alternatives_found">No Alternatives Found</string>
|
||||
<string name="stop_migrating">Stop migrating?</string>
|
||||
<plurals name="migrate_manga">
|
||||
<item quantity="one">Migrate %1$d%2$s manga?</item>
|
||||
<item quantity="other">Migrate %1$d%2$s manga?</item>
|
||||
</plurals>
|
||||
<plurals name="copy_manga">
|
||||
<item quantity="one">Copy %1$d%2$s manga?</item>
|
||||
<item quantity="other">Copy %1$d%2$s manga?</item>
|
||||
</plurals>
|
||||
<string name="skipping_">(skipping %1$d)</string>
|
||||
<plurals name="manga_migrated">
|
||||
<item quantity="one">%d manga migrated</item>
|
||||
<item quantity="other">%d manga migrated</item>
|
||||
</plurals>
|
||||
|
||||
<!-- EXH -->
|
||||
<string name="label_login">Login</string>
|
||||
@ -699,7 +708,8 @@
|
||||
<string name="eh_rounded_corner_9">Radius of 9</string>
|
||||
<string name="eh_rounded_corner_10">Radius of 10</string>
|
||||
<string name="eh_rounded_corners_desc">The level of radius that the corners are rounded to. Current value is: %s</string>
|
||||
|
||||
<string name="merge">Merge with current</string>
|
||||
<string name="eh_merge_with_another_source">Merge With Another</string>
|
||||
|
||||
|
||||
</resources>
|
||||
|
Loading…
x
Reference in New Issue
Block a user