mirror of
https://github.com/aniyomiorg/aniyomi.git
synced 2024-11-25 14:19:27 +03:00
add migrating anime from the browse tab
This commit is contained in:
parent
1e0d9ce737
commit
bbd4b3766e
9 changed files with 306 additions and 7 deletions
|
@ -0,0 +1,14 @@
|
|||
package eu.kanade.tachiyomi.ui.browse.migration.anime
|
||||
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.items.IFlexible
|
||||
|
||||
class MigrationAnimeAdapter(controller: MigrationAnimeController) :
|
||||
FlexibleAdapter<IFlexible<*>>(null, controller, true) {
|
||||
|
||||
val coverClickListener: OnCoverClickListener = controller
|
||||
|
||||
interface OnCoverClickListener {
|
||||
fun onCoverClick(position: Int)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
package eu.kanade.tachiyomi.ui.browse.migration.anime
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import dev.chrisbanes.insetter.applyInsetter
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.kanade.tachiyomi.databinding.MigrationMangaControllerBinding
|
||||
import eu.kanade.tachiyomi.ui.anime.AnimeController
|
||||
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
|
||||
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
||||
import eu.kanade.tachiyomi.ui.browse.migration.search.AnimeSearchController
|
||||
|
||||
class MigrationAnimeController :
|
||||
NucleusController<MigrationMangaControllerBinding, MigrationAnimePresenter>,
|
||||
FlexibleAdapter.OnItemClickListener,
|
||||
MigrationAnimeAdapter.OnCoverClickListener {
|
||||
|
||||
private var adapter: MigrationAnimeAdapter? = null
|
||||
|
||||
constructor(sourceId: Long, sourceName: String?) : super(
|
||||
bundleOf(
|
||||
SOURCE_ID_EXTRA to sourceId,
|
||||
SOURCE_NAME_EXTRA to sourceName
|
||||
)
|
||||
)
|
||||
|
||||
@Suppress("unused")
|
||||
constructor(bundle: Bundle) : this(
|
||||
bundle.getLong(SOURCE_ID_EXTRA),
|
||||
bundle.getString(SOURCE_NAME_EXTRA)
|
||||
)
|
||||
|
||||
private val sourceId: Long = args.getLong(SOURCE_ID_EXTRA)
|
||||
private val sourceName: String? = args.getString(SOURCE_NAME_EXTRA)
|
||||
|
||||
override fun getTitle(): String? {
|
||||
return sourceName
|
||||
}
|
||||
|
||||
override fun createPresenter(): MigrationAnimePresenter {
|
||||
return MigrationAnimePresenter(sourceId)
|
||||
}
|
||||
|
||||
override fun createBinding(inflater: LayoutInflater) = MigrationMangaControllerBinding.inflate(inflater)
|
||||
|
||||
override fun onViewCreated(view: View) {
|
||||
super.onViewCreated(view)
|
||||
|
||||
binding.recycler.applyInsetter {
|
||||
type(navigationBars = true) {
|
||||
padding()
|
||||
}
|
||||
}
|
||||
|
||||
adapter = MigrationAnimeAdapter(this)
|
||||
binding.recycler.layoutManager = LinearLayoutManager(view.context)
|
||||
binding.recycler.adapter = adapter
|
||||
adapter?.fastScroller = binding.fastScroller
|
||||
}
|
||||
|
||||
override fun onDestroyView(view: View) {
|
||||
adapter = null
|
||||
super.onDestroyView(view)
|
||||
}
|
||||
|
||||
fun setAnime(anime: List<MigrationAnimeItem>) {
|
||||
adapter?.updateDataSet(anime)
|
||||
}
|
||||
|
||||
override fun onItemClick(view: View, position: Int): Boolean {
|
||||
val item = adapter?.getItem(position) as? MigrationAnimeItem ?: return false
|
||||
val controller = AnimeSearchController(item.anime)
|
||||
router.pushController(controller.withFadeTransaction())
|
||||
return false
|
||||
}
|
||||
|
||||
override fun onCoverClick(position: Int) {
|
||||
val animeItem = adapter?.getItem(position) as? MigrationAnimeItem ?: return
|
||||
router.pushController(AnimeController(animeItem.anime).withFadeTransaction())
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val SOURCE_ID_EXTRA = "source_id_extra"
|
||||
const val SOURCE_NAME_EXTRA = "source_name_extra"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package eu.kanade.tachiyomi.ui.browse.migration.anime
|
||||
|
||||
import android.view.View
|
||||
import coil.clear
|
||||
import coil.loadAny
|
||||
import coil.transform.RoundedCornersTransformation
|
||||
import eu.davidea.viewholders.FlexibleViewHolder
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.databinding.SourceListItemBinding
|
||||
|
||||
class MigrationAnimeHolder(
|
||||
view: View,
|
||||
private val adapter: MigrationAnimeAdapter
|
||||
) : FlexibleViewHolder(view, adapter) {
|
||||
|
||||
private val binding = SourceListItemBinding.bind(view)
|
||||
|
||||
init {
|
||||
binding.thumbnail.setOnClickListener {
|
||||
adapter.coverClickListener.onCoverClick(bindingAdapterPosition)
|
||||
}
|
||||
}
|
||||
|
||||
fun bind(item: MigrationAnimeItem) {
|
||||
binding.title.text = item.anime.title
|
||||
|
||||
// Update the cover.
|
||||
val radius = itemView.context.resources.getDimension(R.dimen.card_radius)
|
||||
binding.thumbnail.clear()
|
||||
binding.thumbnail.loadAny(item.anime.thumbnail_url) {
|
||||
transformations(RoundedCornersTransformation(radius))
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package eu.kanade.tachiyomi.ui.browse.migration.anime
|
||||
|
||||
import android.view.View
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||
import eu.davidea.flexibleadapter.items.IFlexible
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Anime
|
||||
|
||||
class MigrationAnimeItem(val anime: Anime) : AbstractFlexibleItem<MigrationAnimeHolder>() {
|
||||
|
||||
override fun getLayoutRes(): Int {
|
||||
return R.layout.source_list_item
|
||||
}
|
||||
|
||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): MigrationAnimeHolder {
|
||||
return MigrationAnimeHolder(view, adapter as MigrationAnimeAdapter)
|
||||
}
|
||||
|
||||
override fun bindViewHolder(
|
||||
adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>,
|
||||
holder: MigrationAnimeHolder,
|
||||
position: Int,
|
||||
payloads: List<Any?>?
|
||||
) {
|
||||
holder.bind(this)
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (other is MigrationAnimeItem) {
|
||||
return anime.id == other.anime.id
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return anime.id!!.hashCode()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package eu.kanade.tachiyomi.ui.browse.migration.anime
|
||||
|
||||
import android.os.Bundle
|
||||
import eu.kanade.tachiyomi.data.database.AnimeDatabaseHelper
|
||||
import eu.kanade.tachiyomi.data.database.models.Anime
|
||||
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 MigrationAnimePresenter(
|
||||
private val sourceId: Long,
|
||||
private val db: AnimeDatabaseHelper = Injekt.get()
|
||||
) : BasePresenter<MigrationAnimeController>() {
|
||||
|
||||
override fun onCreate(savedState: Bundle?) {
|
||||
super.onCreate(savedState)
|
||||
|
||||
db.getFavoriteAnimes()
|
||||
.asRxObservable()
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.map { libraryToMigrationItem(it) }
|
||||
.subscribeLatestCache(MigrationAnimeController::setAnime)
|
||||
}
|
||||
|
||||
private fun libraryToMigrationItem(library: List<Anime>): List<MigrationAnimeItem> {
|
||||
return library.filter { it.source == sourceId }
|
||||
.sortedBy { it.title }
|
||||
.map { MigrationAnimeItem(it) }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package eu.kanade.tachiyomi.ui.browse.migration.sources
|
||||
|
||||
import android.view.View
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||
import eu.davidea.flexibleadapter.items.IFlexible
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.source.AnimeSource
|
||||
|
||||
/**
|
||||
* Item that contains source information.
|
||||
*
|
||||
* @param source Instance of [Source] containing source information.
|
||||
* @param header The header for this item.
|
||||
*/
|
||||
data class AnimeSourceItem(val source: AnimeSource, val animeCount: Int) :
|
||||
AbstractFlexibleItem<SourceHolder>() {
|
||||
|
||||
/**
|
||||
* Returns the layout resource of this item.
|
||||
*/
|
||||
override fun getLayoutRes(): Int {
|
||||
return R.layout.source_main_controller_card_item
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds this item to the given view holder.
|
||||
*/
|
||||
override fun bindViewHolder(
|
||||
adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>,
|
||||
holder: SourceHolder,
|
||||
position: Int,
|
||||
payloads: List<Any?>?
|
||||
) {
|
||||
holder.bind(this)
|
||||
}
|
||||
}
|
|
@ -12,6 +12,7 @@ import eu.kanade.tachiyomi.R
|
|||
import eu.kanade.tachiyomi.databinding.MigrationSourcesControllerBinding
|
||||
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
|
||||
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
||||
import eu.kanade.tachiyomi.ui.browse.migration.anime.MigrationAnimeController
|
||||
import eu.kanade.tachiyomi.ui.browse.migration.manga.MigrationMangaController
|
||||
import eu.kanade.tachiyomi.util.system.openInBrowser
|
||||
|
||||
|
@ -66,12 +67,23 @@ class MigrationSourcesController :
|
|||
adapter?.updateDataSet(sourcesWithManga)
|
||||
}
|
||||
|
||||
fun setAnimeSources(sourcesWithAnime: List<AnimeSourceItem>) {
|
||||
adapter?.addItems(adapter?.itemCount!!, sourcesWithAnime)
|
||||
}
|
||||
|
||||
override fun onItemClick(view: View, position: Int): Boolean {
|
||||
if (adapter?.getItem(position) is AnimeSourceItem) {
|
||||
val item = adapter?.getItem(position) as? AnimeSourceItem ?: return false
|
||||
val controller = MigrationAnimeController(item.source.id, item.source.name)
|
||||
parentController!!.router.pushController(controller.withFadeTransaction())
|
||||
return false
|
||||
} else {
|
||||
val item = adapter?.getItem(position) as? SourceItem ?: return false
|
||||
val controller = MigrationMangaController(item.source.id, item.source.name)
|
||||
parentController!!.router.pushController(controller.withFadeTransaction())
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val HELP_URL = "https://tachiyomi.org/help/guides/source-migration/"
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
package eu.kanade.tachiyomi.ui.browse.migration.sources
|
||||
|
||||
import android.os.Bundle
|
||||
import eu.kanade.tachiyomi.data.database.AnimeDatabaseHelper
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
import eu.kanade.tachiyomi.data.database.models.Anime
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.source.LocalSource
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
import eu.kanade.tachiyomi.source.*
|
||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
import uy.kohesive.injekt.Injekt
|
||||
|
@ -12,7 +13,9 @@ import uy.kohesive.injekt.api.get
|
|||
|
||||
class MigrationSourcesPresenter(
|
||||
private val sourceManager: SourceManager = Injekt.get(),
|
||||
private val db: DatabaseHelper = Injekt.get()
|
||||
private val animesourceManager: AnimeSourceManager = Injekt.get(),
|
||||
private val db: DatabaseHelper = Injekt.get(),
|
||||
private val animedb: AnimeDatabaseHelper = Injekt.get()
|
||||
) : BasePresenter<MigrationSourcesController>() {
|
||||
|
||||
override fun onCreate(savedState: Bundle?) {
|
||||
|
@ -23,6 +26,11 @@ class MigrationSourcesPresenter(
|
|||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.map { findSourcesWithManga(it) }
|
||||
.subscribeLatestCache(MigrationSourcesController::setSources)
|
||||
animedb.getFavoriteAnimes()
|
||||
.asRxObservable()
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.map { findSourcesWithAnime(it) }
|
||||
.subscribeLatestCache(MigrationSourcesController::setAnimeSources)
|
||||
}
|
||||
|
||||
private fun findSourcesWithManga(library: List<Manga>): List<SourceItem> {
|
||||
|
@ -37,4 +45,16 @@ class MigrationSourcesPresenter(
|
|||
.sortedBy { it.source.name.toLowerCase() }
|
||||
.toList()
|
||||
}
|
||||
|
||||
private fun findSourcesWithAnime(library: List<Anime>): List<AnimeSourceItem> {
|
||||
return library
|
||||
.groupBy { it.source }
|
||||
.filterKeys { it != LocalSource.ID }
|
||||
.map {
|
||||
val source = animesourceManager.getOrStub(it.key)
|
||||
AnimeSourceItem(source, it.value.size)
|
||||
}
|
||||
.sortedBy { it.source.name.toLowerCase() }
|
||||
.toList()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,17 @@ class SourceHolder(view: View, val adapter: SourceAdapter) :
|
|||
binding.subtitle.isVisible = source.lang != ""
|
||||
binding.subtitle.text = LocaleHelper.getDisplayName(source.lang)
|
||||
|
||||
itemView.post {
|
||||
binding.image.setImageDrawable(source.icon())
|
||||
}
|
||||
}
|
||||
fun bind(item: AnimeSourceItem) {
|
||||
val source = item.source
|
||||
|
||||
binding.title.text = "${source.name} (${item.animeCount})"
|
||||
binding.subtitle.isVisible = source.lang != ""
|
||||
binding.subtitle.text = LocaleHelper.getDisplayName(source.lang)
|
||||
|
||||
itemView.post {
|
||||
binding.image.setImageDrawable(source.icon())
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue