Rewrite migration, split it up into 2 controllers and reorganize the classes

Everything is under the hood, so on top only the back button was fixed in the selct manga screen
This commit is contained in:
Jobobby04 2020-05-26 17:04:07 -04:00
parent 75bddd5105
commit 04e8f0d77f
32 changed files with 352 additions and 294 deletions

View File

@ -5,6 +5,7 @@ import eu.kanade.tachiyomi.extension.ExtensionManager
import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga
import java.io.Serializable
import rx.Observable
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
@ -12,7 +13,7 @@ import uy.kohesive.injekt.api.get
/**
* A basic interface for creating a source. It could be an online source, a local source, etc...
*/
interface Source {
interface Source : Serializable {
/**
* Id for the source. Must be unique.

View File

@ -20,7 +20,7 @@ import eu.kanade.tachiyomi.ui.base.controller.RootController
import eu.kanade.tachiyomi.ui.base.controller.RxController
import eu.kanade.tachiyomi.ui.base.controller.TabbedController
import eu.kanade.tachiyomi.ui.browse.extension.ExtensionController
import eu.kanade.tachiyomi.ui.browse.migration.MigrationController
import eu.kanade.tachiyomi.ui.browse.migration.sources.MigrationSourcesController
import eu.kanade.tachiyomi.ui.browse.source.SourceController
import kotlinx.android.synthetic.main.main_activity.tabs
import uy.kohesive.injekt.injectLazy
@ -126,7 +126,7 @@ class BrowseController :
val controller: Controller = when (position) {
SOURCES_CONTROLLER -> SourceController()
EXTENSIONS_CONTROLLER -> ExtensionController()
MIGRATION_CONTROLLER -> MigrationController()
MIGRATION_CONTROLLER -> MigrationSourcesController()
else -> error("Wrong position $position")
}
router.setRoot(RouterTransaction.with(controller))

View File

@ -1,17 +0,0 @@
package eu.kanade.tachiyomi.ui.browse.migration
import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.davidea.flexibleadapter.items.IFlexible
class MangaAdapter(controller: MigrationController) :
FlexibleAdapter<IFlexible<*>>(null, controller) {
private var items: List<IFlexible<*>>? = null
override fun updateDataSet(items: MutableList<IFlexible<*>>?) {
if (this.items !== items) {
this.items = items
super.updateDataSet(items)
}
}
}

View File

@ -1,151 +0,0 @@
package eu.kanade.tachiyomi.ui.browse.migration
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.davidea.flexibleadapter.items.IFlexible
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.databinding.MigrationControllerBinding
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
import eu.kanade.tachiyomi.ui.browse.migration.manga.design.PreMigrationController
import eu.kanade.tachiyomi.util.lang.launchUI
import exh.util.RecyclerWindowInsetsListener
import exh.util.applyWindowInsetsForController
import exh.util.await
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import rx.schedulers.Schedulers
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
class MigrationController :
NucleusController<MigrationControllerBinding, MigrationPresenter>(),
FlexibleAdapter.OnItemClickListener,
SourceAdapter.OnAllClickListener,
MigrationInterface {
private var adapter: FlexibleAdapter<IFlexible<*>>? = null
private var title: String? = null
set(value) {
field = value
setTitle()
}
override fun createPresenter(): MigrationPresenter {
return MigrationPresenter()
}
override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
binding = MigrationControllerBinding.inflate(inflater)
return binding.root
}
fun searchController(manga: Manga): SearchController {
val controller = SearchController(manga)
controller.targetController = this
return controller
}
override fun onViewCreated(view: View) {
super.onViewCreated(view)
view.applyWindowInsetsForController()
adapter = FlexibleAdapter(null, this)
binding.recycler.layoutManager =
androidx.recyclerview.widget.LinearLayoutManager(view.context)
binding.recycler.adapter = adapter
binding.recycler.setOnApplyWindowInsetsListener(RecyclerWindowInsetsListener)
}
override fun onDestroyView(view: View) {
adapter = null
super.onDestroyView(view)
}
override fun getTitle(): String? {
return title
}
override fun handleBack(): Boolean {
return if (presenter.state.selectedSource != null) {
presenter.deselectSource()
true
} else {
super.handleBack()
}
}
fun render(state: ViewState) {
if (state.selectedSource == null) {
title = resources?.getString(R.string.source_migration)
if (adapter !is SourceAdapter) {
adapter = SourceAdapter(this)
binding.recycler.adapter = adapter
adapter?.fastScroller = binding.fastScroller
}
adapter?.updateDataSet(state.sourcesWithManga)
} else {
// val switching = title == resources?.getString(R.string.source_migration)
title = state.selectedSource.toString()
if (adapter !is MangaAdapter) {
adapter = MangaAdapter(this)
binding.recycler.adapter = adapter
adapter?.fastScroller = binding.fastScroller
}
adapter?.updateDataSet(state.mangaForSource, true)
/*if (switching) launchUI {
migration_recycler.alpha = 0f
migration_recycler.animate().alpha(1f).setStartDelay(100).setDuration(200).start()
}*/
}
}
override fun onItemClick(view: View?, position: Int): Boolean {
val item = adapter?.getItem(position) ?: return false
if (item is MangaItem) {
PreMigrationController.navigateToMigration(
Injekt.get<PreferencesHelper>().skipPreMigration().get(),
parentController!!.router,
listOf(item.manga.id!!)
)
} else if (item is SourceItem) {
presenter.setSelectedSource(item.source)
}
return false
}
override fun onAllClick(position: Int) {
val item = adapter?.getItem(position) as? SourceItem ?: return
launchUI {
val manga = Injekt.get<DatabaseHelper>().getFavoriteMangas().asRxSingle().await(
Schedulers.io()
)
val sourceMangas =
manga.asSequence().filter { it.source == item.source.id }.map { it.id!! }.toList()
withContext(Dispatchers.Main) {
PreMigrationController.navigateToMigration(
Injekt.get<PreferencesHelper>().skipPreMigration().get(),
parentController!!.router,
sourceMangas
)
}
}
}
override fun migrateManga(prevManga: Manga, manga: Manga, replace: Boolean): Manga? {
presenter.migrateManga(prevManga, manga, replace)
return null
}
}
interface MigrationInterface {
fun migrateManga(prevManga: Manga, manga: Manga, replace: Boolean): Manga?
}

