Several small fixes (#1612)

## Description
- Fixes showing "null" in the subtitle for some tv episodes (usually
daily shows like Jeopardy)
- Partially fix holding back to return to the previous grid position
(still has focus issues)
- Show/hide tabs on the discover page similar to other pages in the app
- Prevent a warning server-side if a negative playback timestamp is sent

### Related issues
N/A

### Testing
Emulator

## Screenshots
N/A

## AI or LLM usage
None
This commit is contained in:
Damontecres 2026-06-22 18:38:19 -04:00 • committed by GitHub
parent 77d7571276
commit c945e1a472
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 44 additions and 18 deletions

View file

@ -74,6 +74,8 @@ inline fun <T> List<T>.indexOfFirstOrNull(predicate: (T) -> Boolean): Int? {
return if (index >= 0) index else null
}
fun Iterable<CharSequence?>.joinNotBlank(sep: String): String? = filter { it.isNotNullOrBlank() }.letNotEmpty { it.joinToString(sep) }
/**
* Try to call [FocusRequester.requestFocus], but catch & log the exception if something is not configured properly
*/

View file

@ -141,7 +141,7 @@ fun <T : CardGridItem> CardGrid(
{ index: Int ->
if (DEBUG) Timber.v("focusOn: focusedIndex=$currentFocusedIndex, index=$index")
if (index != currentFocusedIndex) {
previouslyFocusedIndex = focusedIndex
previouslyFocusedIndex = currentFocusedIndex
}
focusedIndex = index
}
@ -257,10 +257,11 @@ fun <T : CardGridItem> CardGrid(
val newPosition = previouslyFocusedIndex
if (DEBUG) Timber.d("Back long pressed: newPosition=$newPosition")
if (newPosition > 0) {
focusOn(newPosition)
scope.launch(ExceptionHandler()) {
gridState.scrollToItem(newPosition, -columns)
firstFocus.tryRequestFocus()
pager.getOrNull(newPosition)
gridState.scrollToItem(newPosition)
focusOn(newPosition)
alphabetFocus = true
}
}
return@onKeyEvent true

View file

@ -42,6 +42,7 @@ fun DiscoverPage(
0 -> {
SeerrDiscoverPage(
preferences = preferences,
positionCallback = { showHeader = it.row < 1 },
modifier =
Modifier
.fillMaxSize()
@ -53,6 +54,7 @@ fun DiscoverPage(
1 -> {
SeerrRequestsPage(
focusRequesterOnEmpty = tabDetails.tabFocusRequester,
positionCallback = { columns, index -> showHeader = index < columns },
modifier =
Modifier
.fillMaxSize()
@ -64,6 +66,7 @@ fun DiscoverPage(
2 -> {
DiscoverSearchPage(
preferences = preferences,
positionCallback = { columns, index -> showHeader = index < columns },
modifier =
Modifier
.fillMaxSize()

View file

@ -102,6 +102,7 @@ class DiscoverSearchViewModel
@Composable
fun DiscoverSearchPage(
preferences: UserPreferences,
positionCallback: (columns: Int, position: Int) -> Unit,
modifier: Modifier = Modifier,
viewModel: DiscoverSearchViewModel = hiltViewModel(),
) {
@ -241,7 +242,10 @@ fun DiscoverSearchPage(
onPlayItem = { _, _ -> },
onClickPosition = { position = it.column },
onClickDiscover = onClickDiscover,
positionCallback = { columns, index -> position = index },
positionCallback = { columns, index ->
position = index
positionCallback.invoke(columns, index)
},
modifier = Modifier.fillMaxSize(),
)
}

View file

@ -243,6 +243,7 @@ data class DiscoverState(
@Composable
fun SeerrDiscoverPage(
preferences: UserPreferences,
positionCallback: (RowColumn) -> Unit,
modifier: Modifier = Modifier,
viewModel: SeerrDiscoverViewModel = hiltViewModel(),
) {
@ -335,12 +336,16 @@ fun SeerrDiscoverPage(
viewModel.navigationManager.navigateTo(item.destination)
},
onLongClickItem = { index, item -> },
onCardFocus = { index -> position = RowColumn(rowIndex, index) },
onCardFocus = { index ->
position = RowColumn(rowIndex, index)
positionCallback.invoke(position)
},
focusRequester = focusRequesters[rowIndex],
enableViewMore = row.type != DiscoverRequestType.UNKNOWN,
onClickViewMore = {
(row.items as? DataLoadingState.Success<List<DiscoverItem>>)?.data?.size?.let {
position = RowColumn(rowIndex, it)
positionCallback.invoke(position)
}
viewModel.navigationManager.navigateTo(
Destination.DiscoverMoreResult(row.type),

View file

@ -148,10 +148,12 @@ data class RequestGridItem(
@Composable
fun SeerrRequestsPage(
focusRequesterOnEmpty: FocusRequester?,
positionCallback: (columns: Int, position: Int) -> Unit,
modifier: Modifier = Modifier,
viewModel: SeerrRequestsViewModel = hiltViewModel(),
) {
val state by viewModel.state.collectAsState(SeerrRequestsState.EMPTY)
val columns = 6
when (val state = state.requests) {
is DataLoadingState.Error -> {
@ -213,7 +215,8 @@ fun SeerrRequestsPage(
modifier = mod,
)
},
columns = 6,
columns = columns,
positionCallback = positionCallback,
modifier = Modifier.fillMaxSize(),
)
}

View file

@ -338,12 +338,15 @@ class PlayExternalViewModel
}
}
Timber.v("Result position: %s", position?.milliseconds)
if (position != null && position < 0L) {
Timber.w("Unknown stop position for external playback")
}
if (position != null || result.data?.action != null) {
api.playStateApi.reportPlaybackStopped(
PlaybackStopInfo(
itemId = itemId,
mediaSourceId = mediaSourceId,
positionTicks = position?.milliseconds?.inWholeTicks,
positionTicks = position?.milliseconds?.inWholeTicks?.takeIf { it >= 0 },
failed = false,
),
)