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
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
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.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 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
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
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