View File

@ -6,7 +6,7 @@ import com.afollestad.materialdialogs.MaterialDialog
import com.bluelinelabs.conductor.Controller
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.ui.base.controller.DialogController
import eu.kanade.tachiyomi.ui.browse.migration.manga.process.MigrationListController
import eu.kanade.tachiyomi.ui.browse.migration.advanced.process.MigrationListController
class MigrationMangaDialog<T>(bundle: Bundle? = null) : DialogController(bundle)
where T : Controller {

View File

@ -1,10 +0,0 @@
package eu.kanade.tachiyomi.ui.browse.migration
import eu.kanade.tachiyomi.source.Source
data class ViewState(
val selectedSource: Source? = null,
val mangaForSource: List<MangaItem> = emptyList(),
val sourcesWithManga: List<SourceItem> = emptyList(),
val isReplacingManga: Boolean = false
)

View File

@ -1,4 +1,4 @@
package eu.kanade.tachiyomi.ui.browse.migration.manga.design
package eu.kanade.tachiyomi.ui.browse.migration.advanced.design
import android.app.Activity
import android.content.res.Configuration

View File

@ -1,4 +1,4 @@
package eu.kanade.tachiyomi.ui.browse.migration.manga.design
package eu.kanade.tachiyomi.ui.browse.migration.advanced.design
import android.os.Bundle
import eu.davidea.flexibleadapter.FlexibleAdapter

View File

@ -1,4 +1,4 @@
package eu.kanade.tachiyomi.ui.browse.migration.manga.design
package eu.kanade.tachiyomi.ui.browse.migration.advanced.design
import android.graphics.Paint.STRIKE_THRU_TEXT_FLAG
import android.view.View

View File

@ -1,4 +1,4 @@
package eu.kanade.tachiyomi.ui.browse.migration.manga.design
package eu.kanade.tachiyomi.ui.browse.migration.advanced.design
import android.os.Parcelable
import android.view.View

View File

@ -1,4 +1,4 @@
package eu.kanade.tachiyomi.ui.browse.migration.manga.design
package eu.kanade.tachiyomi.ui.browse.migration.advanced.design
import android.os.Bundle
import android.view.LayoutInflater
@ -20,8 +20,8 @@ import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.source.online.HttpSource
import eu.kanade.tachiyomi.ui.base.controller.BaseController
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
import eu.kanade.tachiyomi.ui.browse.migration.manga.process.MigrationListController
import eu.kanade.tachiyomi.ui.browse.migration.manga.process.MigrationProcedureConfig
import eu.kanade.tachiyomi.ui.browse.migration.advanced.process.MigrationListController
import eu.kanade.tachiyomi.ui.browse.migration.advanced.process.MigrationProcedureConfig
import exh.util.doOnApplyWindowInsets
import exh.util.marginBottom
import exh.util.updateLayoutParams

View File

@ -1,4 +1,4 @@
package eu.kanade.tachiyomi.ui.browse.migration.manga.process
package eu.kanade.tachiyomi.ui.browse.migration.advanced.process
import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.Manga

View File

@ -1,4 +1,4 @@
package eu.kanade.tachiyomi.ui.browse.migration.manga.process
package eu.kanade.tachiyomi.ui.browse.migration.advanced.process
import android.content.pm.ActivityInfo
import android.graphics.Color
@ -27,8 +27,8 @@ import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.ui.base.controller.BaseController
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
import eu.kanade.tachiyomi.ui.browse.migration.MigrationMangaDialog
import eu.kanade.tachiyomi.ui.browse.migration.SearchController
import eu.kanade.tachiyomi.ui.browse.migration.manga.design.PreMigrationController
import eu.kanade.tachiyomi.ui.browse.migration.advanced.design.PreMigrationController
import eu.kanade.tachiyomi.ui.browse.migration.search.SearchController
import eu.kanade.tachiyomi.ui.manga.MangaAllInOneController
import eu.kanade.tachiyomi.ui.manga.MangaController
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
@ -349,7 +349,11 @@ class MigrationListController(bundle: Bundle? = null) :
} else {
sources.filter { it.id != manga.source }
}
val searchController = SearchController(manga, validSources)
val searchController =
SearchController(
manga,
validSources
)
searchController.targetController = this@MigrationListController
router.pushController(searchController.withFadeTransaction())
}

