mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-11-10 14:27:47 +01:00
Split up MigrationController
This commit is contained in:
parent
3c4bc17065
commit
af1935d2e4
13 changed files with 207 additions and 235 deletions
|
@ -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.
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -1,110 +0,0 @@
|
|||
package eu.kanade.tachiyomi.ui.browse.migration
|
||||
|
||||
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.R
|
||||
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.manga.MangaAdapter
|
||||
import eu.kanade.tachiyomi.ui.browse.migration.manga.MangaItem
|
||||
import eu.kanade.tachiyomi.ui.browse.migration.search.SearchController
|
||||
import eu.kanade.tachiyomi.ui.browse.migration.sources.SourceAdapter
|
||||
import eu.kanade.tachiyomi.ui.browse.migration.sources.SourceItem
|
||||
import eu.kanade.tachiyomi.ui.browse.source.SourceDividerItemDecoration
|
||||
|
||||
class MigrationController :
|
||||
NucleusController<MigrationControllerBinding, MigrationPresenter>(),
|
||||
FlexibleAdapter.OnItemClickListener {
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View) {
|
||||
super.onViewCreated(view)
|
||||
|
||||
adapter = FlexibleAdapter(null, this)
|
||||
binding.recycler.layoutManager = LinearLayoutManager(view.context)
|
||||
binding.recycler.adapter = adapter
|
||||
binding.recycler.addItemDecoration(SourceDividerItemDecoration(view.context))
|
||||
}
|
||||
|
||||
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.label_migration)
|
||||
if (adapter !is SourceAdapter) {
|
||||
adapter =
|
||||
SourceAdapter(
|
||||
this
|
||||
)
|
||||
binding.recycler.adapter = adapter
|
||||
adapter?.fastScroller = binding.fastScroller
|
||||
}
|
||||
adapter?.updateDataSet(state.sourcesWithManga)
|
||||
} else {
|
||||
title = state.selectedSource.toString()
|
||||
if (adapter !is MangaAdapter) {
|
||||
adapter =
|
||||
MangaAdapter(
|
||||
this
|
||||
)
|
||||
binding.recycler.adapter = adapter
|
||||
adapter?.fastScroller = binding.fastScroller
|
||||
}
|
||||
adapter?.updateDataSet(state.mangaForSource)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onItemClick(view: View, position: Int): Boolean {
|
||||
val item = adapter?.getItem(position) ?: return false
|
||||
|
||||
if (item is MangaItem) {
|
||||
val controller =
|
||||
SearchController(
|
||||
item.manga
|
||||
)
|
||||
controller.targetController = this
|
||||
|
||||
parentController!!.router.pushController(controller.withFadeTransaction())
|
||||
} else if (item is SourceItem) {
|
||||
presenter.setSelectedSource(item.source)
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
package eu.kanade.tachiyomi.ui.browse.migration
|
||||
|
||||
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.source.LocalSource
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
||||
import eu.kanade.tachiyomi.ui.browse.migration.manga.MangaItem
|
||||
import eu.kanade.tachiyomi.ui.browse.migration.sources.SelectionHeader
|
||||
import eu.kanade.tachiyomi.ui.browse.migration.sources.SourceItem
|
||||
import eu.kanade.tachiyomi.util.lang.combineLatest
|
||||
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()
|
||||
) : BasePresenter<MigrationController>() {
|
||||
|
||||
var state = ViewState()
|
||||
private set(value) {
|
||||
field = value
|
||||
stateRelay.call(value)
|
||||
}
|
||||
|
||||
private val stateRelay = BehaviorRelay.create(state)
|
||||
|
||||
override fun onCreate(savedState: Bundle?) {
|
||||
super.onCreate(savedState)
|
||||
|
||||
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()
|
||||
|
||||
// Render the view when any field changes
|
||||
stateRelay.subscribeLatestCache(MigrationController::render)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
package eu.kanade.tachiyomi.ui.browse.migration
|
||||
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.ui.browse.migration.manga.MangaItem
|
||||
import eu.kanade.tachiyomi.ui.browse.migration.sources.SourceItem
|
||||
|
||||
data class ViewState(
|
||||
val selectedSource: Source? = null,
|
||||
val mangaForSource: List<MangaItem> = emptyList(),
|
||||
val sourcesWithManga: List<SourceItem> = emptyList()
|
||||
)
|
|
@ -1,18 +0,0 @@
|
|||
package eu.kanade.tachiyomi.ui.browse.migration.manga
|
||||
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.items.IFlexible
|
||||
import eu.kanade.tachiyomi.ui.browse.migration.MigrationController
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
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,8 +8,10 @@ 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
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
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.databinding.MigrationControllerBinding
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
|
||||
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
||||
import eu.kanade.tachiyomi.ui.browse.migration.search.SearchController
|
||||
import eu.kanade.tachiyomi.ui.browse.source.SourceDividerItemDecoration
|
||||
|
||||
class MigrationMangaController :
|
||||
NucleusController<MigrationControllerBinding, MigrationMangaPresenter>,
|
||||
FlexibleAdapter.OnItemClickListener {
|
||||
|
||||
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
|
||||
val controller = SearchController(item.manga)
|
||||
router.pushController(controller.withFadeTransaction())
|
||||
return false
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val SOURCE_EXTRA = "source_id_extra"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package eu.kanade.tachiyomi.ui.browse.migration.manga
|
||||
|
||||
import android.os.Bundle
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
class MigrationMangaPresenter(
|
||||
private val sourceId: Long,
|
||||
private val db: DatabaseHelper = Injekt.get()
|
||||
) : BasePresenter<MigrationMangaController>() {
|
||||
|
||||
override fun onCreate(savedState: Bundle?) {
|
||||
super.onCreate(savedState)
|
||||
|
||||
db.getFavoriteMangas()
|
||||
.asRxObservable()
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.map { libraryToMigrationItem(it) }
|
||||
.subscribeLatestCache(MigrationMangaController::setManga)
|
||||
}
|
||||
|
||||
private fun libraryToMigrationItem(library: List<Manga>): List<MangaItem> {
|
||||
return library.filter { it.source == sourceId }
|
||||
.sortedBy { it.title }
|
||||
.map { MangaItem(it) }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
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.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.manga.MigrationMangaController
|
||||
import eu.kanade.tachiyomi.ui.browse.source.SourceDividerItemDecoration
|
||||
|
||||
class MigrationSourcesController :
|
||||
NucleusController<MigrationControllerBinding, MigrationSourcesPresenter>(),
|
||||
FlexibleAdapter.OnItemClickListener {
|
||||
|
||||
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 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
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
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.source.LocalSource
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
||||
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()
|
||||
) : 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) sourceManager.getOrStub(it) else null }
|
||||
.sortedBy { it.name }
|
||||
.map { SourceItem(it, header) }
|
||||
}
|
||||
}
|
|
@ -1,9 +1,9 @@
|
|||
package eu.kanade.tachiyomi.ui.browse.migration.sources
|
||||
|
||||
import com.bluelinelabs.conductor.Controller
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.items.IFlexible
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.browse.migration.MigrationController
|
||||
import eu.kanade.tachiyomi.util.system.getResourceColor
|
||||
|
||||
/**
|
||||
|
@ -11,21 +11,12 @@ import eu.kanade.tachiyomi.util.system.getResourceColor
|
|||
*
|
||||
* @param controller instance of [MigrationController].
|
||||
*/
|
||||
class SourceAdapter(val controller: MigrationController) :
|
||||
class SourceAdapter(val controller: Controller) :
|
||||
FlexibleAdapter<IFlexible<*>>(null, controller, true) {
|
||||
|
||||
val cardBackground = controller.activity!!.getResourceColor(R.attr.colorSurface)
|
||||
|
||||
private var items: List<IFlexible<*>>? = null
|
||||
|
||||
init {
|
||||
setDisplayHeadersAtStartUp(true)
|
||||
}
|
||||
|
||||
override fun updateDataSet(items: MutableList<IFlexible<*>>?) {
|
||||
if (this.items !== items) {
|
||||
this.items = items
|
||||
super.updateDataSet(items)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in a new issue