73 lines
2.4 KiB
Kotlin
73 lines
2.4 KiB
Kotlin
|
package eu.kanade.data
|
||
|
|
||
|
import androidx.paging.PagingSource
|
||
|
import androidx.paging.PagingState
|
||
|
import com.squareup.sqldelight.Query
|
||
|
import eu.kanade.tachiyomi.Database
|
||
|
import kotlin.properties.Delegates
|
||
|
|
||
|
class QueryPagingSource<RowType : Any>(
|
||
|
val handler: DatabaseHandler,
|
||
|
val countQuery: Database.() -> Query<Long>,
|
||
|
val queryProvider: Database.(Long, Long) -> Query<RowType>,
|
||
|
) : PagingSource<Long, RowType>(), Query.Listener {
|
||
|
|
||
|
override val jumpingSupported: Boolean = true
|
||
|
|
||
|
private var currentQuery: Query<RowType>? by Delegates.observable(null) { _, old, new ->
|
||
|
old?.removeListener(this)
|
||
|
new?.addListener(this)
|
||
|
}
|
||
|
|
||
|
init {
|
||
|
registerInvalidatedCallback {
|
||
|
currentQuery?.removeListener(this)
|
||
|
currentQuery = null
|
||
|
}
|
||
|
}
|
||
|
|
||
|
override suspend fun load(params: LoadParams<Long>): LoadResult<Long, RowType> {
|
||
|
try {
|
||
|
val key = params.key ?: 0L
|
||
|
val loadSize = params.loadSize
|
||
|
val count = handler.awaitOne { countQuery() }
|
||
|
|
||
|
val (offset, limit) = when (params) {
|
||
|
is LoadParams.Prepend -> key - loadSize to loadSize.toLong()
|
||
|
else -> key to loadSize.toLong()
|
||
|
}
|
||
|
|
||
|
val data = handler.awaitList {
|
||
|
queryProvider(limit, offset)
|
||
|
.also { currentQuery = it }
|
||
|
}
|
||
|
|
||
|
val (prevKey, nextKey) = when (params) {
|
||
|
is LoadParams.Append -> { offset - loadSize to offset + loadSize }
|
||
|
else -> { offset to offset + loadSize }
|
||
|
}
|
||
|
|
||
|
return LoadResult.Page(
|
||
|
data = data,
|
||
|
prevKey = if (offset <= 0L || prevKey < 0L) null else prevKey,
|
||
|
nextKey = if (offset + loadSize >= count) null else nextKey,
|
||
|
itemsBefore = maxOf(0L, offset).toInt(),
|
||
|
itemsAfter = maxOf(0L, count - (offset + loadSize)).toInt(),
|
||
|
)
|
||
|
} catch (e: Exception) {
|
||
|
return LoadResult.Error(throwable = e)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
override fun getRefreshKey(state: PagingState<Long, RowType>): Long? {
|
||
|
return state.anchorPosition?.let { anchorPosition ->
|
||
|
val anchorPage = state.closestPageToPosition(anchorPosition)
|
||
|
anchorPage?.prevKey ?: anchorPage?.nextKey
|
||
|
}
|
||
|
}
|
||
|
|
||
|
override fun queryResultsChanged() {
|
||
|
invalidate()
|
||
|
}
|
||
|
}
|