View File

@ -1,4 +1,4 @@
package eu.kanade.tachiyomi.ui.browse.migration.manga.process
package eu.kanade.tachiyomi.ui.browse.migration.advanced.process
import android.os.Parcelable
import kotlinx.android.parcel.Parcelize

View File

@ -1,4 +1,4 @@
package eu.kanade.tachiyomi.ui.browse.migration.manga.process
package eu.kanade.tachiyomi.ui.browse.migration.advanced.process
import android.view.MenuItem
import eu.davidea.flexibleadapter.FlexibleAdapter

View File

@ -1,4 +1,4 @@
package eu.kanade.tachiyomi.ui.browse.migration.manga.process
package eu.kanade.tachiyomi.ui.browse.migration.advanced.process
import android.view.View
import android.widget.PopupMenu

View File

@ -1,4 +1,4 @@
package eu.kanade.tachiyomi.ui.browse.migration.manga.process
package eu.kanade.tachiyomi.ui.browse.migration.advanced.process
import android.view.View
import androidx.recyclerview.widget.RecyclerView

View File

@ -1,4 +1,4 @@
package eu.kanade.tachiyomi.ui.browse.migration
package eu.kanade.tachiyomi.ui.browse.migration.manga
import android.view.View
import com.bumptech.glide.load.engine.DiskCacheStrategy

