mirror of
https://github.com/JustinZeus/Wholphin.git
synced 2026-07-08 23:51:21 +02:00
Keep grid controls accessible if error occurs (#714)
## Description If an error occurs while fetching data for the grid, leave the controls accessible. This is useful in case a particular sort or filter causes an error because the app remembers those values between page loads. Essentially the error message is shown in place of the grid content instead of the entire tab. ### Related issues Fixes #712
This commit is contained in:
parent
88de065fe0
commit
bbeb42dab9
1 changed files with 184 additions and 173 deletions
|
|
@ -89,10 +89,10 @@ import com.github.damontecres.wholphin.ui.setValueOnMain
|
|||
import com.github.damontecres.wholphin.ui.toServerString
|
||||
import com.github.damontecres.wholphin.ui.tryRequestFocus
|
||||
import com.github.damontecres.wholphin.util.ApiRequestPager
|
||||
import com.github.damontecres.wholphin.util.DataLoadingState
|
||||
import com.github.damontecres.wholphin.util.ExceptionHandler
|
||||
import com.github.damontecres.wholphin.util.GetItemsRequestHandler
|
||||
import com.github.damontecres.wholphin.util.GetPersonsHandler
|
||||
import com.github.damontecres.wholphin.util.LoadingExceptionHandler
|
||||
import com.github.damontecres.wholphin.util.LoadingState
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
|
|
@ -151,9 +151,8 @@ class CollectionFolderViewModel
|
|||
): CollectionFolderViewModel
|
||||
}
|
||||
|
||||
val loading = MutableLiveData<LoadingState>(LoadingState.Loading)
|
||||
val loading = MutableLiveData<DataLoadingState<List<BaseItem?>>>(DataLoadingState.Loading)
|
||||
val backgroundLoading = MutableLiveData<LoadingState>(LoadingState.Loading)
|
||||
val pager = MutableLiveData<List<BaseItem?>>(listOf())
|
||||
val sortAndDirection = MutableLiveData<SortAndDirection>()
|
||||
val filter = MutableLiveData<GetItemsFilter>(GetItemsFilter())
|
||||
val viewOptions = MutableLiveData<ViewOptions>()
|
||||
|
|
@ -165,13 +164,9 @@ class CollectionFolderViewModel
|
|||
}
|
||||
|
||||
init {
|
||||
viewModelScope.launch(
|
||||
LoadingExceptionHandler(
|
||||
loading,
|
||||
context.getString(R.string.error_loading_collection, itemId),
|
||||
) + Dispatchers.IO,
|
||||
) {
|
||||
viewModelScope.launchIO {
|
||||
super.itemId = itemId
|
||||
try {
|
||||
itemId.toUUIDOrNull()?.let {
|
||||
fetchItem(it)
|
||||
}
|
||||
|
|
@ -199,6 +194,10 @@ class CollectionFolderViewModel
|
|||
}
|
||||
|
||||
loadResults(true, sortAndDirection, recursive, filterToUse, useSeriesForPrimary)
|
||||
} catch (ex: Exception) {
|
||||
Timber.e(ex, "Error during init")
|
||||
loading.setValueOnMain(DataLoadingState.Error(ex))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -269,8 +268,7 @@ class CollectionFolderViewModel
|
|||
viewModelScope.launch(Dispatchers.IO) {
|
||||
withContext(Dispatchers.Main) {
|
||||
if (resetState) {
|
||||
pager.value = listOf()
|
||||
loading.value = LoadingState.Loading
|
||||
loading.value = DataLoadingState.Loading
|
||||
}
|
||||
backgroundLoading.value = LoadingState.Loading
|
||||
this@CollectionFolderViewModel.sortAndDirection.value = sortAndDirection
|
||||
|
|
@ -281,8 +279,7 @@ class CollectionFolderViewModel
|
|||
createPager(sortAndDirection, recursive, filter, useSeriesForPrimary).init()
|
||||
if (newPager.isNotEmpty()) newPager.getBlocking(0)
|
||||
withContext(Dispatchers.Main) {
|
||||
pager.value = newPager
|
||||
loading.value = LoadingState.Success
|
||||
loading.value = DataLoadingState.Success(newPager)
|
||||
backgroundLoading.value = LoadingState.Success
|
||||
}
|
||||
} catch (ex: Exception) {
|
||||
|
|
@ -293,8 +290,7 @@ class CollectionFolderViewModel
|
|||
filter,
|
||||
)
|
||||
withContext(Dispatchers.Main) {
|
||||
loading.value = LoadingState.Error(ex)
|
||||
pager.value = listOf()
|
||||
loading.value = DataLoadingState.Error(ex)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -498,7 +494,9 @@ class CollectionFolderViewModel
|
|||
played: Boolean,
|
||||
) = viewModelScope.launch(ExceptionHandler() + Dispatchers.IO) {
|
||||
favoriteWatchManager.setWatched(itemId, played)
|
||||
(pager.value as? ApiRequestPager<*>)?.refreshItem(position, itemId)
|
||||
(loading.value as? DataLoadingState.Success)?.let {
|
||||
(it.data as? ApiRequestPager<*>)?.refreshItem(position, itemId)
|
||||
}
|
||||
}
|
||||
|
||||
fun setFavorite(
|
||||
|
|
@ -507,7 +505,9 @@ class CollectionFolderViewModel
|
|||
favorite: Boolean,
|
||||
) = viewModelScope.launch(ExceptionHandler() + Dispatchers.IO) {
|
||||
favoriteWatchManager.setFavorite(itemId, favorite)
|
||||
(pager.value as? ApiRequestPager<*>)?.refreshItem(position, itemId)
|
||||
(loading.value as? DataLoadingState.Success)?.let {
|
||||
(it.data as? ApiRequestPager<*>)?.refreshItem(position, itemId)
|
||||
}
|
||||
}
|
||||
|
||||
fun updateBackdrop(item: BaseItem) {
|
||||
|
|
@ -598,7 +598,6 @@ fun CollectionFolderGrid(
|
|||
val loading by viewModel.loading.observeAsState(LoadingState.Loading)
|
||||
val backgroundLoading by viewModel.backgroundLoading.observeAsState(LoadingState.Loading)
|
||||
val item by viewModel.item.observeAsState()
|
||||
val pager by viewModel.pager.observeAsState()
|
||||
val viewOptions by viewModel.viewOptions.observeAsState(defaultViewOptions)
|
||||
|
||||
var moreDialog by remember { mutableStateOf<Optional<PositionItem>>(Optional.absent()) }
|
||||
|
|
@ -606,18 +605,15 @@ fun CollectionFolderGrid(
|
|||
val playlistState by playlistViewModel.playlistState.observeAsState(PlaylistLoadingState.Pending)
|
||||
|
||||
when (val state = loading) {
|
||||
is LoadingState.Error -> {
|
||||
ErrorMessage(state)
|
||||
}
|
||||
|
||||
LoadingState.Loading,
|
||||
LoadingState.Pending,
|
||||
DataLoadingState.Loading,
|
||||
DataLoadingState.Pending,
|
||||
-> {
|
||||
LoadingPage()
|
||||
}
|
||||
|
||||
LoadingState.Success -> {
|
||||
pager?.let { pager ->
|
||||
is DataLoadingState.Error,
|
||||
is DataLoadingState.Success<*>,
|
||||
-> {
|
||||
val title =
|
||||
initialFilter.nameOverride
|
||||
?: item?.name
|
||||
|
|
@ -629,7 +625,7 @@ fun CollectionFolderGrid(
|
|||
initialPosition = viewModel.position,
|
||||
item = item,
|
||||
title = title,
|
||||
pager = pager,
|
||||
loadingState = state as DataLoadingState<List<BaseItem?>>,
|
||||
sortAndDirection = sortAndDirection!!,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
focusRequesterOnEmpty = focusRequesterOnEmpty,
|
||||
|
|
@ -698,7 +694,6 @@ fun CollectionFolderGrid(
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
moreDialog.compose { (position, item) ->
|
||||
DialogPopup(
|
||||
showDialog = true,
|
||||
|
|
@ -755,7 +750,7 @@ fun CollectionFolderGridContent(
|
|||
preferences: UserPreferences,
|
||||
item: BaseItem?,
|
||||
title: String,
|
||||
pager: List<BaseItem?>,
|
||||
loadingState: DataLoadingState<List<BaseItem?>>,
|
||||
sortAndDirection: SortAndDirection,
|
||||
onClickItem: (Int, BaseItem) -> Unit,
|
||||
onLongClickItem: (Int, BaseItem) -> Unit,
|
||||
|
|
@ -781,13 +776,14 @@ fun CollectionFolderGridContent(
|
|||
) {
|
||||
val context = LocalContext.current
|
||||
|
||||
val pager = (loadingState as? DataLoadingState.Success)?.data
|
||||
var showHeader by rememberSaveable { mutableStateOf(true) }
|
||||
var showViewOptions by rememberSaveable { mutableStateOf(false) }
|
||||
var viewOptions by remember { mutableStateOf(viewOptions) }
|
||||
val headerRowFocusRequester = remember { FocusRequester() }
|
||||
|
||||
val gridFocusRequester = remember { FocusRequester() }
|
||||
if (pager.isNotEmpty()) {
|
||||
if (pager?.isNotEmpty() == true) {
|
||||
RequestOrRestoreFocus(gridFocusRequester)
|
||||
} else {
|
||||
LaunchedEffect(Unit) {
|
||||
|
|
@ -797,7 +793,7 @@ fun CollectionFolderGridContent(
|
|||
var backdropImageUrl by remember { mutableStateOf<String?>(null) }
|
||||
|
||||
var position by rememberInt(initialPosition)
|
||||
val focusedItem = pager.getOrNull(position)
|
||||
val focusedItem = pager?.getOrNull(position)
|
||||
if (viewOptions.showDetails) {
|
||||
LaunchedEffect(focusedItem) {
|
||||
focusedItem?.let(onChangeBackdrop)
|
||||
|
|
@ -810,7 +806,7 @@ fun CollectionFolderGridContent(
|
|||
modifier = Modifier.fillMaxSize(),
|
||||
) {
|
||||
AnimatedVisibility(
|
||||
showHeader,
|
||||
showHeader || loadingState !is DataLoadingState.Success,
|
||||
enter = slideInVertically() + fadeIn(),
|
||||
exit = slideOutVertically() + fadeOut(),
|
||||
) {
|
||||
|
|
@ -871,7 +867,7 @@ fun CollectionFolderGridContent(
|
|||
)
|
||||
}
|
||||
}
|
||||
if (playEnabled) {
|
||||
if (playEnabled && pager?.isNotEmpty() == true) {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
|
|
@ -903,8 +899,21 @@ fun CollectionFolderGridContent(
|
|||
.padding(16.dp),
|
||||
)
|
||||
}
|
||||
when (val state = loadingState) {
|
||||
DataLoadingState.Pending,
|
||||
DataLoadingState.Loading,
|
||||
-> {
|
||||
// This shouldn't happen, so just show placeholder
|
||||
Text("Loading")
|
||||
}
|
||||
|
||||
is DataLoadingState.Error -> {
|
||||
ErrorMessage(state.message, state.exception)
|
||||
}
|
||||
|
||||
is DataLoadingState.Success<List<BaseItem?>> -> {
|
||||
CardGrid(
|
||||
pager = pager,
|
||||
pager = state.data,
|
||||
onClickItem = onClickItem,
|
||||
onLongClickItem = onLongClickItem,
|
||||
onClickPlay = onClickPlay,
|
||||
|
|
@ -947,6 +956,8 @@ fun CollectionFolderGridContent(
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class PositionItem(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue