package dev.inmo.micro_utils.android.recyclerview import androidx.recyclerview.widget.* import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.* @Suppress("NOTHING_TO_INLINE") private inline fun RecyclerView.LayoutManager.findLastVisibleItemPositionGetter(): (() -> Int)? = when (this) { is LinearLayoutManager -> ::findLastVisibleItemPosition is GridLayoutManager -> ::findLastVisibleItemPosition else -> null } fun RecyclerView.lastVisibleItemFlow( completingScope: CoroutineScope ): Flow { val lastVisibleElementFun: () -> Int = layoutManager ?.findLastVisibleItemPositionGetter() ?: error("Currently supported only linear and grid layout manager") val lastVisibleFlow = MutableStateFlow(lastVisibleElementFun()) addOnScrollListener( object : RecyclerView.OnScrollListener() { override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { super.onScrolled(recyclerView, dx, dy) lastVisibleFlow.value = lastVisibleElementFun() } }.also { scrollListener -> lastVisibleFlow.onCompletion { removeOnScrollListener(scrollListener) }.launchIn(completingScope) } ) return lastVisibleFlow.asStateFlow() } inline fun Flow.mapLeftItems( crossinline countGetter: () -> Int ): Flow = map { countGetter() - it } inline fun Flow.mapRequireFilling( minimalLeftItems: Int, crossinline countGetter: () -> Int ): Flow = mapLeftItems(countGetter).mapNotNull { if (it < minimalLeftItems) { it } else { null } } inline fun RecyclerView.mapRequireFilling( minimalLeftItems: Int, completingScope: CoroutineScope, crossinline countGetter: () -> Int ): Flow = lastVisibleItemFlow(completingScope).mapRequireFilling(minimalLeftItems, countGetter)