View File

@ -1,5 +1,6 @@
package eu.kanade.tachiyomi.ui.browse.migration
package eu.kanade.tachiyomi.ui.browse.migration.manga
import android.os.Parcelable
import android.view.View
import androidx.recyclerview.widget.RecyclerView
import eu.davidea.flexibleadapter.FlexibleAdapter
@ -7,15 +8,20 @@ import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
import eu.davidea.flexibleadapter.items.IFlexible
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.models.Manga
import kotlinx.android.parcel.Parcelize
class MangaItem(val manga: Manga) : AbstractFlexibleItem<MangaHolder>() {
@Parcelize
class MangaItem(val manga: Manga) : AbstractFlexibleItem<MangaHolder>(), Parcelable {
override fun getLayoutRes(): Int {
return R.layout.source_list_item
}
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): MangaHolder {
return MangaHolder(view, adapter)
return MangaHolder(
view,
adapter
)
}
override fun bindViewHolder(

View File

@ -0,0 +1,95 @@
package eu.kanade.tachiyomi.ui.browse.migration.manga
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.LinearLayoutManager
import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.davidea.flexibleadapter.items.IFlexible
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.databinding.MigrationControllerBinding
import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
import eu.kanade.tachiyomi.ui.browse.migration.advanced.design.PreMigrationController
import eu.kanade.tachiyomi.ui.browse.source.SourceDividerItemDecoration
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
class MigrationMangaController :
NucleusController<MigrationControllerBinding, MigrationMangaPresenter>,
FlexibleAdapter.OnItemClickListener,
MigrationInterface {
private var adapter: FlexibleAdapter<IFlexible<*>>? = null
constructor(source: Source) : super(
Bundle().apply {
putSerializable(SOURCE_EXTRA, source)
}
)
@Suppress("unused")
constructor(bundle: Bundle) : this(bundle.getSerializable(SOURCE_EXTRA) as Source)
private val source: Source = args.getSerializable(SOURCE_EXTRA) as Source
override fun getTitle(): String? {
return source.name
}
override fun createPresenter(): MigrationMangaPresenter {
return MigrationMangaPresenter(
source.id
)
}
override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
binding = MigrationControllerBinding.inflate(inflater)
return binding.root
}
override fun onViewCreated(view: View) {
super.onViewCreated(view)
adapter = FlexibleAdapter<IFlexible<*>>(null, this)
binding.recycler.layoutManager = LinearLayoutManager(view.context)
binding.recycler.adapter = adapter
binding.recycler.addItemDecoration(SourceDividerItemDecoration(view.context))
adapter?.fastScroller = binding.fastScroller
}
override fun onDestroyView(view: View) {
adapter = null
super.onDestroyView(view)
}
fun setManga(manga: List<MangaItem>) {
adapter?.updateDataSet(manga)
}
override fun onItemClick(view: View, position: Int): Boolean {
val item = adapter?.getItem(position) as? MangaItem
?: return false
PreMigrationController.navigateToMigration(
Injekt.get<PreferencesHelper>().skipPreMigration().get(),
router,
listOf(item.manga.id!!)
)
return false
}
override fun migrateManga(prevManga: Manga, manga: Manga, replace: Boolean): Manga? {
presenter.migrateManga(prevManga, manga, replace)
return null
}
companion object {
const val SOURCE_EXTRA = "source_id_extra"
}
}
interface MigrationInterface {
fun migrateManga(prevManga: Manga, manga: Manga, replace: Boolean): Manga?
}

View File

@ -1,37 +1,26 @@
package eu.kanade.tachiyomi.ui.browse.migration
package eu.kanade.tachiyomi.ui.browse.migration.manga
import android.os.Bundle
import com.jakewharton.rxrelay.BehaviorRelay
import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.database.models.MangaCategory
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.source.LocalSource
import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
import eu.kanade.tachiyomi.ui.browse.migration.MigrationFlags
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
import eu.kanade.tachiyomi.util.lang.combineLatest
import exh.debug.DebugFunctions.sourceManager
import rx.Observable
import rx.android.schedulers.AndroidSchedulers
import rx.schedulers.Schedulers
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
class MigrationPresenter(
private val sourceManager: SourceManager = Injekt.get(),
private val db: DatabaseHelper = Injekt.get(),
private val preferences: PreferencesHelper = Injekt.get()
) : BasePresenter<MigrationController>() {
var state = ViewState()
private set(value) {
field = value
stateRelay.call(value)
}
private val stateRelay = BehaviorRelay.create(state)
class MigrationMangaPresenter(
private val sourceId: Long,
private val db: DatabaseHelper = Injekt.get()
) : BasePresenter<MigrationMangaController>() {
override fun onCreate(savedState: Bundle?) {
super.onCreate(savedState)
@ -39,54 +28,24 @@ class MigrationPresenter(
db.getFavoriteMangas()
.asRxObservable()
.observeOn(AndroidSchedulers.mainThread())
.doOnNext { state = state.copy(sourcesWithManga = findSourcesWithManga(it)) }
.combineLatest(
stateRelay.map { it.selectedSource }
.distinctUntilChanged()
) { library, source -> library to source }
.filter { (_, source) -> source != null }
.observeOn(Schedulers.io())
.map { (library, source) -> libraryToMigrationItem(library, source!!.id) }
.observeOn(AndroidSchedulers.mainThread())
.doOnNext { state = state.copy(mangaForSource = it) }
.subscribe()
stateRelay
// Render the view when any field other than isReplacingManga changes
.distinctUntilChanged { t1, t2 -> t1.isReplacingManga != t2.isReplacingManga }
.subscribeLatestCache(MigrationController::render)
.map { libraryToMigrationItem(it) }
.subscribeLatestCache(MigrationMangaController::setManga)
}
fun setSelectedSource(source: Source) {
state = state.copy(selectedSource = source, mangaForSource = emptyList())
}
fun deselectSource() {
state = state.copy(selectedSource = null, mangaForSource = emptyList())
}
private fun findSourcesWithManga(library: List<Manga>): List<SourceItem> {
val header = SelectionHeader()
return library.map { it.source }.toSet()
.mapNotNull { if (it != LocalSource.ID) sourceManager.getOrStub(it) else null }
.sortedBy { it.name }
.map { SourceItem(it, header) }
}
private fun libraryToMigrationItem(library: List<Manga>, sourceId: Long): List<MangaItem> {
return library.filter { it.source == sourceId }.map(::MangaItem)
private fun libraryToMigrationItem(library: List<Manga>): List<MangaItem> {
return library.filter { it.source == sourceId }
.sortedBy { it.title }
.map { MangaItem(it) }
}
fun migrateManga(prevManga: Manga, manga: Manga, replace: Boolean) {
val source = sourceManager.get(manga.source) ?: return
state = state.copy(isReplacingManga = true)
Observable.defer { source.fetchChapterList(manga) }.onErrorReturn { emptyList() }
.doOnNext { migrateMangaInternal(source, it, prevManga, manga, replace) }
.onErrorReturn { emptyList() }.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnUnsubscribe { state = state.copy(isReplacingManga = false) }.subscribe()
.subscribe()
}
private fun migrateMangaInternal(
@ -96,10 +55,19 @@ class MigrationPresenter(
manga: Manga,
replace: Boolean
) {
val flags = preferences.migrateFlags().get()
val migrateChapters = MigrationFlags.hasChapters(flags)
val migrateCategories = MigrationFlags.hasCategories(flags)
val migrateTracks = MigrationFlags.hasTracks(flags)
val flags = Injekt.get<PreferencesHelper>().migrateFlags().get()
val migrateChapters =
MigrationFlags.hasChapters(
flags
)
val migrateCategories =
MigrationFlags.hasCategories(
flags
)
val migrateTracks =
MigrationFlags.hasTracks(
flags
)
db.inTransaction {
// Update chapters read

View File

@ -1,4 +1,4 @@
package eu.kanade.tachiyomi.ui.browse.migration
package eu.kanade.tachiyomi.ui.browse.migration.search
import android.app.Dialog
import android.os.Bundle
@ -15,7 +15,9 @@ import eu.kanade.tachiyomi.source.CatalogueSource
import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.ui.base.controller.DialogController
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
import eu.kanade.tachiyomi.ui.browse.migration.manga.process.MigrationListController
import eu.kanade.tachiyomi.ui.browse.migration.MigrationFlags
import eu.kanade.tachiyomi.ui.browse.migration.advanced.process.MigrationListController
import eu.kanade.tachiyomi.ui.browse.migration.manga.MigrationInterface
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchController
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchPresenter
import kotlinx.coroutines.flow.filter
@ -50,7 +52,11 @@ class SearchController(
}
override fun createPresenter(): GlobalSearchPresenter {
return SearchPresenter(initialQuery, manga!!, sources = sources)
return SearchPresenter(
initialQuery,
manga!!,
sources = sources
)
}
override fun onSaveInstanceState(outState: Bundle) {
@ -85,7 +91,8 @@ class SearchController(
}*/
fun migrateManga() {
val target = targetController as? MigrationInterface ?: return
val target = targetController as? MigrationInterface
?: return
val manga = manga ?: return
val newManga = newManga ?: return
@ -94,7 +101,8 @@ class SearchController(
}
fun copyManga() {
val target = targetController as? MigrationInterface ?: return
val target = targetController as? MigrationInterface
?: return
val manga = manga ?: return
val newManga = newManga ?: return
@ -105,7 +113,10 @@ class SearchController(
private fun replaceWithNewSearchController(manga: Manga?) {
if (manga != null) {
// router.popCurrentController()
val searchController = SearchController(manga)
val searchController =
SearchController(
manga
)
searchController.targetController = targetController
searchController.progress = progress + 1
searchController.totalProgress = totalProgress
@ -123,7 +134,8 @@ class SearchController(
return
}
newManga = manga
val dialog = MigrationDialog()
val dialog =
MigrationDialog()
dialog.targetController = this
dialog.showDialog(router)
}
@ -140,7 +152,10 @@ class SearchController(
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
val prefValue = preferences.migrateFlags().get()
val preselected = MigrationFlags.getEnabledFlagsPositions(prefValue)
val preselected =
MigrationFlags.getEnabledFlagsPositions(
prefValue
)
return MaterialDialog(activity!!)
.message(R.string.data_to_include_in_migration)
@ -149,7 +164,10 @@ class SearchController(
{ resources?.getString(it) as CharSequence },
initialSelection = preselected.toIntArray()
) { _, positions, _ ->
val newValue = MigrationFlags.getFlagsFromPositions(positions.toTypedArray())
val newValue =
MigrationFlags.getFlagsFromPositions(
positions.toTypedArray()
)
preferences.migrateFlags().set(newValue)
}
.positiveButton(R.string.migrate) {

View File

@ -1,4 +1,4 @@
package eu.kanade.tachiyomi.ui.browse.migration
package eu.kanade.tachiyomi.ui.browse.migration.search
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.source.CatalogueSource

View File

@ -0,0 +1,95 @@
package eu.kanade.tachiyomi.ui.browse.migration.sources
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.LinearLayoutManager
import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.databinding.MigrationControllerBinding
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
import eu.kanade.tachiyomi.ui.browse.migration.advanced.design.PreMigrationController
import eu.kanade.tachiyomi.ui.browse.migration.manga.MigrationMangaController
import eu.kanade.tachiyomi.ui.browse.source.SourceDividerItemDecoration
import eu.kanade.tachiyomi.util.lang.launchUI
import exh.util.await
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import rx.schedulers.Schedulers
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
class MigrationSourcesController :
NucleusController<MigrationControllerBinding, MigrationSourcesPresenter>(),
FlexibleAdapter.OnItemClickListener,
SourceAdapter.OnAllClickListener {
private var adapter: SourceAdapter? = null
override fun createPresenter(): MigrationSourcesPresenter {
return MigrationSourcesPresenter()
}
override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
binding = MigrationControllerBinding.inflate(inflater)
return binding.root
}
override fun onViewCreated(view: View) {
super.onViewCreated(view)
adapter =
SourceAdapter(this)
binding.recycler.layoutManager = LinearLayoutManager(view.context)
binding.recycler.adapter = adapter
binding.recycler.addItemDecoration(SourceDividerItemDecoration(view.context))
adapter?.fastScroller = binding.fastScroller
}
override fun onDestroyView(view: View) {
adapter = null
super.onDestroyView(view)
}
fun setSources(sourcesWithManga: List<SourceItem>) {
adapter?.updateDataSet(sourcesWithManga)
}
override fun getTitle(): String? {
return resources?.getString(R.string.source_migration)
}
override fun onItemClick(view: View?, position: Int): Boolean {
val item = adapter?.getItem(position) as? SourceItem
?: return false
val controller =
MigrationMangaController(
item.source
)
parentController!!.router.pushController(controller.withFadeTransaction())
return false
}
override fun onAllClick(position: Int) {
val item = adapter?.getItem(position) as? SourceItem
?: return
launchUI {
val manga = Injekt.get<DatabaseHelper>().getFavoriteMangas().asRxSingle().await(
Schedulers.io()
)
val sourceMangas =
manga.asSequence().filter { it.source == item.source.id }.map { it.id!! }.toList()
withContext(Dispatchers.Main) {
PreMigrationController.navigateToMigration(
Injekt.get<PreferencesHelper>().skipPreMigration().get(),
parentController!!.router,
sourceMangas
)
}
}
}
}

View File

@ -0,0 +1,49 @@
package eu.kanade.tachiyomi.ui.browse.migration.sources
import android.os.Bundle
import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.source.LocalSource
import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
import eu.kanade.tachiyomi.ui.browse.migration.manga.MangaItem
import exh.MERGED_SOURCE_ID
import rx.android.schedulers.AndroidSchedulers
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
class MigrationSourcesPresenter(
private val sourceManager: SourceManager = Injekt.get(),
private val db: DatabaseHelper = Injekt.get(),
private val preferences: PreferencesHelper = Injekt.get()
) : BasePresenter<MigrationSourcesController>() {
override fun onCreate(savedState: Bundle?) {
super.onCreate(savedState)
db.getFavoriteMangas()
.asRxObservable()
.observeOn(AndroidSchedulers.mainThread())
.map { findSourcesWithManga(it) }
.subscribeLatestCache(MigrationSourcesController::setSources)
}
private fun findSourcesWithManga(library: List<Manga>): List<SourceItem> {
val header =
SelectionHeader()
return library.map { it.source }.toSet()
.mapNotNull { if (it != LocalSource.ID && it != MERGED_SOURCE_ID) sourceManager.getOrStub(it) else null }
.sortedBy { it.name }
.map {
SourceItem(
it,
header
)
}
}
private fun libraryToMigrationItem(library: List<Manga>, sourceId: Long): List<MangaItem> {
return library.filter { it.source == sourceId }.map(::MangaItem)
}
}

View File

@ -1,4 +1,4 @@
package eu.kanade.tachiyomi.ui.browse.migration
package eu.kanade.tachiyomi.ui.browse.migration.sources
import android.view.View
import androidx.recyclerview.widget.RecyclerView
@ -25,7 +25,10 @@ class SelectionHeader : AbstractHeaderItem<SelectionHeader.Holder>() {
* Creates a new view holder for this item.
*/
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): Holder {
return Holder(view, adapter)
return Holder(
view,
adapter
)
}
/**

View File

@ -1,4 +1,4 @@
package eu.kanade.tachiyomi.ui.browse.migration
package eu.kanade.tachiyomi.ui.browse.migration.sources
import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.davidea.flexibleadapter.items.IFlexible
@ -8,15 +8,13 @@ import eu.kanade.tachiyomi.util.system.getResourceColor
/**
* Adapter that holds the catalogue cards.
*
* @param controller instance of [MigrationController].
* @param controller instance of [MigrationSourcesController].
*/
class SourceAdapter(val controller: MigrationController) :
class SourceAdapter(val controller: MigrationSourcesController) :
FlexibleAdapter<IFlexible<*>>(null, controller, true) {
val cardBackground = controller.activity!!.getResourceColor(R.attr.colorSurface)
private var items: List<IFlexible<*>>? = null
init {
setDisplayHeadersAtStartUp(true)
}
@ -32,11 +30,4 @@ class SourceAdapter(val controller: MigrationController) :
interface OnAllClickListener {
fun onAllClick(position: Int)
}
override fun updateDataSet(items: MutableList<IFlexible<*>>?) {
if (this.items !== items) {
this.items = items
super.updateDataSet(items)
}
}
}

View File

@ -1,4 +1,4 @@
package eu.kanade.tachiyomi.ui.browse.migration
package eu.kanade.tachiyomi.ui.browse.migration.sources
import android.view.View
import eu.kanade.tachiyomi.source.icon

View File

@ -1,4 +1,4 @@
package eu.kanade.tachiyomi.ui.browse.migration
package eu.kanade.tachiyomi.ui.browse.migration.sources
import android.view.View
import androidx.recyclerview.widget.RecyclerView
@ -14,7 +14,7 @@ import eu.kanade.tachiyomi.source.Source
* @param source Instance of [Source] containing source information.
* @param header The header for this item.
*/
data class SourceItem(val source: Source, val header: SelectionHeader? = null) :
data class SourceItem(val source: Source, val header: SelectionHeader) :
AbstractSectionableItem<SourceHolder, SelectionHeader>(header) {
/**
@ -28,7 +28,10 @@ data class SourceItem(val source: Source, val header: SelectionHeader? = null) :
* Creates a new view holder for this item.
*/
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): SourceHolder {
return SourceHolder(view, adapter as SourceAdapter)
return SourceHolder(
view,
adapter as SourceAdapter
)
}
/**

View File

@ -34,8 +34,8 @@ import eu.kanade.tachiyomi.ui.base.controller.NucleusController
import eu.kanade.tachiyomi.ui.base.controller.RootController
import eu.kanade.tachiyomi.ui.base.controller.TabbedController
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
import eu.kanade.tachiyomi.ui.browse.migration.MigrationController
import eu.kanade.tachiyomi.ui.browse.migration.manga.design.PreMigrationController
import eu.kanade.tachiyomi.ui.browse.migration.advanced.design.PreMigrationController
import eu.kanade.tachiyomi.ui.browse.migration.sources.MigrationSourcesController
import eu.kanade.tachiyomi.ui.main.MainActivity
import eu.kanade.tachiyomi.ui.main.offsetAppbarHeight
import eu.kanade.tachiyomi.ui.manga.MangaAllInOneController
@ -429,7 +429,10 @@ class LibraryController(
}
}
R.id.action_source_migration -> {
router.pushController(MigrationController().withFadeTransaction())
router.pushController(
MigrationSourcesController()
.withFadeTransaction()
)
}
// --> EXH
R.id.action_sync_favorites -> {

View File

@ -32,7 +32,7 @@ import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.source.online.HttpSource
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
import eu.kanade.tachiyomi.ui.browse.migration.manga.design.PreMigrationController
import eu.kanade.tachiyomi.ui.browse.migration.advanced.design.PreMigrationController
import eu.kanade.tachiyomi.ui.browse.source.SourceController
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceController
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchController

View File

@ -24,7 +24,7 @@ import eu.kanade.tachiyomi.source.online.HttpSource
import eu.kanade.tachiyomi.source.online.all.MergedSource
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
import eu.kanade.tachiyomi.ui.browse.migration.manga.design.PreMigrationController
import eu.kanade.tachiyomi.ui.browse.migration.advanced.design.PreMigrationController
import eu.kanade.tachiyomi.ui.browse.source.SourceController
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceController
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchController