sqldelight icon indicating copy to clipboard operation
sqldelight copied to clipboard

Paging Source emitting 0 items when table is updated in some other screen which results in Scroll State being lost

Open Vaibhav2002 opened this issue 3 months ago • 0 comments

Discussed in https://github.com/cashapp/sqldelight/discussions/5103

Originally posted by Vaibhav2002 March 31, 2024 I have a screen which shows a paged list of data coming from a SQL Delight table, Now when i navigate to some other screen in which I either add new data to the table or update existing one and navigate back My whole screen scroll state is lost When logging I found out that the LazyPagingItems<T>.itemCount is 0, which seems to be messing up the scroll state

I'm using CashApp's Multiplatform Paging for Paging in Compose Multiplatform, and Decompose for navigation

This is an example of how my query is

fun getByReferenceIdPaged(referenceId: String) = QueryPagingSource(
    countQuery = queries.countByReferenceId(referenceId),
    transacter = queries,
    context = Dispatchers.IO,
    queryProvider = { limit, offset ->
        queries.getByReferenceIdPaged(referenceId, limit, offset)
    }
)
countByReferenceId:
SELECT COUNT(*) FROM PostEntity WHERE referenceId = :referenceId;

getByReferenceIdPaged:
SELECT * FROM PostEntity
WHERE referenceId = :referenceId
ORDER BY createdAt DESC
LIMIT :limit OFFSET :offset;

This is how i get the `Flow<PagingData<T>>

val replies = threads
    .mapLatest { it.lastOrNull() }
    .filterNotNull()
    .distinctUntilChangedBy { it.id }
    .mapLatest { postsRepo.getReplies(it.id) } // <--- Getting paging data from DB
    .flatMapLatest { it.pagedData } // <- Flow of PagingData
    .mapLatest { it.map { it.toDomain() } }
    .cachedIn(componentScope)
    .onIO()
    .safeCatch()
    .toStateFlow(componentScope, PagingData.empty())

My Lazy Column

LazyColumn(
    modifier = modifier,
    state = state,
    contentPadding = contentPadding,
    verticalArrangement = verticalArrangement,
    reverseLayout = reverseLayout
) {
    header?.invoke(this)
    when(val loadState = loadState?.refresh) {
        is LoadState.Loading -> {
            if(loader!=null) item("Main Loader", content = loader)
        }
        is LoadState.Error -> {
            item("Main Error") {
                ErrorState(
                    error = loadState.error,
                    onRetryClick = items::retry,
                    modifier = errorModifier()
                )
            }
        }
        is LoadState.NotLoading -> {
            if(items.itemSnapshotList.items.isEmpty())
                emptyState?.let { item("Main Empty", content = it) }
            else {
                items(
                    count = items.itemCount,
                    key = key?.let(items::itemKey),
                    contentType = contentType?.let(items::itemContentType) ?: { null }
                ) {
                    items[it]?.let { item -> content(item) }
                }
            }
        }
        else -> Unit
    }
    if (loadState?.append?.endOfPaginationReached == true)
        footer?.invoke(this)
}

Vaibhav2002 avatar Apr 01 '24 13:04 Vaibhav2002