Skip to content

Instantly share code, notes, and snippets.

@ElianFabian
Last active November 15, 2023 09:33
Show Gist options
  • Save ElianFabian/9874d9032c7b7526f5a5003d310493ab to your computer and use it in GitHub Desktop.
Save ElianFabian/9874d9032c7b7526f5a5003d310493ab to your computer and use it in GitHub Desktop.
import androidx.recyclerview.widget.AsyncListDiffer
import androidx.recyclerview.widget.ListAdapter
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlin.reflect.full.allSuperclasses
suspend fun <T : Any> ListAdapter<T, *>.awaitCurrentListChanged(
predicate: (previousList: List<T>, currentList: List<T>) -> Boolean = { _, _ -> true },
) {
val listAdapterClass = this::class.allSuperclasses.find {
it.qualifiedName == ListAdapter::class.qualifiedName
}?.java ?: return
@Suppress("UNCHECKED_CAST")
val differ = listAdapterClass
.getDeclaredField("mDiffer")
.apply { isAccessible = true }
.get(this) as? AsyncListDiffer<T> ?: return
suspendCancellableCoroutine<Unit> { continuation ->
val listener = object : AsyncListDiffer.ListListener<T> {
override fun onCurrentListChanged(previousList: List<T>, currentList: List<T>) {
if (predicate(previousList, currentList)) {
differ.removeListListener(this)
continuation.resumeWith(Result.success(Unit))
}
}
}
differ.addListListener(listener)
continuation.invokeOnCancellation {
differ.removeListListener(listener)
}
}
}
suspend inline fun <T : Any> ListAdapter<T, *>.awaitNonEmptyList() {
if (currentList.isNotEmpty()) {
return
}
awaitCurrentListChanged { _, currentList ->
currentList.isNotEmpty()
}
}
fun <T> ListAdapter<T, *>.currentListFlow(): Flow<List<T>> {
val listAdapterClass = this::class.allSuperclasses.find {
it.qualifiedName == ListAdapter::class.qualifiedName
}?.java ?: return emptyFlow()
@Suppress("UNCHECKED_CAST")
val differ = listAdapterClass
.getDeclaredField("mDiffer")
.apply { isAccessible = true }
.get(this) as? AsyncListDiffer<T> ?: return emptyFlow()
return callbackFlow {
val listener = AsyncListDiffer.ListListener<T> { _, currentList ->
trySend(currentList)
}
differ.addListListener(listener)
awaitClose {
differ.removeListListener(listener)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment