Migrate to AdapterDelegates
parent
7d24286c55
commit
7e76e10591
@ -0,0 +1,10 @@
|
|||||||
|
package org.koitharu.kotatsu.base.ui.list
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
|
||||||
|
interface OnListItemClickListener<I> {
|
||||||
|
|
||||||
|
fun onItemClick(item: I, view: View)
|
||||||
|
|
||||||
|
fun onItemLongClick(item: I, view: View) = false
|
||||||
|
}
|
||||||
@ -1,35 +0,0 @@
|
|||||||
package org.koitharu.kotatsu.list.ui
|
|
||||||
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import coil.ImageLoader
|
|
||||||
import coil.request.Disposable
|
|
||||||
import kotlinx.android.synthetic.main.item_manga_grid.*
|
|
||||||
import org.koin.core.component.inject
|
|
||||||
import org.koitharu.kotatsu.R
|
|
||||||
import org.koitharu.kotatsu.base.ui.list.BaseViewHolder
|
|
||||||
import org.koitharu.kotatsu.core.model.Manga
|
|
||||||
import org.koitharu.kotatsu.core.model.MangaHistory
|
|
||||||
import org.koitharu.kotatsu.utils.ext.enqueueWith
|
|
||||||
import org.koitharu.kotatsu.utils.ext.newImageRequest
|
|
||||||
|
|
||||||
class MangaGridHolder(parent: ViewGroup) :
|
|
||||||
BaseViewHolder<Manga, MangaHistory?>(parent, R.layout.item_manga_grid) {
|
|
||||||
|
|
||||||
private val coil by inject<ImageLoader>()
|
|
||||||
private var imageRequest: Disposable? = null
|
|
||||||
|
|
||||||
override fun onBind(data: Manga, extra: MangaHistory?) {
|
|
||||||
textView_title.text = data.title
|
|
||||||
imageRequest?.dispose()
|
|
||||||
imageRequest = imageView_cover.newImageRequest(data.coverUrl)
|
|
||||||
.placeholder(R.drawable.ic_placeholder)
|
|
||||||
.fallback(R.drawable.ic_placeholder)
|
|
||||||
.error(R.drawable.ic_placeholder)
|
|
||||||
.enqueueWith(coil)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onRecycled() {
|
|
||||||
imageRequest?.dispose()
|
|
||||||
imageView_cover.setImageDrawable(null)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,26 +0,0 @@
|
|||||||
package org.koitharu.kotatsu.list.ui
|
|
||||||
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import org.koitharu.kotatsu.base.ui.list.BaseRecyclerAdapter
|
|
||||||
import org.koitharu.kotatsu.base.ui.list.OnRecyclerItemClickListener
|
|
||||||
import org.koitharu.kotatsu.core.model.Manga
|
|
||||||
import org.koitharu.kotatsu.core.model.MangaHistory
|
|
||||||
import org.koitharu.kotatsu.core.prefs.ListMode
|
|
||||||
|
|
||||||
class MangaListAdapter(onItemClickListener: OnRecyclerItemClickListener<Manga>) :
|
|
||||||
BaseRecyclerAdapter<Manga, MangaHistory?>(onItemClickListener) {
|
|
||||||
|
|
||||||
var listMode: ListMode = ListMode.LIST
|
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup) = when (listMode) {
|
|
||||||
ListMode.LIST -> MangaListHolder(parent)
|
|
||||||
ListMode.DETAILED_LIST -> MangaListDetailsHolder(
|
|
||||||
parent
|
|
||||||
)
|
|
||||||
ListMode.GRID -> MangaGridHolder(parent)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onGetItemId(item: Manga) = item.id
|
|
||||||
|
|
||||||
override fun getExtra(item: Manga, position: Int): MangaHistory? = null
|
|
||||||
}
|
|
||||||
@ -1,51 +0,0 @@
|
|||||||
package org.koitharu.kotatsu.list.ui
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.core.view.isVisible
|
|
||||||
import coil.ImageLoader
|
|
||||||
import coil.request.Disposable
|
|
||||||
import kotlinx.android.synthetic.main.item_manga_list_details.*
|
|
||||||
import org.koin.core.component.inject
|
|
||||||
import org.koitharu.kotatsu.R
|
|
||||||
import org.koitharu.kotatsu.base.ui.list.BaseViewHolder
|
|
||||||
import org.koitharu.kotatsu.core.model.Manga
|
|
||||||
import org.koitharu.kotatsu.core.model.MangaHistory
|
|
||||||
import org.koitharu.kotatsu.utils.ext.enqueueWith
|
|
||||||
import org.koitharu.kotatsu.utils.ext.newImageRequest
|
|
||||||
import org.koitharu.kotatsu.utils.ext.textAndVisible
|
|
||||||
import kotlin.math.roundToInt
|
|
||||||
|
|
||||||
class MangaListDetailsHolder(
|
|
||||||
parent: ViewGroup
|
|
||||||
) : BaseViewHolder<Manga, MangaHistory?>(parent, R.layout.item_manga_list_details) {
|
|
||||||
|
|
||||||
private val coil by inject<ImageLoader>()
|
|
||||||
private var imageRequest: Disposable? = null
|
|
||||||
|
|
||||||
@SuppressLint("SetTextI18n")
|
|
||||||
override fun onBind(data: Manga, extra: MangaHistory?) {
|
|
||||||
imageRequest?.dispose()
|
|
||||||
textView_title.text = data.title
|
|
||||||
textView_subtitle.textAndVisible = data.altTitle
|
|
||||||
imageRequest = imageView_cover.newImageRequest(data.coverUrl)
|
|
||||||
.placeholder(R.drawable.ic_placeholder)
|
|
||||||
.fallback(R.drawable.ic_placeholder)
|
|
||||||
.error(R.drawable.ic_placeholder)
|
|
||||||
.enqueueWith(coil)
|
|
||||||
if (data.rating == Manga.NO_RATING) {
|
|
||||||
textView_rating.isVisible = false
|
|
||||||
} else {
|
|
||||||
textView_rating.text = "${(data.rating * 10).roundToInt()}/10"
|
|
||||||
textView_rating.isVisible = true
|
|
||||||
}
|
|
||||||
textView_tags.text = data.tags.joinToString(", ") {
|
|
||||||
it.title
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onRecycled() {
|
|
||||||
imageRequest?.dispose()
|
|
||||||
imageView_cover.setImageDrawable(null)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,38 +0,0 @@
|
|||||||
package org.koitharu.kotatsu.list.ui
|
|
||||||
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import coil.ImageLoader
|
|
||||||
import coil.request.Disposable
|
|
||||||
import kotlinx.android.synthetic.main.item_manga_list.*
|
|
||||||
import org.koin.core.component.inject
|
|
||||||
import org.koitharu.kotatsu.R
|
|
||||||
import org.koitharu.kotatsu.base.ui.list.BaseViewHolder
|
|
||||||
import org.koitharu.kotatsu.core.model.Manga
|
|
||||||
import org.koitharu.kotatsu.core.model.MangaHistory
|
|
||||||
import org.koitharu.kotatsu.utils.ext.enqueueWith
|
|
||||||
import org.koitharu.kotatsu.utils.ext.newImageRequest
|
|
||||||
import org.koitharu.kotatsu.utils.ext.textAndVisible
|
|
||||||
|
|
||||||
class MangaListHolder(
|
|
||||||
parent: ViewGroup
|
|
||||||
) : BaseViewHolder<Manga, MangaHistory?>(parent, R.layout.item_manga_list) {
|
|
||||||
|
|
||||||
private val coil by inject<ImageLoader>()
|
|
||||||
private var imageRequest: Disposable? = null
|
|
||||||
|
|
||||||
override fun onBind(data: Manga, extra: MangaHistory?) {
|
|
||||||
imageRequest?.dispose()
|
|
||||||
textView_title.text = data.title
|
|
||||||
textView_subtitle.textAndVisible = data.tags.joinToString(", ") { it.title }
|
|
||||||
imageRequest = imageView_cover.newImageRequest(data.coverUrl)
|
|
||||||
.placeholder(R.drawable.ic_placeholder)
|
|
||||||
.fallback(R.drawable.ic_placeholder)
|
|
||||||
.error(R.drawable.ic_placeholder)
|
|
||||||
.enqueueWith(coil)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onRecycled() {
|
|
||||||
imageRequest?.dispose()
|
|
||||||
imageView_cover.setImageDrawable(null)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,55 @@
|
|||||||
|
package org.koitharu.kotatsu.list.ui
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.view.View
|
||||||
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import org.koitharu.kotatsu.R
|
||||||
|
import org.koitharu.kotatsu.list.ui.adapter.MangaListAdapter
|
||||||
|
import kotlin.math.abs
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
|
class MangaListSpanResolver(
|
||||||
|
context: Context,
|
||||||
|
private val adapter: MangaListAdapter
|
||||||
|
) : GridLayoutManager.SpanSizeLookup(), View.OnLayoutChangeListener {
|
||||||
|
|
||||||
|
private val gridWidth = context.resources.getDimension(R.dimen.preferred_grid_width)
|
||||||
|
private var cellWidth = -1f
|
||||||
|
|
||||||
|
override fun getSpanSize(position: Int) = when(adapter.getItemViewType(position)) {
|
||||||
|
else -> 1
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onLayoutChange(
|
||||||
|
v: View?,
|
||||||
|
left: Int,
|
||||||
|
top: Int,
|
||||||
|
right: Int,
|
||||||
|
bottom: Int,
|
||||||
|
oldLeft: Int,
|
||||||
|
oldTop: Int,
|
||||||
|
oldRight: Int,
|
||||||
|
oldBottom: Int
|
||||||
|
) {
|
||||||
|
if (cellWidth <= 0f) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val rv = v as? RecyclerView ?: return
|
||||||
|
val width = abs(right - left)
|
||||||
|
if (width == 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
(rv.layoutManager as? GridLayoutManager)?.spanCount = resolveGridSpanCount(width)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setGridSize(gridSize: Int) {
|
||||||
|
val scaleFactor = gridSize / 100f
|
||||||
|
cellWidth = gridWidth * scaleFactor
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun resolveGridSpanCount(width: Int): Int {
|
||||||
|
val estimatedCount = (width / cellWidth).roundToInt()
|
||||||
|
return estimatedCount.coerceAtLeast(2)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,11 +1,31 @@
|
|||||||
package org.koitharu.kotatsu.list.ui
|
package org.koitharu.kotatsu.list.ui
|
||||||
|
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import androidx.lifecycle.asLiveData
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.flow.*
|
||||||
import org.koitharu.kotatsu.base.ui.BaseViewModel
|
import org.koitharu.kotatsu.base.ui.BaseViewModel
|
||||||
import org.koitharu.kotatsu.core.model.Manga
|
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||||
|
import org.koitharu.kotatsu.core.prefs.ListMode
|
||||||
|
|
||||||
abstract class MangaListViewModel : BaseViewModel() {
|
abstract class MangaListViewModel(
|
||||||
|
private val settings: AppSettings
|
||||||
|
) : BaseViewModel() {
|
||||||
|
|
||||||
val content = MutableLiveData<List<Manga>>()
|
abstract val content: LiveData<List<Any>>
|
||||||
val filter = MutableLiveData<MangaFilterConfig>()
|
val filter = MutableLiveData<MangaFilterConfig>()
|
||||||
|
val listMode = MutableLiveData<ListMode>()
|
||||||
|
val gridScale = settings.observe()
|
||||||
|
.filter { it == AppSettings.KEY_GRID_SIZE }
|
||||||
|
.map { settings.gridSize / 100f }
|
||||||
|
.asLiveData(viewModelScope.coroutineContext + Dispatchers.IO)
|
||||||
|
|
||||||
|
protected fun createListModeFlow() = settings.observe()
|
||||||
|
.filter { it == AppSettings.KEY_LIST_MODE }
|
||||||
|
.map { settings.listMode }
|
||||||
|
.onStart { emit(settings.listMode) }
|
||||||
|
.distinctUntilChanged()
|
||||||
|
.onEach { listMode.postValue(it) }
|
||||||
}
|
}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
package org.koitharu.kotatsu.list.ui.adapter
|
||||||
|
|
||||||
|
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegate
|
||||||
|
import org.koitharu.kotatsu.R
|
||||||
|
import org.koitharu.kotatsu.list.ui.model.IndeterminateProgress
|
||||||
|
|
||||||
|
fun indeterminateProgressAD() = adapterDelegate<IndeterminateProgress, Any>(R.layout.item_progress) {
|
||||||
|
}
|
||||||
@ -0,0 +1,42 @@
|
|||||||
|
package org.koitharu.kotatsu.list.ui.adapter
|
||||||
|
|
||||||
|
import coil.ImageLoader
|
||||||
|
import coil.request.Disposable
|
||||||
|
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateLayoutContainer
|
||||||
|
import kotlinx.android.synthetic.main.item_manga_list.*
|
||||||
|
import org.koitharu.kotatsu.R
|
||||||
|
import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener
|
||||||
|
import org.koitharu.kotatsu.core.model.Manga
|
||||||
|
import org.koitharu.kotatsu.list.ui.model.MangaGridModel
|
||||||
|
import org.koitharu.kotatsu.utils.ext.enqueueWith
|
||||||
|
import org.koitharu.kotatsu.utils.ext.newImageRequest
|
||||||
|
|
||||||
|
fun mangaGridItemAD(
|
||||||
|
coil: ImageLoader,
|
||||||
|
clickListener: OnListItemClickListener<Manga>
|
||||||
|
) = adapterDelegateLayoutContainer<MangaGridModel, Any>(R.layout.item_manga_grid) {
|
||||||
|
|
||||||
|
var imageRequest: Disposable? = null
|
||||||
|
|
||||||
|
itemView.setOnClickListener {
|
||||||
|
clickListener.onItemClick(item.manga, it)
|
||||||
|
}
|
||||||
|
itemView.setOnLongClickListener {
|
||||||
|
clickListener.onItemLongClick(item.manga, it)
|
||||||
|
}
|
||||||
|
|
||||||
|
bind {
|
||||||
|
textView_title.text = item.title
|
||||||
|
imageRequest?.dispose()
|
||||||
|
imageRequest = imageView_cover.newImageRequest(item.coverUrl)
|
||||||
|
.placeholder(R.drawable.ic_placeholder)
|
||||||
|
.fallback(R.drawable.ic_placeholder)
|
||||||
|
.error(R.drawable.ic_placeholder)
|
||||||
|
.enqueueWith(coil)
|
||||||
|
}
|
||||||
|
|
||||||
|
onViewRecycled {
|
||||||
|
imageRequest?.dispose()
|
||||||
|
imageView_cover.setImageDrawable(null)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,49 @@
|
|||||||
|
package org.koitharu.kotatsu.list.ui.adapter
|
||||||
|
|
||||||
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
|
import coil.ImageLoader
|
||||||
|
import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter
|
||||||
|
import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener
|
||||||
|
import org.koitharu.kotatsu.core.model.Manga
|
||||||
|
import org.koitharu.kotatsu.list.ui.model.IndeterminateProgress
|
||||||
|
import org.koitharu.kotatsu.list.ui.model.MangaGridModel
|
||||||
|
import org.koitharu.kotatsu.list.ui.model.MangaListDetailedModel
|
||||||
|
import org.koitharu.kotatsu.list.ui.model.MangaListModel
|
||||||
|
import kotlin.jvm.internal.Intrinsics
|
||||||
|
|
||||||
|
class MangaListAdapter(
|
||||||
|
coil: ImageLoader,
|
||||||
|
clickListener: OnListItemClickListener<Manga>
|
||||||
|
) : AsyncListDifferDelegationAdapter<Any>(DiffCallback) {
|
||||||
|
|
||||||
|
init {
|
||||||
|
delegatesManager.addDelegate(mangaListItemAD(coil, clickListener))
|
||||||
|
.addDelegate(mangaListDetailedItemAD(coil, clickListener))
|
||||||
|
.addDelegate(mangaGridItemAD(coil, clickListener))
|
||||||
|
.addDelegate(indeterminateProgressAD())
|
||||||
|
}
|
||||||
|
|
||||||
|
private companion object DiffCallback : DiffUtil.ItemCallback<Any>() {
|
||||||
|
|
||||||
|
override fun areItemsTheSame(oldItem: Any, newItem: Any) = when {
|
||||||
|
oldItem is MangaListModel && newItem is MangaListModel -> {
|
||||||
|
oldItem.id == newItem.id
|
||||||
|
}
|
||||||
|
oldItem is MangaListDetailedModel && newItem is MangaListDetailedModel -> {
|
||||||
|
oldItem.id == newItem.id
|
||||||
|
}
|
||||||
|
oldItem is MangaGridModel && newItem is MangaGridModel -> {
|
||||||
|
oldItem.id == newItem.id
|
||||||
|
}
|
||||||
|
oldItem == IndeterminateProgress && newItem == IndeterminateProgress -> {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun areContentsTheSame(oldItem: Any, newItem: Any): Boolean {
|
||||||
|
return Intrinsics.areEqual(oldItem, newItem)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,46 @@
|
|||||||
|
package org.koitharu.kotatsu.list.ui.adapter
|
||||||
|
|
||||||
|
import coil.ImageLoader
|
||||||
|
import coil.request.Disposable
|
||||||
|
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateLayoutContainer
|
||||||
|
import kotlinx.android.synthetic.main.item_manga_list_details.*
|
||||||
|
import org.koitharu.kotatsu.R
|
||||||
|
import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener
|
||||||
|
import org.koitharu.kotatsu.core.model.Manga
|
||||||
|
import org.koitharu.kotatsu.list.ui.model.MangaListDetailedModel
|
||||||
|
import org.koitharu.kotatsu.utils.ext.enqueueWith
|
||||||
|
import org.koitharu.kotatsu.utils.ext.newImageRequest
|
||||||
|
import org.koitharu.kotatsu.utils.ext.textAndVisible
|
||||||
|
|
||||||
|
fun mangaListDetailedItemAD(
|
||||||
|
coil: ImageLoader,
|
||||||
|
clickListener: OnListItemClickListener<Manga>
|
||||||
|
) = adapterDelegateLayoutContainer<MangaListDetailedModel, Any>(R.layout.item_manga_list_details) {
|
||||||
|
|
||||||
|
var imageRequest: Disposable? = null
|
||||||
|
|
||||||
|
itemView.setOnClickListener {
|
||||||
|
clickListener.onItemClick(item.manga, it)
|
||||||
|
}
|
||||||
|
itemView.setOnLongClickListener {
|
||||||
|
clickListener.onItemLongClick(item.manga, it)
|
||||||
|
}
|
||||||
|
|
||||||
|
bind {
|
||||||
|
imageRequest?.dispose()
|
||||||
|
textView_title.text = item.title
|
||||||
|
textView_subtitle.textAndVisible = item.subtitle
|
||||||
|
imageRequest = imageView_cover.newImageRequest(item.coverUrl)
|
||||||
|
.placeholder(R.drawable.ic_placeholder)
|
||||||
|
.fallback(R.drawable.ic_placeholder)
|
||||||
|
.error(R.drawable.ic_placeholder)
|
||||||
|
.enqueueWith(coil)
|
||||||
|
textView_rating.textAndVisible = item.rating
|
||||||
|
textView_tags.text = item.tags
|
||||||
|
}
|
||||||
|
|
||||||
|
onViewRecycled {
|
||||||
|
imageRequest?.dispose()
|
||||||
|
imageView_cover.setImageDrawable(null)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,44 @@
|
|||||||
|
package org.koitharu.kotatsu.list.ui.adapter
|
||||||
|
|
||||||
|
import coil.ImageLoader
|
||||||
|
import coil.request.Disposable
|
||||||
|
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateLayoutContainer
|
||||||
|
import kotlinx.android.synthetic.main.item_manga_list.*
|
||||||
|
import org.koitharu.kotatsu.R
|
||||||
|
import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener
|
||||||
|
import org.koitharu.kotatsu.core.model.Manga
|
||||||
|
import org.koitharu.kotatsu.list.ui.model.MangaListModel
|
||||||
|
import org.koitharu.kotatsu.utils.ext.enqueueWith
|
||||||
|
import org.koitharu.kotatsu.utils.ext.newImageRequest
|
||||||
|
import org.koitharu.kotatsu.utils.ext.textAndVisible
|
||||||
|
|
||||||
|
fun mangaListItemAD(
|
||||||
|
coil: ImageLoader,
|
||||||
|
clickListener: OnListItemClickListener<Manga>
|
||||||
|
) = adapterDelegateLayoutContainer<MangaListModel, Any>(R.layout.item_manga_list) {
|
||||||
|
|
||||||
|
var imageRequest: Disposable? = null
|
||||||
|
|
||||||
|
itemView.setOnClickListener {
|
||||||
|
clickListener.onItemClick(item.manga, it)
|
||||||
|
}
|
||||||
|
itemView.setOnLongClickListener {
|
||||||
|
clickListener.onItemLongClick(item.manga, it)
|
||||||
|
}
|
||||||
|
|
||||||
|
bind {
|
||||||
|
imageRequest?.dispose()
|
||||||
|
textView_title.text = item.title
|
||||||
|
textView_subtitle.textAndVisible = item.subtitle
|
||||||
|
imageRequest = imageView_cover.newImageRequest(item.coverUrl)
|
||||||
|
.placeholder(R.drawable.ic_placeholder)
|
||||||
|
.fallback(R.drawable.ic_placeholder)
|
||||||
|
.error(R.drawable.ic_placeholder)
|
||||||
|
.enqueueWith(coil)
|
||||||
|
}
|
||||||
|
|
||||||
|
onViewRecycled {
|
||||||
|
imageRequest?.dispose()
|
||||||
|
imageView_cover.setImageDrawable(null)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,3 @@
|
|||||||
|
package org.koitharu.kotatsu.list.ui.model
|
||||||
|
|
||||||
|
object IndeterminateProgress
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
package org.koitharu.kotatsu.list.ui.model
|
||||||
|
|
||||||
|
import org.koitharu.kotatsu.core.model.Manga
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
|
fun Manga.toListModel() = MangaListModel(
|
||||||
|
id = id,
|
||||||
|
title = title,
|
||||||
|
subtitle = tags.joinToString(", ") { it.title },
|
||||||
|
coverUrl = coverUrl,
|
||||||
|
manga = this
|
||||||
|
)
|
||||||
|
|
||||||
|
fun Manga.toListDetailedModel() = MangaListDetailedModel(
|
||||||
|
id = id,
|
||||||
|
title = title,
|
||||||
|
subtitle = altTitle,
|
||||||
|
rating = "${(rating * 10).roundToInt()}/10",
|
||||||
|
tags = tags.joinToString(", ") { it.title },
|
||||||
|
coverUrl = coverUrl,
|
||||||
|
manga = this
|
||||||
|
)
|
||||||
|
|
||||||
|
fun Manga.toGridModel() = MangaGridModel(
|
||||||
|
id = id,
|
||||||
|
title = title,
|
||||||
|
coverUrl = coverUrl,
|
||||||
|
manga = this
|
||||||
|
)
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
package org.koitharu.kotatsu.list.ui.model
|
||||||
|
|
||||||
|
import org.koitharu.kotatsu.core.model.Manga
|
||||||
|
|
||||||
|
data class MangaGridModel(
|
||||||
|
val id: Long,
|
||||||
|
val title: String,
|
||||||
|
val coverUrl: String,
|
||||||
|
val manga: Manga
|
||||||
|
)
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
package org.koitharu.kotatsu.list.ui.model
|
||||||
|
|
||||||
|
import org.koitharu.kotatsu.core.model.Manga
|
||||||
|
|
||||||
|
data class MangaListDetailedModel(
|
||||||
|
val id: Long,
|
||||||
|
val title: String,
|
||||||
|
val subtitle: String?,
|
||||||
|
val tags: String,
|
||||||
|
val coverUrl: String,
|
||||||
|
val rating: String?,
|
||||||
|
val manga: Manga
|
||||||
|
)
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
package org.koitharu.kotatsu.list.ui.model
|
||||||
|
|
||||||
|
import org.koitharu.kotatsu.core.model.Manga
|
||||||
|
|
||||||
|
data class MangaListModel(
|
||||||
|
val id: Long,
|
||||||
|
val title: String,
|
||||||
|
val subtitle: String,
|
||||||
|
val coverUrl: String,
|
||||||
|
val manga: Manga
|
||||||
|
)
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
package org.koitharu.kotatsu.utils.ext
|
||||||
|
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
|
||||||
|
fun <T> Flow<T>.onFirst(action: suspend (T) -> Unit): Flow<T> {
|
||||||
|
var isFirstCall = true
|
||||||
|
return onEach {
|
||||||
|
if (isFirstCall) {
|
||||||
|
action(it)
|
||||||
|
isFirstCall = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <T, R> Flow<List<T>>.mapItems(crossinline transform: (T) -> R): Flow<List<R>> {
|
||||||
|
return map { list -> list.map(transform) }
|
||||||
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
#Sun Nov 15 14:08:38 EET 2020
|
#Thu Nov 19 06:56:48 EET 2020
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-all.zip
|
||||||
|
|||||||
Loading…
Reference in New Issue