From ae10f1476f3480dd2c0c4e77cd798ef952c81782 Mon Sep 17 00:00:00 2001 From: Syer10 Date: Mon, 3 Jul 2023 21:20:45 -0400 Subject: [PATCH] Fix infinite loading in library --- .../ca/gosyer/jui/ui/library/LibraryScreen.kt | 2 - .../jui/ui/library/LibraryScreenViewModel.kt | 38 ++-- .../components/LibraryScreenContent.kt | 173 +++++++++--------- 3 files changed, 113 insertions(+), 100 deletions(-) diff --git a/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/library/LibraryScreen.kt b/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/library/LibraryScreen.kt index bf7428ef..60832961 100644 --- a/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/library/LibraryScreen.kt +++ b/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/library/LibraryScreen.kt @@ -33,8 +33,6 @@ class LibraryScreen : BaseScreen() { displayMode = vm.displayMode.collectAsState().value, gridColumns = vm.gridColumns.collectAsState().value, gridSize = vm.gridSize.collectAsState().value, - isLoading = vm.isLoading.collectAsState().value, - error = vm.error.collectAsState().value, query = vm.query.collectAsState().value, updateQuery = vm::updateQuery, getLibraryForPage = { vm.getLibraryForCategoryId(it).collectAsState() }, diff --git a/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/library/LibraryScreenViewModel.kt b/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/library/LibraryScreenViewModel.kt index 80aac654..8022a6cb 100644 --- a/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/library/LibraryScreenViewModel.kt +++ b/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/library/LibraryScreenViewModel.kt @@ -52,6 +52,20 @@ import me.tatarka.inject.annotations.Assisted import me.tatarka.inject.annotations.Inject import org.lighthousegames.logging.logging +@Stable +sealed class LibraryState { + @Stable + object Loading : LibraryState() + + @Stable + data class Failed(val e: Throwable) : LibraryState() + + @Stable + data class Loaded( + val categories: ImmutableList + ) : LibraryState() +} + @Stable sealed class CategoryState { @Stable @@ -68,7 +82,7 @@ sealed class CategoryState { } private typealias LibraryMap = MutableMap> -private data class Library(val categories: MutableStateFlow>, val mangaMap: LibraryMap) +private data class Library(val categories: MutableStateFlow, val mangaMap: LibraryMap) private fun LibraryMap.getManga(id: Long) = getOrPut(id) { @@ -98,7 +112,7 @@ class LibraryScreenViewModel @Inject constructor( contextWrapper: ContextWrapper, @Assisted private val savedStateHandle: SavedStateHandle, ) : ViewModel(contextWrapper) { - private val library = Library(MutableStateFlow(persistentListOf()), mutableMapOf()) + private val library = Library(MutableStateFlow(LibraryState.Loading), mutableMapOf()) val categories = library.categories.asStateFlow() private val _selectedCategoryIndex by savedStateHandle.getStateFlow { 0 } @@ -140,12 +154,6 @@ class LibraryScreenViewModel @Inject constructor( } } - private val _isLoading = MutableStateFlow(true) - val isLoading = _isLoading.asStateFlow() - - private val _error = MutableStateFlow(null) - val error = _error.asStateFlow() - private val _query by savedStateHandle.getStateFlow { "" } val query = _query.asStateFlow() @@ -158,14 +166,16 @@ class LibraryScreenViewModel @Inject constructor( } private fun getLibrary() { - _isLoading.value = true + library.categories.value = LibraryState.Loading getCategories.asFlow() .onEach { categories -> if (categories.isEmpty()) { throw Exception(MR.strings.library_empty.toPlatformString()) } - library.categories.value = categories.sortedBy { it.order } - .toImmutableList() + library.categories.value = LibraryState.Loaded( + categories.sortedBy { it.order } + .toImmutableList() + ) categories.forEach { category -> getMangaListFromCategory.asFlow(category) .onEach { @@ -181,12 +191,10 @@ class LibraryScreenViewModel @Inject constructor( } .launchIn(coroutineScope) } - _isLoading.value = false } .catch { - _error.value = it.message + library.categories.value = LibraryState.Failed(it) log.warn(it) { "Failed to get categories" } - _isLoading.value = false } .launchIn(scope) } @@ -273,7 +281,7 @@ class LibraryScreenViewModel @Inject constructor( .filter { mangaMapEntry -> (mangaMapEntry.value.value as? CategoryState.Loaded)?.items?.value?.firstOrNull { it.id == mangaId } != null } - .map { (id) -> library.categories.value.first { it.id == id } } + .mapNotNull { (id) -> (library.categories.value as? LibraryState.Loaded)?.categories?.first { it.id == id } } } fun removeManga(mangaId: Long) { diff --git a/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/library/components/LibraryScreenContent.kt b/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/library/components/LibraryScreenContent.kt index 2cc46f60..88e8a4b3 100644 --- a/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/library/components/LibraryScreenContent.kt +++ b/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/library/components/LibraryScreenContent.kt @@ -41,7 +41,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.unit.dp import ca.gosyer.jui.domain.base.WebsocketService -import ca.gosyer.jui.domain.category.model.Category import ca.gosyer.jui.domain.library.model.DisplayMode import ca.gosyer.jui.i18n.MR import ca.gosyer.jui.ui.base.navigation.ActionItem @@ -49,8 +48,10 @@ import ca.gosyer.jui.ui.base.navigation.BackHandler import ca.gosyer.jui.ui.base.navigation.OverflowMode import ca.gosyer.jui.ui.base.navigation.Toolbar import ca.gosyer.jui.ui.library.CategoryState +import ca.gosyer.jui.ui.library.LibraryState import ca.gosyer.jui.ui.library.settings.LibrarySheet import ca.gosyer.jui.ui.library.settings.LibrarySideMenu +import ca.gosyer.jui.uicore.components.ErrorScreen import ca.gosyer.jui.uicore.components.LoadingScreen import ca.gosyer.jui.uicore.insets.navigationBars import ca.gosyer.jui.uicore.insets.statusBars @@ -60,13 +61,11 @@ import kotlinx.collections.immutable.toImmutableList @Composable fun LibraryScreenContent( - categories: ImmutableList, + categories: LibraryState, selectedCategoryIndex: Int, displayMode: DisplayMode, gridColumns: Int, gridSize: Int, - isLoading: Boolean, - error: String?, query: String, updateQuery: (String) -> Unit, getLibraryForPage: @Composable (Long) -> State, @@ -110,8 +109,6 @@ fun LibraryScreenContent( displayMode = displayMode, gridColumns = gridColumns, gridSize = gridSize, - isLoading = isLoading, - error = error, query = query, updateQuery = updateQuery, getLibraryForPage = getLibraryForPage, @@ -137,8 +134,6 @@ fun LibraryScreenContent( displayMode = displayMode, gridColumns = gridColumns, gridSize = gridSize, - isLoading = isLoading, - error = error, query = query, updateQuery = updateQuery, getLibraryForPage = getLibraryForPage, @@ -165,13 +160,11 @@ fun LibraryScreenContent( @Composable fun WideLibraryScreenContent( pagerState: PagerState, - categories: ImmutableList, + categories: LibraryState, selectedCategoryIndex: Int, displayMode: DisplayMode, gridColumns: Int, gridSize: Int, - isLoading: Boolean, - error: String?, query: String, updateQuery: (String) -> Unit, getLibraryForPage: @Composable (Long) -> State, @@ -208,57 +201,65 @@ fun WideLibraryScreenContent( ) }, ) - LibraryTabs( - visible = true, // vm.showCategoryTabs, - pagerState = pagerState, - categories = categories, - selectedPage = selectedCategoryIndex, - onPageChanged = onPageChanged, - ) + if (categories is LibraryState.Loaded) { + LibraryTabs( + visible = true, // vm.showCategoryTabs, + pagerState = pagerState, + categories = categories.categories, + selectedPage = selectedCategoryIndex, + onPageChanged = onPageChanged, + ) + } } }, ) { padding -> Box(Modifier.padding(padding)) { - if (categories.isEmpty()) { - LoadingScreen(isLoading, errorMessage = error) - } else { - LibraryPager( - pagerState = pagerState, - categories = categories, - displayMode = displayMode, - gridColumns = gridColumns, - gridSize = gridSize, - getLibraryForPage = getLibraryForPage, - onClickManga = onClickManga, - onRemoveMangaClicked = onRemoveMangaClicked, - showUnread = showUnread, - showDownloaded = showDownloaded, - showLanguage = showLanguage, - showLocal = showLocal, - ) - - if (showingMenu) { - Box( - Modifier.fillMaxSize().pointerInput(isLoading) { - forEachGesture { - detectTapGestures { - setShowingMenu(false) - } - } - }, - ) + when (categories) { + is LibraryState.Failed -> { + ErrorScreen(categories.e.message) } - AnimatedVisibility( - showingMenu, - enter = fadeIn() + slideInHorizontally(initialOffsetX = { it * 2 }), - exit = fadeOut() + slideOutHorizontally(targetOffsetX = { it * 2 }), - modifier = Modifier.align(Alignment.TopEnd), - ) { - LibrarySideMenu( - libraryFilters = libraryFilters, - librarySort = librarySort, - libraryDisplay = libraryDisplay, + LibraryState.Loading -> { + LoadingScreen(true) + } + is LibraryState.Loaded -> { + LibraryPager( + pagerState = pagerState, + categories = categories.categories, + displayMode = displayMode, + gridColumns = gridColumns, + gridSize = gridSize, + getLibraryForPage = getLibraryForPage, + onClickManga = onClickManga, + onRemoveMangaClicked = onRemoveMangaClicked, + showUnread = showUnread, + showDownloaded = showDownloaded, + showLanguage = showLanguage, + showLocal = showLocal, ) + + if (showingMenu) { + Box( + Modifier.fillMaxSize().pointerInput(Unit) { + forEachGesture { + detectTapGestures { + setShowingMenu(false) + } + } + }, + ) + } + AnimatedVisibility( + showingMenu, + enter = fadeIn() + slideInHorizontally(initialOffsetX = { it * 2 }), + exit = fadeOut() + slideOutHorizontally(targetOffsetX = { it * 2 }), + modifier = Modifier.align(Alignment.TopEnd), + ) { + LibrarySideMenu( + libraryFilters = libraryFilters, + librarySort = librarySort, + libraryDisplay = libraryDisplay, + ) + } } } } @@ -268,13 +269,11 @@ fun WideLibraryScreenContent( @Composable fun ThinLibraryScreenContent( pagerState: PagerState, - categories: ImmutableList, + categories: LibraryState, selectedCategoryIndex: Int, displayMode: DisplayMode, gridColumns: Int, gridSize: Int, - isLoading: Boolean, - error: String?, query: String, updateQuery: (String) -> Unit, getLibraryForPage: @Composable (Long) -> State, @@ -334,13 +333,15 @@ fun ThinLibraryScreenContent( ) }, ) - LibraryTabs( - visible = true, // vm.showCategoryTabs, - pagerState = pagerState, - categories = categories, - selectedPage = selectedCategoryIndex, - onPageChanged = onPageChanged, - ) + if (categories is LibraryState.Loaded) { + LibraryTabs( + visible = true, // vm.showCategoryTabs, + pagerState = pagerState, + categories = categories.categories, + selectedPage = selectedCategoryIndex, + onPageChanged = onPageChanged, + ) + } } }, ) { padding -> @@ -355,23 +356,29 @@ fun ThinLibraryScreenContent( ) }, ) { - if (categories.isEmpty()) { - LoadingScreen(isLoading, errorMessage = error) - } else { - LibraryPager( - pagerState = pagerState, - categories = categories, - displayMode = displayMode, - gridColumns = gridColumns, - gridSize = gridSize, - getLibraryForPage = getLibraryForPage, - onClickManga = onClickManga, - onRemoveMangaClicked = onRemoveMangaClicked, - showUnread = showUnread, - showDownloaded = showDownloaded, - showLanguage = showLanguage, - showLocal = showLocal, - ) + when (categories) { + LibraryState.Loading -> { + LoadingScreen(true) + } + is LibraryState.Failed -> { + ErrorScreen(categories.e.message) + } + is LibraryState.Loaded -> { + LibraryPager( + pagerState = pagerState, + categories = categories.categories, + displayMode = displayMode, + gridColumns = gridColumns, + gridSize = gridSize, + getLibraryForPage = getLibraryForPage, + onClickManga = onClickManga, + onRemoveMangaClicked = onRemoveMangaClicked, + showUnread = showUnread, + showDownloaded = showDownloaded, + showLanguage = showLanguage, + showLocal = showLocal, + ) + } } } }