Part 2 of Auto-Migration Done

(cherry picked from commit c4321e3adfff1bdfdcd8ba209dd20549348be217)
This commit is contained in:
jobobby04 2020-04-16 23:45:05 -04:00 committed by Jobobby04
parent f1472d4f8b
commit a6f0e7f9b9
16 changed files with 481 additions and 331 deletions

View File

@ -260,6 +260,14 @@ class PreferencesHelper(val context: Context) {
fun skipPreMigration() = flowPrefs.getBoolean(Keys.skipPreMigration, false) fun skipPreMigration() = flowPrefs.getBoolean(Keys.skipPreMigration, false)
fun migrationSources() = rxPrefs.getString("migrate_sources", "")
fun smartMigration() = rxPrefs.getBoolean("smart_migrate", false)
fun useSourceWithMost() = rxPrefs.getBoolean("use_source_with_most", false)
fun skipPreMigration() = rxPrefs.getBoolean(Keys.skipPreMigration, false)
fun upgradeFilters() { fun upgradeFilters() {
val filterDl = rxPrefs.getBoolean(Keys.filterDownloaded, false).getOrDefault() val filterDl = rxPrefs.getBoolean(Keys.filterDownloaded, false).getOrDefault()
val filterUn = rxPrefs.getBoolean(Keys.filterUnread, false).getOrDefault() val filterUn = rxPrefs.getBoolean(Keys.filterUnread, false).getOrDefault()

View File

@ -11,6 +11,8 @@ import android.view.MenuInflater
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.WindowInsets
import android.view.WindowManager
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.view.ActionMode import androidx.appcompat.view.ActionMode
import androidx.appcompat.widget.SearchView import androidx.appcompat.widget.SearchView
@ -36,8 +38,9 @@ import eu.kanade.tachiyomi.ui.main.offsetFabAppbarHeight
import eu.kanade.tachiyomi.ui.manga.MangaController import eu.kanade.tachiyomi.ui.manga.MangaController
import eu.kanade.tachiyomi.ui.migration.MigrationController import eu.kanade.tachiyomi.ui.migration.MigrationController
import eu.kanade.tachiyomi.ui.migration.MigrationInterface import eu.kanade.tachiyomi.ui.migration.MigrationInterface
import eu.kanade.tachiyomi.ui.migration.SearchController
import eu.kanade.tachiyomi.ui.migration.manga.design.MigrationDesignController import eu.kanade.tachiyomi.ui.migration.manga.design.MigrationDesignController
import eu.kanade.tachiyomi.ui.migration.manga.process.MigrationListController
import eu.kanade.tachiyomi.ui.migration.manga.process.MigrationProcedureConfig
import eu.kanade.tachiyomi.util.system.getResourceColor import eu.kanade.tachiyomi.util.system.getResourceColor
import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.system.toast
import eu.kanade.tachiyomi.util.view.inflate import eu.kanade.tachiyomi.util.view.inflate
@ -484,9 +487,15 @@ class LibraryController(
R.id.action_select_inverse -> selectInverseCategoryManga() R.id.action_select_inverse -> selectInverseCategoryManga()
R.id.action_migrate -> { R.id.action_migrate -> {
router.pushController( router.pushController(
MigrationDesignController.create( if (preferences.skipPreMigration().getOrDefault()) {
selectedMangas.mapNotNull { it.id } MigrationListController.create(
).withFadeTransaction()) MigrationProcedureConfig(
selectedMangas.mapNotNull { it.id }, null)
)
} else {
MigrationDesignController.create(selectedMangas.mapNotNull { it.id })
}
.withFadeTransaction())
destroyActionModeIfNeeded() destroyActionModeIfNeeded()
} }
else -> return false else -> return false
@ -503,18 +512,6 @@ class LibraryController(
return nextManga return nextManga
} }
private fun startMangaMigration() {
migratingMangas.clear()
migratingMangas.addAll(selectedMangas)
destroyActionModeIfNeeded()
val manga = migratingMangas.firstOrNull() ?: return
val searchController = SearchController(manga)
searchController.totalProgress = migratingMangas.size
searchController.targetController = this
router.pushController(searchController.withFadeTransaction())
migratingMangas.remove(manga)
}
override fun onDestroyActionMode(mode: ActionMode?) { override fun onDestroyActionMode(mode: ActionMode?) {
// Clear all the manga selections and notify child views. // Clear all the manga selections and notify child views.
selectedMangas.clear() selectedMangas.clear()
@ -788,3 +785,15 @@ class LibraryController(
const val REQUEST_IMAGE_OPEN = 101 const val REQUEST_IMAGE_OPEN = 101
} }
} }
object HeightTopWindowInsetsListener : View.OnApplyWindowInsetsListener {
override fun onApplyWindowInsets(v: View, insets: WindowInsets): WindowInsets {
val topInset = insets.systemWindowInsetTop
v.setPadding(0, topInset, 0, 0)
if (v.layoutParams.height != topInset) {
v.layoutParams.height = topInset
v.requestLayout()
}
return insets
}
}

View File

@ -0,0 +1,137 @@
package eu.kanade.tachiyomi.ui.migration.manga.design
import android.app.Activity
import android.content.res.Configuration
import android.os.Bundle
import android.widget.CompoundButton
import android.widget.LinearLayout
import android.widget.RadioButton
import android.widget.RadioGroup
import android.widget.Toast
import com.bluelinelabs.conductor.Controller
import com.f2prateek.rx.preferences.Preference
import com.google.android.material.bottomsheet.BottomSheetDialog
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.preference.getOrDefault
import eu.kanade.tachiyomi.ui.migration.MigrationFlags
import eu.kanade.tachiyomi.util.system.toast
import eu.kanade.tachiyomi.util.view.gone
import eu.kanade.tachiyomi.util.view.visible
import kotlinx.android.synthetic.main.migration_bottom_sheet.*
import kotlinx.android.synthetic.main.migration_bottom_sheet.extra_search_param
import kotlinx.android.synthetic.main.migration_bottom_sheet.extra_search_param_text
import kotlinx.android.synthetic.main.migration_bottom_sheet.mig_categories
import kotlinx.android.synthetic.main.migration_bottom_sheet.mig_chapters
import kotlinx.android.synthetic.main.migration_bottom_sheet.mig_tracking
import kotlinx.android.synthetic.main.migration_bottom_sheet.use_smart_search
import uy.kohesive.injekt.injectLazy
class MigrationBottomSheetDialog(
activity: Activity,
theme: Int,
private val listener:
StartMigrationListener
) :
BottomSheetDialog(activity,
theme) {
/**
* Preferences helper.
*/
private val preferences by injectLazy<PreferencesHelper>()
init {
// Use activity theme for this layout
val view = activity.layoutInflater.inflate(R.layout.migration_bottom_sheet, null)
// val scroll = NestedScrollView(context)
// scroll.addView(view)
setContentView(view)
if (activity.resources.configuration?.orientation == Configuration.ORIENTATION_LANDSCAPE)
sourceGroup.orientation = LinearLayout.HORIZONTAL
window?.setBackgroundDrawable(null)
}
/**
* Called when the sheet is created. It initializes the listeners and values of the preferences.
*/
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
initPreferences()
fab.setOnClickListener {
preferences.skipPreMigration().set(skip_step.isChecked)
listener.startMigration(
if (use_smart_search.isChecked && extra_search_param_text.text.isNotBlank())
extra_search_param_text.text.toString() else null)
dismiss()
}
}
/**
* Init general reader preferences.
*/
private fun initPreferences() {
val flags = preferences.migrateFlags().getOrDefault()
mig_chapters.isChecked = MigrationFlags.hasChapters(flags)
mig_categories.isChecked = MigrationFlags.hasCategories(flags)
mig_tracking.isChecked = MigrationFlags.hasTracks(flags)
mig_chapters.setOnCheckedChangeListener { _, _ -> setFlags() }
mig_categories.setOnCheckedChangeListener { _, _ -> setFlags() }
mig_tracking.setOnCheckedChangeListener { _, _ -> setFlags() }
use_smart_search.bindToPreference(preferences.smartMigration())
extra_search_param_text.gone()
extra_search_param.setOnCheckedChangeListener { _, isChecked ->
if (isChecked) {
extra_search_param_text.visible()
} else {
extra_search_param_text.gone()
}
}
sourceGroup.bindToPreference(preferences.useSourceWithMost())
skip_step.isChecked = preferences.skipPreMigration().getOrDefault()
skip_step.setOnCheckedChangeListener { _, isChecked ->
if (isChecked)
(listener as? Controller)?.activity?.toast(R.string.pre_migration_skip_toast,
Toast.LENGTH_LONG)
}
}
private fun setFlags() {
var flags = 0
if (mig_chapters.isChecked) flags = flags or MigrationFlags.CHAPTERS
if (mig_categories.isChecked) flags = flags or MigrationFlags.CATEGORIES
if (mig_categories.isChecked) flags = flags or MigrationFlags.TRACK
preferences.migrateFlags().set(flags)
}
/**
* Binds a checkbox or switch view with a boolean preference.
*/
private fun CompoundButton.bindToPreference(pref: Preference<Boolean>) {
isChecked = pref.getOrDefault()
setOnCheckedChangeListener { _, isChecked -> pref.set(isChecked) }
}
/**
* Binds a radio group with a boolean preference.
*/
private fun RadioGroup.bindToPreference(pref: Preference<Boolean>) {
(getChildAt(pref.getOrDefault().toInt()) as RadioButton).isChecked = true
setOnCheckedChangeListener { _, value ->
val index = indexOfChild(findViewById(value))
pref.set(index == 1)
}
}
private fun Boolean.toInt() = if (this) 1 else 0
}
interface StartMigrationListener {
fun startMigration(extraParam: String?)
}

View File

@ -4,7 +4,9 @@ import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.bottomsheet.BottomSheetBehavior
import eu.davidea.flexibleadapter.FlexibleAdapter import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
@ -13,27 +15,18 @@ import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.source.online.HttpSource
import eu.kanade.tachiyomi.ui.base.controller.BaseController import eu.kanade.tachiyomi.ui.base.controller.BaseController
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
import eu.kanade.tachiyomi.ui.migration.MigrationFlags
import eu.kanade.tachiyomi.ui.migration.manga.process.MigrationListController import eu.kanade.tachiyomi.ui.migration.manga.process.MigrationListController
import eu.kanade.tachiyomi.ui.migration.manga.process.MigrationProcedureConfig import eu.kanade.tachiyomi.ui.migration.manga.process.MigrationProcedureConfig
import eu.kanade.tachiyomi.util.view.gone import eu.kanade.tachiyomi.util.view.doOnApplyWindowInsets
import eu.kanade.tachiyomi.util.view.visible import eu.kanade.tachiyomi.util.view.marginBottom
import kotlinx.android.synthetic.main.migration_design_controller.begin_migration_btn import eu.kanade.tachiyomi.util.view.updateLayoutParams
import kotlinx.android.synthetic.main.migration_design_controller.extra_search_param import eu.kanade.tachiyomi.util.view.updatePaddingRelative
import kotlinx.android.synthetic.main.migration_design_controller.extra_search_param_desc import kotlinx.android.synthetic.main.migration_design_controller.fab
import kotlinx.android.synthetic.main.migration_design_controller.extra_search_param_text
import kotlinx.android.synthetic.main.migration_design_controller.fuzzy_search
import kotlinx.android.synthetic.main.migration_design_controller.mig_categories
import kotlinx.android.synthetic.main.migration_design_controller.mig_chapters
import kotlinx.android.synthetic.main.migration_design_controller.migration_mode
import kotlinx.android.synthetic.main.migration_design_controller.options_group
import kotlinx.android.synthetic.main.migration_design_controller.prioritize_chapter_count
import kotlinx.android.synthetic.main.migration_design_controller.recycler import kotlinx.android.synthetic.main.migration_design_controller.recycler
import kotlinx.android.synthetic.main.migration_design_controller.use_smart_search
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
class MigrationDesignController(bundle: Bundle? = null) : BaseController(bundle), FlexibleAdapter class MigrationDesignController(bundle: Bundle? = null) : BaseController(bundle), FlexibleAdapter
.OnItemClickListener { .OnItemClickListener, StartMigrationListener {
private val sourceManager: SourceManager by injectLazy() private val sourceManager: SourceManager by injectLazy()
private val prefs: PreferencesHelper by injectLazy() private val prefs: PreferencesHelper by injectLazy()
@ -53,7 +46,7 @@ class MigrationDesignController(bundle: Bundle? = null) : BaseController(bundle)
super.onViewCreated(view) super.onViewCreated(view)
val ourAdapter = adapter ?: MigrationSourceAdapter( val ourAdapter = adapter ?: MigrationSourceAdapter(
getEnabledSources().map { MigrationSourceItem(it, true) }, getEnabledSources().map { MigrationSourceItem(it, isEnabled(it.id.toString())) },
this this
) )
adapter = ourAdapter adapter = ourAdapter
@ -63,83 +56,42 @@ class MigrationDesignController(bundle: Bundle? = null) : BaseController(bundle)
ourAdapter.itemTouchHelperCallback = null // Reset adapter touch adapter to fix drag after rotation ourAdapter.itemTouchHelperCallback = null // Reset adapter touch adapter to fix drag after rotation
ourAdapter.isHandleDragEnabled = true ourAdapter.isHandleDragEnabled = true
migration_mode.setOnClickListener { val fabBaseMarginBottom = fab?.marginBottom ?: 0
prioritize_chapter_count.toggle() recycler.doOnApplyWindowInsets { v, insets, padding ->
}
fuzzy_search.setOnClickListener { fab?.updateLayoutParams<ViewGroup.MarginLayoutParams> {
use_smart_search.toggle() bottomMargin = fabBaseMarginBottom + insets.systemWindowInsetBottom
}
extra_search_param_desc.setOnClickListener {
extra_search_param.toggle()
}
prioritize_chapter_count.setOnCheckedChangeListener { _, b ->
updatePrioritizeChapterCount(b)
}
extra_search_param.setOnCheckedChangeListener { _, b ->
updateOptionsState()
}
updatePrioritizeChapterCount(prioritize_chapter_count.isChecked)
updateOptionsState()
begin_migration_btn.setOnClickListener {
if (!showingOptions) {
showingOptions = true
updateOptionsState()
return@setOnClickListener
} }
// offset the recycler by the fab's inset + some inset on top
v.updatePaddingRelative(bottom = padding.bottom + (fab?.marginBottom ?: 0) +
fabBaseMarginBottom + (fab?.height ?: 0))
}
var flags = 0 fab.setOnClickListener {
if (mig_chapters.isChecked) flags = flags or MigrationFlags.CHAPTERS val dialog = MigrationBottomSheetDialog(activity!!, R.style.SheetDialog, this)
if (mig_categories.isChecked) flags = flags or MigrationFlags.CATEGORIES dialog.show()
if (mig_categories.isChecked) flags = flags or MigrationFlags.TRACK val bottomSheet =
dialog.findViewById<FrameLayout>(com.google.android.material.R.id
.design_bottom_sheet)
val behavior: BottomSheetBehavior<*> = BottomSheetBehavior.from(bottomSheet!!)
behavior.state = BottomSheetBehavior.STATE_EXPANDED
behavior.skipCollapsed = true
}
}
router.replaceTopController( override fun startMigration(extraParam: String?) {
MigrationListController.create( val listOfSources = adapter?.items?.filter {
MigrationProcedureConfig( it.sourceEnabled
config.toList(), }?.joinToString("/") { it.source.id.toString() }
ourAdapter.items.filter { prefs.migrationSources().set(listOfSources)
it.sourceEnabled
}.map { it.source.id }, router.replaceTopController(
useSourceWithMostChapters = prioritize_chapter_count.isChecked, MigrationListController.create(
enableLenientSearch = use_smart_search.isChecked, MigrationProcedureConfig(
migrationFlags = flags, config.toList(),
extraSearchParams = if (extra_search_param.isChecked && extra_search_param_text.text.isNotBlank()) { extraSearchParams = extraParam
extra_search_param_text.text.toString() )
} else null
)
).withFadeTransaction()) ).withFadeTransaction())
}
}
fun updateOptionsState() {
if (showingOptions) {
begin_migration_btn.text = "Begin migration"
options_group.visible()
if (extra_search_param.isChecked) {
extra_search_param_text.visible()
} else {
extra_search_param_text.gone()
}
} else {
begin_migration_btn.text = "Next step"
options_group.gone()
extra_search_param_text.gone()
}
}
override fun handleBack(): Boolean {
if (showingOptions) {
showingOptions = false
updateOptionsState()
return true
}
return super.handleBack()
} }
override fun onSaveInstanceState(outState: Bundle) { override fun onSaveInstanceState(outState: Bundle) {
@ -153,14 +105,6 @@ class MigrationDesignController(bundle: Bundle? = null) : BaseController(bundle)
adapter?.onRestoreInstanceState(savedInstanceState) adapter?.onRestoreInstanceState(savedInstanceState)
} }
private fun updatePrioritizeChapterCount(migrationMode: Boolean) {
migration_mode.text = if (migrationMode) {
"Currently using the source with the most chapters and the above list to break ties (slow with many sources or smart search)"
} else {
"Currently using the first source in the list that has the manga"
}
}
override fun onItemClick(view: View, position: Int): Boolean { override fun onItemClick(view: View, position: Int): Boolean {
adapter?.getItem(position)?.let { adapter?.getItem(position)?.let {
it.sourceEnabled = !it.sourceEnabled it.sourceEnabled = !it.sourceEnabled
@ -176,13 +120,25 @@ class MigrationDesignController(bundle: Bundle? = null) : BaseController(bundle)
*/ */
private fun getEnabledSources(): List<HttpSource> { private fun getEnabledSources(): List<HttpSource> {
val languages = prefs.enabledLanguages().getOrDefault() val languages = prefs.enabledLanguages().getOrDefault()
val hiddenCatalogues = prefs.hiddenCatalogues().getOrDefault() val sourcesSaved = prefs.migrationSources().getOrDefault().split("/")
var sources = sourceManager.getCatalogueSources()
.filterIsInstance<HttpSource>()
.filter { it.lang in languages }
.sortedBy { "(${it.lang}) ${it.name}" }
sources =
sources.filter { isEnabled(it.id.toString()) }.sortedBy { sourcesSaved.indexOf(it.id
.toString())
} +
sources.filterNot { isEnabled(it.id.toString()) }
return sourceManager.getVisibleCatalogueSources() return sources
.filterIsInstance<HttpSource>() }
.filter { it.lang in languages }
.filterNot { it.id.toString() in hiddenCatalogues } fun isEnabled(id: String): Boolean {
.sortedBy { "(${it.lang}) ${it.name}" } val sourcesSaved = prefs.migrationSources().getOrDefault()
val hiddenCatalogues = prefs.hiddenCatalogues().getOrDefault()
return if (sourcesSaved.isEmpty()) id !in hiddenCatalogues
else sourcesSaved.split("/").contains(id)
} }
companion object { companion object {

View File

@ -6,7 +6,7 @@ import eu.kanade.tachiyomi.source.SourceManager
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
class MigrationSourceAdapter( class MigrationSourceAdapter(
val items: List<MigrationSourceItem>, var items: List<MigrationSourceItem>,
val controller: MigrationDesignController val controller: MigrationDesignController
) : FlexibleAdapter<MigrationSourceItem>( ) : FlexibleAdapter<MigrationSourceItem>(
items, items,
@ -32,6 +32,10 @@ class MigrationSourceAdapter(
super.onRestoreInstanceState(savedInstanceState) super.onRestoreInstanceState(savedInstanceState)
} }
fun updateItems() {
items = currentItems
}
companion object { companion object {
private const val SELECTED_SOURCES_KEY = "selected_sources" private const val SELECTED_SOURCES_KEY = "selected_sources"
} }

View File

@ -16,6 +16,8 @@ import com.afollestad.materialdialogs.MaterialDialog
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.preference.getOrDefault
import eu.kanade.tachiyomi.smartsearch.SmartSearchEngine import eu.kanade.tachiyomi.smartsearch.SmartSearchEngine
import eu.kanade.tachiyomi.source.CatalogueSource import eu.kanade.tachiyomi.source.CatalogueSource
import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.Source
@ -62,6 +64,7 @@ class MigrationListController(bundle: Bundle? = null) : BaseController(bundle),
val config: MigrationProcedureConfig? = args.getParcelable(CONFIG_EXTRA) val config: MigrationProcedureConfig? = args.getParcelable(CONFIG_EXTRA)
private val db: DatabaseHelper by injectLazy() private val db: DatabaseHelper by injectLazy()
private val preferences: PreferencesHelper by injectLazy()
private val sourceManager: SourceManager by injectLazy() private val sourceManager: SourceManager by injectLazy()
private val smartSearchEngine = SmartSearchEngine(coroutineContext, config?.extraSearchParams) private val smartSearchEngine = SmartSearchEngine(coroutineContext, config?.extraSearchParams)
@ -95,11 +98,8 @@ class MigrationListController(bundle: Bundle? = null) : BaseController(bundle),
recycler.adapter = adapter recycler.adapter = adapter
recycler.layoutManager = LinearLayoutManager(view.context) recycler.layoutManager = LinearLayoutManager(view.context)
// recycler.addItemDecoration(DividerItemDecoration(view.context, DividerItemDecoration
// .VERTICAL))
recycler.setHasFixedSize(true) recycler.setHasFixedSize(true)
recycler.setOnApplyWindowInsetsListener(RecyclerWindowInsetsListener) recycler.setOnApplyWindowInsetsListener(RecyclerWindowInsetsListener)
// recycler.isEnabled = false
adapter?.updateDataSet(newMigratingManga.map { it.toModal() }) adapter?.updateDataSet(newMigratingManga.map { it.toModal() })
@ -110,21 +110,6 @@ class MigrationListController(bundle: Bundle? = null) : BaseController(bundle),
} }
} }
/*fun nextMigration() {
adapter?.let { adapter ->
if(pager.currentItem >= adapter.count - 1) {
applicationContext?.toast("All migrations complete!")
router.popCurrentController()
} else {
adapter.migratingManga[pager.currentItem].migrationJob.cancel()
pager.setCurrentItem(pager.currentItem + 1, true)
launch(Dispatchers.Main) {
updateTitle()
}
}
}
}*/
fun migrationFailure() { fun migrationFailure() {
activity?.let { activity?.let {
MaterialDialog.Builder(it) MaterialDialog.Builder(it)
@ -136,8 +121,13 @@ class MigrationListController(bundle: Bundle? = null) : BaseController(bundle),
} }
suspend fun runMigrations(mangas: List<MigratingManga>) { suspend fun runMigrations(mangas: List<MigratingManga>) {
val sources = config?.targetSourceIds?.mapNotNull { sourceManager.get(it) as? CatalogueSource } ?: return 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 }
if (config == null) return
for (manga in mangas) { for (manga in mangas) {
if (!manga.searchResult.initialized && manga.migrationJob.isActive) { if (!manga.searchResult.initialized && manga.migrationJob.isActive) {
val mangaObj = manga.manga() val mangaObj = manga.manga()
@ -154,7 +144,7 @@ class MigrationListController(bundle: Bundle? = null) : BaseController(bundle),
val validSources = sources.filter { val validSources = sources.filter {
it.id != mangaSource.id it.id != mangaSource.id
} }
if (config.useSourceWithMostChapters) { if (useSourceWithMost) {
val sourceSemaphore = Semaphore(3) val sourceSemaphore = Semaphore(3)
val processedSources = AtomicInteger() val processedSources = AtomicInteger()
@ -162,7 +152,7 @@ class MigrationListController(bundle: Bundle? = null) : BaseController(bundle),
async { async {
sourceSemaphore.withPermit { sourceSemaphore.withPermit {
try { try {
val searchResult = if (config.enableLenientSearch) { val searchResult = if (useSmartSearch) {
smartSearchEngine.smartSearch(source, mangaObj.title) smartSearchEngine.smartSearch(source, mangaObj.title)
} else { } else {
smartSearchEngine.normalSearch(source, mangaObj.title) smartSearchEngine.normalSearch(source, mangaObj.title)
@ -192,7 +182,7 @@ class MigrationListController(bundle: Bundle? = null) : BaseController(bundle),
} else { } else {
validSources.forEachIndexed { index, source -> validSources.forEachIndexed { index, source ->
val searchResult = try { val searchResult = try {
val searchResult = if (config.enableLenientSearch) { val searchResult = if (useSmartSearch) {
smartSearchEngine.smartSearch(source, mangaObj.title) smartSearchEngine.smartSearch(source, mangaObj.title)
} else { } else {
smartSearchEngine.normalSearch(source, mangaObj.title) smartSearchEngine.normalSearch(source, mangaObj.title)

View File

@ -8,7 +8,6 @@ import com.google.gson.Gson
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.database.models.MangaCategory
import eu.kanade.tachiyomi.data.glide.GlideApp import eu.kanade.tachiyomi.data.glide.GlideApp
import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.SourceManager
@ -16,7 +15,6 @@ import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.all.MergedSource import eu.kanade.tachiyomi.source.online.all.MergedSource
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
import eu.kanade.tachiyomi.ui.manga.MangaController import eu.kanade.tachiyomi.ui.manga.MangaController
import eu.kanade.tachiyomi.ui.migration.MigrationFlags
import eu.kanade.tachiyomi.util.view.gone import eu.kanade.tachiyomi.util.view.gone
import eu.kanade.tachiyomi.util.view.inflate import eu.kanade.tachiyomi.util.view.inflate
import eu.kanade.tachiyomi.util.view.visible import eu.kanade.tachiyomi.util.view.visible
@ -123,7 +121,7 @@ class MigrationProcedureAdapter(
val config = controller.config ?: return val config = controller.config ?: return
// db.inTransaction { // db.inTransaction {
// Update chapters read // Update chapters read
if (MigrationFlags.hasChapters(controller.config.migrationFlags)) { /* if (MigrationFlags.hasChapters(controller.config.migrationFlags)) {
val prevMangaChapters = db.getChapters(prevManga).executeAsBlocking() val prevMangaChapters = db.getChapters(prevManga).executeAsBlocking()
val maxChapterRead = prevMangaChapters.filter { it.read } val maxChapterRead = prevMangaChapters.filter { it.read }
.maxBy { it.chapter_number }?.chapter_number .maxBy { it.chapter_number }?.chapter_number
@ -162,7 +160,7 @@ class MigrationProcedureAdapter(
// SearchPresenter#networkToLocalManga may have updated the manga title, so ensure db gets updated title // SearchPresenter#networkToLocalManga may have updated the manga title, so ensure db gets updated title
db.updateMangaTitle(manga).executeAsBlocking() db.updateMangaTitle(manga).executeAsBlocking()
// } //}*/
} }
fun View.setupView(tag: ViewTag, migratingManga: MigratingManga) { fun View.setupView(tag: ViewTag, migratingManga: MigratingManga) {

View File

@ -6,9 +6,5 @@ import kotlinx.android.parcel.Parcelize
@Parcelize @Parcelize
data class MigrationProcedureConfig( data class MigrationProcedureConfig(
var mangaIds: List<Long>, var mangaIds: List<Long>,
val targetSourceIds: List<Long>,
val useSourceWithMostChapters: Boolean,
val enableLenientSearch: Boolean,
val migrationFlags: Int,
val extraSearchParams: String? val extraSearchParams: String?
) : Parcelable ) : Parcelable

View File

@ -9,27 +9,16 @@ import com.afollestad.materialdialogs.MaterialDialog
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.smartsearch.SmartSearchEngine import eu.kanade.tachiyomi.smartsearch.SmartSearchEngine
import eu.kanade.tachiyomi.source.CatalogueSource
import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.ui.base.controller.BaseController import eu.kanade.tachiyomi.ui.base.controller.BaseController
import eu.kanade.tachiyomi.util.await
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.system.toast
import java.util.concurrent.atomic.AtomicInteger
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
import kotlinx.android.synthetic.main.migration_process.pager import kotlinx.android.synthetic.main.migration_process.pager
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.async
import kotlinx.coroutines.cancel import kotlinx.coroutines.cancel
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Semaphore
import kotlinx.coroutines.sync.withPermit
import kotlinx.coroutines.withContext
import rx.schedulers.Schedulers
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
// TODO Will probably implode if activity is fully destroyed // TODO Will probably implode if activity is fully destroyed
@ -121,7 +110,7 @@ class MigrationProcedureController(bundle: Bundle? = null) : BaseController(bund
} }
suspend fun runMigrations(mangas: List<MigratingManga>) { suspend fun runMigrations(mangas: List<MigratingManga>) {
val sources = config?.targetSourceIds?.mapNotNull { sourceManager.get(it) as? /* val sources = config?.targetSourceIds?.mapNotNull { sourceManager.get(it) as?
CatalogueSource } ?: return CatalogueSource } ?: return
for (manga in mangas) { for (manga in mangas) {
@ -229,7 +218,7 @@ class MigrationProcedureController(bundle: Bundle? = null) : BaseController(bund
manga.searchResult.initialize(result?.id) manga.searchResult.initialize(result?.id)
} }
} }*/
} }
override fun onDestroy() { override fun onDestroy() {

View File

@ -6,6 +6,8 @@ import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.database.models.MangaCategory import eu.kanade.tachiyomi.data.database.models.MangaCategory
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.preference.getOrDefault
import eu.kanade.tachiyomi.ui.migration.MigrationFlags import eu.kanade.tachiyomi.ui.migration.MigrationFlags
import eu.kanade.tachiyomi.util.lang.launchUI import eu.kanade.tachiyomi.util.lang.launchUI
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@ -21,6 +23,7 @@ class MigrationProcessAdapter(
private val db: DatabaseHelper by injectLazy() private val db: DatabaseHelper by injectLazy()
var items: List<MigrationProcessItem> = emptyList() var items: List<MigrationProcessItem> = emptyList()
val preferences: PreferencesHelper by injectLazy()
val menuItemListener: MigrationProcessInterface = controller val menuItemListener: MigrationProcessInterface = controller
@ -46,7 +49,7 @@ class MigrationProcessAdapter(
.searchResult.content != null }) .searchResult.content != null })
fun mangasSkipped() = (items.count { (!it.manga.searchResult.initialized || it.manga fun mangasSkipped() = (items.count { (!it.manga.searchResult.initialized || it.manga
.searchResult.content == null) && !it.manga.migrationJob.isActive }) .searchResult.content == null) })
suspend fun performMigrations(copy: Boolean) { suspend fun performMigrations(copy: Boolean) {
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
@ -95,9 +98,9 @@ class MigrationProcessAdapter(
replace: Boolean replace: Boolean
) { ) {
if (controller.config == null) return if (controller.config == null) return
// db.inTransaction { val flags = preferences.migrateFlags().getOrDefault()
// Update chapters read // Update chapters read
if (MigrationFlags.hasChapters(controller.config.migrationFlags)) { if (MigrationFlags.hasChapters(flags)) {
val prevMangaChapters = db.getChapters(prevManga).executeAsBlocking() val prevMangaChapters = db.getChapters(prevManga).executeAsBlocking()
val maxChapterRead = prevMangaChapters.filter { it.read } val maxChapterRead = prevMangaChapters.filter { it.read }
.maxBy { it.chapter_number }?.chapter_number .maxBy { it.chapter_number }?.chapter_number
@ -112,13 +115,13 @@ class MigrationProcessAdapter(
} }
} }
// Update categories // Update categories
if (MigrationFlags.hasCategories(controller.config.migrationFlags)) { if (MigrationFlags.hasCategories(flags)) {
val categories = db.getCategoriesForManga(prevManga).executeAsBlocking() val categories = db.getCategoriesForManga(prevManga).executeAsBlocking()
val mangaCategories = categories.map { MangaCategory.create(manga, it) } val mangaCategories = categories.map { MangaCategory.create(manga, it) }
db.setMangaCategories(mangaCategories, listOf(manga)) db.setMangaCategories(mangaCategories, listOf(manga))
} }
// Update track // Update track
if (MigrationFlags.hasTracks(controller.config.migrationFlags)) { if (MigrationFlags.hasTracks(flags)) {
val tracks = db.getTracks(prevManga).executeAsBlocking() val tracks = db.getTracks(prevManga).executeAsBlocking()
for (track in tracks) { for (track in tracks) {
track.id = null track.id = null

View File

@ -16,6 +16,7 @@ import eu.kanade.tachiyomi.util.preference.onChange
import eu.kanade.tachiyomi.util.preference.onClick import eu.kanade.tachiyomi.util.preference.onClick
import eu.kanade.tachiyomi.util.preference.preference import eu.kanade.tachiyomi.util.preference.preference
import eu.kanade.tachiyomi.util.preference.preferenceCategory import eu.kanade.tachiyomi.util.preference.preferenceCategory
import eu.kanade.tachiyomi.util.preference.summaryRes
import eu.kanade.tachiyomi.util.preference.switchPreference import eu.kanade.tachiyomi.util.preference.switchPreference
import eu.kanade.tachiyomi.util.preference.titleRes import eu.kanade.tachiyomi.util.preference.titleRes
import eu.kanade.tachiyomi.util.system.LocaleHelper import eu.kanade.tachiyomi.util.system.LocaleHelper
@ -191,6 +192,16 @@ class SettingsGeneralController : SettingsController() {
} }
} }
if (preferences.skipPreMigration().getOrDefault() || preferences.migrationSources()
.getOrDefault().isNotEmpty()) {
switchPreference {
key = Keys.skipPreMigration
titleRes = R.string.pref_skip_pre_migration
summaryRes = R.string.pref_skip_pre_migration_summary
defaultValue = false
}
}
// --> EXH // --> EXH
switchPreference { switchPreference {
key = Keys.eh_expandFilters key = Keys.eh_expandFilters

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<solid android:color="?attr/colorSurface" />
<corners android:radius="10dip" />
</shape>

View File

@ -0,0 +1,164 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/constraintLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/transparent"
android:orientation="vertical">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/constraintLayout2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:background="@drawable/dialog_rounded_background"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0">
<TextView
android:id="@+id/data_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:text="@string/data_to_include_in_migration"
android:textAppearance="@style/TextAppearance.Medium.Body2"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<CheckBox
android:id="@+id/mig_chapters"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:checked="true"
android:text="@string/chapters"
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/track"
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
android:id="@+id/options_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/options"
android:textAppearance="@style/TextAppearance.Medium.Body2"
app:layout_constraintStart_toStartOf="@+id/mig_chapters"
app:layout_constraintTop_toBottomOf="@+id/mig_chapters" />
<RadioGroup
android:id="@+id/sourceGroup"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:orientation="vertical"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/options_label"
app:layout_constraintTop_toBottomOf="@+id/options_label">
<RadioButton
android:id="@+id/radioButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="0dp"
android:paddingEnd="8dp"
android:text="@string/use_first_source" />
<RadioButton
android:id="@+id/radioButton2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/use_most_chapters" />
</RadioGroup>
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/use_smart_search"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="6dp"
android:layout_marginTop="16dp"
android:text="@string/use_intelligent_search"
app:layout_constraintEnd_toEndOf="@+id/sourceGroup"
app:layout_constraintStart_toStartOf="@+id/sourceGroup"
app:layout_constraintTop_toBottomOf="@+id/sourceGroup" />
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/extra_search_param"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/include_extra_search_parameter"
app:layout_constraintEnd_toEndOf="@+id/use_smart_search"
app:layout_constraintStart_toStartOf="@+id/use_smart_search"
app:layout_constraintTop_toBottomOf="@+id/use_smart_search" />
<EditText
android:id="@+id/extra_search_param_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:ems="10"
android:hint="@string/search_parameter"
android:importantForAutofill="no"
android:inputType="textPersonName"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="@+id/extra_search_param"
app:layout_constraintTop_toBottomOf="@+id/extra_search_param" />
<Switch
android:id="@+id/skip_step"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:text="@string/skip_this_step_next_time"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="@+id/extra_search_param"
app:layout_constraintStart_toStartOf="@+id/extra_search_param"
app:layout_constraintTop_toBottomOf="@+id/extra_search_param_text" />
</androidx.constraintlayout.widget.ConstraintLayout>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:src="@drawable/ic_arrow_forward_24dp"
app:layout_anchor="@id/constraintLayout"
app:layout_anchorGravity="bottom|end"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -2,6 +2,7 @@
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/frameLayout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:animateLayoutChanges="true"> android:animateLayoutChanges="true">
@ -10,174 +11,24 @@
android:id="@+id/recycler" android:id="@+id/recycler"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="0dp" android:layout_height="0dp"
android:layout_marginBottom="8dp" android:clipToPadding="false"
app:layout_constraintBottom_toTopOf="@+id/textView2" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
tools:listitem="@layout/migration_source_item"> tools:listitem="@layout/migration_source_item">
</androidx.recyclerview.widget.RecyclerView> </androidx.recyclerview.widget.RecyclerView>
<TextView <com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/textView2" android:id="@+id/fab"
android:layout_width="wrap_content" style="@style/Theme.Widget.FAB"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:text="@string/data_to_include_in_migration"
android:textAppearance="@style/TextAppearance.Medium.Body2"
app:layout_constraintBottom_toTopOf="@+id/mig_chapters"
app:layout_constraintStart_toStartOf="@+id/textView" />
<CheckBox
android:id="@+id/mig_chapters"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:checked="true"
android:text="@string/chapters"
app:layout_constraintBottom_toTopOf="@+id/textView"
app:layout_constraintStart_toStartOf="@+id/textView2" />
<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" />
<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/track"
app:layout_constraintBottom_toBottomOf="@+id/mig_categories"
app:layout_constraintStart_toEndOf="@+id/mig_categories" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginBottom="8dp"
android:text="@string/options"
android:textAppearance="@style/TextAppearance.Medium.Body2"
app:layout_constraintBottom_toTopOf="@+id/prioritize_chapter_count"
app:layout_constraintStart_toStartOf="parent" />
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/prioritize_chapter_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
app:layout_constraintStart_toStartOf="@+id/textView"
app:layout_constraintTop_toTopOf="@+id/migration_mode" />
<TextView
android:id="@+id/migration_mode"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:layout_marginBottom="8dp"
android:gravity="start|center_vertical"
android:clickable="true" android:clickable="true"
app:layout_constraintBottom_toTopOf="@+id/fuzzy_search" android:focusable="true"
app:layout_constraintEnd_toEndOf="parent" android:src="@drawable/ic_arrow_forward_24dp"
app:layout_constraintStart_toEndOf="@+id/prioritize_chapter_count" app:layout_anchor="@id/recycler"
android:focusable="true" /> app:layout_anchorGravity="bottom|right|end"
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/use_smart_search"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="@+id/textView"
app:layout_constraintTop_toTopOf="@+id/fuzzy_search" />
<TextView
android:id="@+id/fuzzy_search"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:layout_marginBottom="8dp"
android:gravity="start|center_vertical"
android:text="@string/use_intelligent_search"
android:clickable="true"
app:layout_constraintBottom_toTopOf="@+id/extra_search_param"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/prioritize_chapter_count"
android:focusable="true" />
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/extra_search_param"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="@+id/textView"
app:layout_constraintTop_toTopOf="@+id/extra_search_param_desc" />
<TextView
android:id="@+id/extra_search_param_desc"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:layout_marginBottom="8dp"
android:gravity="start|center_vertical"
android:text="@string/include_extra_search_parameter"
android:clickable="true"
app:layout_constraintBottom_toTopOf="@+id/extra_search_param_text"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/prioritize_chapter_count"
android:focusable="true" />
<EditText
android:id="@+id/extra_search_param_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:ems="10"
android:hint="@string/search_parameter"
android:inputType="textPersonName"
app:layout_constraintBottom_toTopOf="@+id/begin_migration_btn"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:importantForAutofill="no" />
<Button
android:id="@+id/begin_migration_btn"
style="@style/Theme.Widget.Button.FilledAccent"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:layout_marginBottom="8dp"
android:text="@string/begin_migration"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent" />
app:layout_constraintStart_toStartOf="parent" />
<androidx.constraintlayout.widget.Group
android:id="@+id/options_group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:constraint_referenced_ids="migration_mode,use_smart_search,fuzzy_search,action_copy_manga,extra_search_param_desc,mig_tracking,textView,mig_chapters,copy_manga_desc,textView2,prioritize_chapter_count,mig_categories,extra_search_param" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -192,7 +192,9 @@
<string name="wifi">Wi-Fi</string> <string name="wifi">Wi-Fi</string>
<string name="charging">Charging</string> <string name="charging">Charging</string>
<string name="pref_update_only_non_completed">Only update ongoing manga</string> <string name="pref_update_only_non_completed">Only update ongoing manga</string>
<string name="pref_skip_pre_migration">Skip pre-migration</string>
<string name="pref_skip_pre_migration_summary">Use last saved pre-migration preferences
and sources to mass migrate</string>
<string name="pref_category_library_categories">Categories</string> <string name="pref_category_library_categories">Categories</string>
<string name="default_category">Default category</string> <string name="default_category">Default category</string>
<string name="default_category_summary">Always ask</string> <string name="default_category_summary">Always ask</string>
@ -657,10 +659,12 @@
<string name="data_to_include_in_migration">Data to include in migration</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="search_parameter">Search parameter (e.g. language:english)</string>
<string name="include_extra_search_parameter">Include extra search parameter when searching</string> <string name="include_extra_search_parameter">Include extra search parameter when searching</string>
<string name="keep_old_manga">Keep old manga</string> <string name="use_intelligent_search">Search title + keywords of title</string>
<string name="use_intelligent_search">Use intelligent search algorithm</string>
<string name="begin_migration">Begin migration</string>
<string name="migrating_to">migrating to</string> <string name="migrating_to">migrating to</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 -> General.</string>
<!-- EXH --> <!-- EXH -->
<string name="label_login">Login</string> <string name="label_login">Login</string>

View File

@ -309,4 +309,25 @@
<style name="FilePickerAlertDialogTheme" parent="Theme.MaterialComponents.Light.Dialog.Alert" /> <style name="FilePickerAlertDialogTheme" parent="Theme.MaterialComponents.Light.Dialog.Alert" />
<style name="reader_settings_popup_animation">
<item name="android:windowEnterAnimation">@anim/enter_from_right</item>
<item name="android:windowExitAnimation">@anim/exit_to_right</item>
</style>
<style name="reader_brightness_popup_animation">
<item name="android:windowEnterAnimation">@anim/enter_from_left</item>
<item name="android:windowExitAnimation">@anim/exit_to_left</item>
</style>
<style name="SheetDialog" parent="Theme.Design.Light.BottomSheetDialog">
<!--<item name="android:windowCloseOnTouchOutside">false</item>-->
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:colorBackground"> @android:color/transparent</item>
<item name="android:backgroundDimEnabled">true</item>
<item name="android:backgroundDimAmount">0.3</item>
<item name="android:windowFrame">@null</item>
<item name="android:windowIsFloating">true</item>
</style>
</resources> </resources>