Fixes missing parental ratings & focus loss when changing filters (#1559)

## Description
- Ensures all parent ratings are shown in the filter drop down
- Fixes focus loss after filtering library and there are no results

### Related issues
Fixes #1535 (along w/ #1529)
Fixes #1534

### Testing
Emulator w/ a UK movie library

## Screenshots
N/A

## AI or LLM usage
None
This commit is contained in:
Damontecres 2026-06-10 19:29:49 -04:00 • committed by GitHub
parent 01bd3249fa
commit f7f0ea9cca
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 33 additions and 11 deletions

View file

@ -124,9 +124,9 @@ class FilterOptionCache
parentId = parentId,
userId = userId,
).content.officialRatings
?.mapNotNull { r ->
val value = ratings[r]
value?.let { FilterValueOption(r, value) }
?.map { r ->
val value = ratings[r] ?: 0
FilterValueOption(r, value)
}?.sortedBy { it.value as Int }
.orEmpty()
}

View file

@ -21,6 +21,8 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.focus.focusRestorer
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.text.style.TextAlign
@ -270,6 +272,8 @@ fun CollectionFolderHeader(
currentFilter: GetItemsFilter = GetItemsFilter(),
filterOptions: List<ItemFilterBy<*>> = listOf(),
onFilterChange: (GetItemsFilter) -> Unit = {},
onShowFilterDropdown: ((Boolean) -> Unit)? = null,
filterButtonFocusRequester: FocusRequester = remember { FocusRequester() },
) {
AnimatedVisibility(
showHeader,
@ -292,13 +296,14 @@ fun CollectionFolderHeader(
modifier =
Modifier
.padding(start = 16.dp, end = endPadding)
.focusRestorer()
.fillMaxWidth(),
) {
if (sortOptions.isNotEmpty() || filterOptions.isNotEmpty()) {
Row(
horizontalArrangement = Arrangement.spacedBy(8.dp),
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier,
modifier = Modifier.focusRestorer(),
) {
if (sortOptions.isNotEmpty()) {
SortByButton(
@ -314,7 +319,8 @@ fun CollectionFolderHeader(
current = currentFilter,
onFilterChange = onFilterChange,
getPossibleValues = getPossibleFilterValues,
modifier = Modifier,
modifier = Modifier.focusRequester(filterButtonFocusRequester),
onShow = onShowFilterDropdown,
)
}
ExpandableFaButton(
@ -329,7 +335,7 @@ fun CollectionFolderHeader(
Row(
horizontalArrangement = Arrangement.spacedBy(8.dp),
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier,
modifier = Modifier.focusRestorer(),
) {
ExpandablePlayButton(
title = R.string.play,

View file

@ -659,6 +659,9 @@ fun CollectionFolderView(
val contextMenu = rememberContextMenu(preferences, viewModel)
var showViewOptions by rememberSaveable { mutableStateOf(false) }
var filterDropdownShowing by remember { mutableStateOf(false) }
val headerRowFocusRequester = remember { FocusRequester() }
val filterButtonFocusRequester = remember { FocusRequester() }
val gridActions =
remember(actions) {
@ -741,7 +744,6 @@ fun CollectionFolderView(
?: item?.data?.collectionType?.name
?: stringResource(R.string.collection)
Column(modifier = Modifier.fillMaxSize()) {
val headerRowFocusRequester = remember { FocusRequester() }
LifecycleResumeEffect(itemId) {
viewModel.onResumePage()
@ -780,6 +782,8 @@ fun CollectionFolderView(
onClickPlayAll = gridActions.onClickPlayAll!!,
onClickShowViewOptions = { showViewOptions = true },
modifier = Modifier.focusRequester(headerRowFocusRequester),
onShowFilterDropdown = { filterDropdownShowing = it },
filterButtonFocusRequester = filterButtonFocusRequester,
)
when (val pager = state.items) {
@ -798,9 +802,14 @@ fun CollectionFolderView(
is DataLoadingState.Success<List<BaseItem?>> -> {
LaunchedEffect(Unit) {
if (pager.data.isNotEmpty()) {
gridFocusRequester.tryRequestFocus()
}
val focusRequester =
when {
contextMenu.isShowing -> null
filterDropdownShowing -> filterButtonFocusRequester
pager.data.isNotEmpty() -> gridFocusRequester
else -> focusRequesterOnEmpty ?: headerRowFocusRequester
}
focusRequester?.tryRequestFocus()
}
Box(Modifier.fillMaxSize()) {
if (state.viewOptions.type == ViewOptionsType.GRID) {

View file

@ -36,6 +36,8 @@ class ContextMenuUtils(
) {
private var showContextMenu by mutableStateOf<Pair<Int, BaseItem>?>(null)
val isShowing: Boolean get() = showContextMenu != null
/**
* Show the context menu, typically from a long click
*/

View file

@ -71,6 +71,7 @@ fun FilterByButton(
onFilterChange: (GetItemsFilter) -> Unit,
getPossibleValues: suspend (ItemFilterBy<*>) -> List<FilterValueOption>,
modifier: Modifier = Modifier,
onShow: ((Boolean) -> Unit)? = null,
) {
var dropDown by remember { mutableStateOf(false) }
var nestedDropDown by remember { mutableStateOf<ItemFilterBy<*>?>(null) }
@ -79,7 +80,10 @@ fun FilterByButton(
Box(modifier = modifier) {
ExpandableFilterButton(
filterCount = filterCount,
onClick = { dropDown = true },
onClick = {
onShow?.invoke(true)
dropDown = true
},
modifier = Modifier,
)
@ -87,6 +91,7 @@ fun FilterByButton(
expanded = dropDown,
containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation(3.dp),
onDismissRequest = {
onShow?.invoke(false)
dropDown = false
nestedDropDown = null
},