From 13d70e76238b37c34052d7b737dffb1e2379b0d1 Mon Sep 17 00:00:00 2001 From: Ray <154766448+damontecres@users.noreply.github.com> Date: Sat, 20 Dec 2025 14:39:48 -0500 Subject: [PATCH] Rework internals of ApiRequestPager (#518) ## Description Changes how `init()` works for `ApiRequestPager` so that it 1) always forces updating the total count if needed and 2) propagates errors during the initial fetch up to the original caller This means if an error occurs during the initialization of the pager data, it won't be quietly logged and ignored. Instead, ViewModel code will catch it and display an error in the UI. ### Related issues Should fix #492 --- .../ui/components/CollectionFolderGrid.kt | 27 +++++++--- .../wholphin/util/ApiRequestPager.kt | 54 ++++++++++--------- 2 files changed, 49 insertions(+), 32 deletions(-) diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/components/CollectionFolderGrid.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/components/CollectionFolderGrid.kt index 7ff7fdcf..f52f3970 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/components/CollectionFolderGrid.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/components/CollectionFolderGrid.kt @@ -252,13 +252,26 @@ class CollectionFolderViewModel this@CollectionFolderViewModel.sortAndDirection.value = sortAndDirection this@CollectionFolderViewModel.filter.value = filter } - val newPager = createPager(sortAndDirection, recursive, filter, useSeriesForPrimary) - newPager.init() - if (newPager.isNotEmpty()) newPager.getBlocking(0) - withContext(Dispatchers.Main) { - pager.value = newPager - loading.value = LoadingState.Success - backgroundLoading.value = LoadingState.Success + try { + val newPager = + createPager(sortAndDirection, recursive, filter, useSeriesForPrimary).init() + if (newPager.isNotEmpty()) newPager.getBlocking(0) + withContext(Dispatchers.Main) { + pager.value = newPager + loading.value = LoadingState.Success + backgroundLoading.value = LoadingState.Success + } + } catch (ex: Exception) { + Timber.e( + ex, + "Exception while loading data: sort=%s, filter=%s", + sortAndDirection, + filter, + ) + withContext(Dispatchers.Main) { + loading.value = LoadingState.Error(ex) + pager.value = listOf() + } } } } diff --git a/app/src/main/java/com/github/damontecres/wholphin/util/ApiRequestPager.kt b/app/src/main/java/com/github/damontecres/wholphin/util/ApiRequestPager.kt index 0ed74fe0..b03ce9f9 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/util/ApiRequestPager.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/util/ApiRequestPager.kt @@ -66,7 +66,7 @@ class ApiRequestPager( suspend fun init(initialPosition: Int = 0): ApiRequestPager { if (totalCount < 0) { - fetchPage(initialPosition, true).join() + fetchPageBlocking(initialPosition, true) } return this } @@ -75,7 +75,7 @@ class ApiRequestPager( if (index in 0..( if (index in 0..( override val size: Int get() = totalCount - private fun fetchPage( + private fun fetchPage(position: Int): Job = + scope.launch(ExceptionHandler() + Dispatchers.IO) { + fetchPageBlocking(position, false) + } + + private suspend fun fetchPageBlocking( position: Int, setTotalCount: Boolean, - ): Job = - scope.launch(ExceptionHandler() + Dispatchers.IO) { - mutex.withLock { - val pageNumber = position / pageSize - if (cachedPages.getIfPresent(pageNumber) == null) { - if (DEBUG) Timber.v("fetchPage: $pageNumber") - val newRequest = - requestHandler.prepare( - request, - pageNumber * pageSize, - pageSize, - setTotalCount, - ) - val result = requestHandler.execute(api, newRequest).content - if (setTotalCount) { - totalCount = result.totalRecordCount - } - val data = mutableListOf() - result.items.forEach { data.add(BaseItem.from(it, api, useSeriesForPrimary)) } - cachedPages.put(pageNumber, data) - items = ItemList(totalCount, pageSize, cachedPages.asMap()) + ) { + mutex.withLock { + val pageNumber = position / pageSize + if (cachedPages.getIfPresent(pageNumber) == null || setTotalCount) { + if (DEBUG) Timber.v("fetchPage: $pageNumber") + val newRequest = + requestHandler.prepare( + request, + pageNumber * pageSize, + pageSize, + setTotalCount, + ) + val result = requestHandler.execute(api, newRequest).content + if (setTotalCount) { + totalCount = result.totalRecordCount.coerceAtLeast(0) } + val data = mutableListOf() + result.items.forEach { data.add(BaseItem.from(it, api, useSeriesForPrimary)) } + cachedPages.put(pageNumber, data) + items = ItemList(totalCount, pageSize, cachedPages.asMap()) } } + } suspend fun refreshItem( position: Int,