Fix card overlays showing, fix home page refresh indicator (#1178)

## Description
- Always show card overlays (ie Movie vs TV Show) for discover/Seerr
cards
- Show card overlays (ie favorite and watched status) for search result
cards
- Restore showing home page refresh indicator

### Related issues
Closes #1141
Closes
https://github.com/damontecres/Wholphin/issues/702#issuecomment-4114775539

### Testing
Emulator

## Screenshots
N/A, no new UIs, just adding existing ones

## AI or LLM usage
None
This commit is contained in:
Ray 2026-03-31 23:45:00 -04:00 committed by GitHub
parent 762a5e6dcc
commit 7ccef6f802
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 34 additions and 25 deletions

View file

@ -16,7 +16,6 @@ import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.NonRestartableComposable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
@ -50,13 +49,12 @@ import com.github.damontecres.wholphin.ui.theme.WholphinTheme
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
@Composable @Composable
@NonRestartableComposable
fun DiscoverItemCard( fun DiscoverItemCard(
item: DiscoverItem?, item: DiscoverItem?,
onClick: () -> Unit, onClick: () -> Unit,
onLongClick: () -> Unit, onLongClick: () -> Unit,
showOverlay: Boolean,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
showOverlay: Boolean = true,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
) { ) {
val focused by interactionSource.collectIsFocusedAsState() val focused by interactionSource.collectIsFocusedAsState()

View file

@ -45,6 +45,7 @@ fun EpisodeCard(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
imageHeight: Dp = Dp.Unspecified, imageHeight: Dp = Dp.Unspecified,
imageWidth: Dp = Dp.Unspecified, imageWidth: Dp = Dp.Unspecified,
showImageOverlay: Boolean = false,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
) { ) {
val dto = item?.data val dto = item?.data
@ -94,7 +95,7 @@ fun EpisodeCard(
ItemCardImage( ItemCardImage(
item = item, item = item,
name = item?.name, name = item?.name,
showOverlay = false, showOverlay = showImageOverlay,
favorite = dto?.userData?.isFavorite ?: false, favorite = dto?.userData?.isFavorite ?: false,
watched = dto?.userData?.played ?: false, watched = dto?.userData?.played ?: false,
unwatchedCount = dto?.userData?.unplayedItemCount ?: -1, unwatchedCount = dto?.userData?.unplayedItemCount ?: -1,

View file

@ -341,7 +341,7 @@ fun DiscoverMovieDetailsContent(
item = item, item = item,
onClick = onClick, onClick = onClick,
onLongClick = onLongClick, onLongClick = onLongClick,
showOverlay = false, showOverlay = true,
modifier = mod, modifier = mod,
) )
}, },

View file

@ -378,7 +378,7 @@ fun DiscoverSeriesDetailsContent(
item = item, item = item,
onClick = onClick, onClick = onClick,
onLongClick = onLongClick, onLongClick = onLongClick,
showOverlay = false, showOverlay = true,
modifier = mod, modifier = mod,
) )
}, },

View file

@ -342,7 +342,7 @@ fun DiscoverRow(
item = item, item = item,
onClick = onClick, onClick = onClick,
onLongClick = onLongClick, onLongClick = onLongClick,
showOverlay = false, showOverlay = true,
modifier = modifier =
mod.onFocusChanged { mod.onFocusChanged {
if (it.isFocused) { if (it.isFocused) {

View file

@ -85,7 +85,13 @@ class HomeViewModel
val refresh = val refresh =
state.loadingState == LoadingState.Success && state.settings == settings state.loadingState == LoadingState.Success && state.settings == settings
Timber.v("refresh=$refresh, state.loadingState=${state.loadingState}") Timber.v("refresh=$refresh, state.loadingState=${state.loadingState}")
_state.update { it.copy(settings = settings) } _state.update {
it.copy(
loadingState = if (refresh) LoadingState.Success else LoadingState.Loading,
refreshState = LoadingState.Loading,
settings = settings,
)
}
val semaphore = Semaphore(4) val semaphore = Semaphore(4)

View file

@ -1,6 +1,7 @@
package com.github.damontecres.wholphin.ui.main package com.github.damontecres.wholphin.ui.main
import androidx.activity.compose.BackHandler import androidx.activity.compose.BackHandler
import androidx.annotation.StringRes
import androidx.compose.foundation.focusGroup import androidx.compose.foundation.focusGroup
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
@ -32,7 +33,6 @@ import androidx.compose.ui.input.key.KeyEventType
import androidx.compose.ui.input.key.key import androidx.compose.ui.input.key.key
import androidx.compose.ui.input.key.onPreviewKeyEvent import androidx.compose.ui.input.key.onPreviewKeyEvent
import androidx.compose.ui.input.key.type import androidx.compose.ui.input.key.type
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
@ -232,7 +232,6 @@ fun SearchPage(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
viewModel: SearchViewModel = hiltViewModel(), viewModel: SearchViewModel = hiltViewModel(),
) { ) {
val context = LocalContext.current
val focusManager = LocalFocusManager.current val focusManager = LocalFocusManager.current
val keyboardController = LocalSoftwareKeyboardController.current val keyboardController = LocalSoftwareKeyboardController.current
val movies by viewModel.movies.observeAsState(SearchResult.NoQuery) val movies by viewModel.movies.observeAsState(SearchResult.NoQuery)
@ -377,7 +376,7 @@ fun SearchPage(
} }
} }
searchResultRow( searchResultRow(
title = context.getString(R.string.movies), title = R.string.movies,
result = movies, result = movies,
rowIndex = MOVIE_ROW, rowIndex = MOVIE_ROW,
position = position, position = position,
@ -387,7 +386,7 @@ fun SearchPage(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
) )
searchResultRow( searchResultRow(
title = context.getString(R.string.tv_shows), title = R.string.tv_shows,
result = series, result = series,
rowIndex = SERIES_ROW, rowIndex = SERIES_ROW,
position = position, position = position,
@ -397,7 +396,7 @@ fun SearchPage(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
) )
searchResultRow( searchResultRow(
title = context.getString(R.string.episodes), title = R.string.episodes,
result = episodes, result = episodes,
rowIndex = EPISODE_ROW, rowIndex = EPISODE_ROW,
position = position, position = position,
@ -414,12 +413,13 @@ fun SearchPage(
}, },
onLongClick = onLongClick, onLongClick = onLongClick,
imageHeight = 140.dp, imageHeight = 140.dp,
showImageOverlay = true,
modifier = mod.padding(horizontal = 8.dp), modifier = mod.padding(horizontal = 8.dp),
) )
}, },
) )
searchResultRow( searchResultRow(
title = context.getString(R.string.albums), title = R.string.albums,
result = albums, result = albums,
rowIndex = ALBUM_ROW, rowIndex = ALBUM_ROW,
position = position, position = position,
@ -437,12 +437,13 @@ fun SearchPage(
onLongClick = onLongClick, onLongClick = onLongClick,
imageHeight = Cards.heightEpisode, imageHeight = Cards.heightEpisode,
aspectRatio = AspectRatios.SQUARE, aspectRatio = AspectRatios.SQUARE,
showImageOverlay = true,
modifier = mod, modifier = mod,
) )
}, },
) )
searchResultRow( searchResultRow(
title = context.getString(R.string.artists), title = R.string.artists,
result = artists, result = artists,
rowIndex = COLLECTION_ROW, rowIndex = COLLECTION_ROW,
position = position, position = position,
@ -460,12 +461,13 @@ fun SearchPage(
onLongClick = onLongClick, onLongClick = onLongClick,
imageHeight = Cards.heightEpisode, imageHeight = Cards.heightEpisode,
aspectRatio = AspectRatios.SQUARE, aspectRatio = AspectRatios.SQUARE,
showImageOverlay = true,
modifier = mod, modifier = mod,
) )
}, },
) )
searchResultRow( searchResultRow(
title = context.getString(R.string.songs), title = R.string.songs,
result = songs, result = songs,
rowIndex = SONG_ROW, rowIndex = SONG_ROW,
position = position, position = position,
@ -483,12 +485,13 @@ fun SearchPage(
onLongClick = onLongClick, onLongClick = onLongClick,
imageHeight = Cards.heightEpisode, imageHeight = Cards.heightEpisode,
aspectRatio = AspectRatios.SQUARE, aspectRatio = AspectRatios.SQUARE,
showImageOverlay = true,
modifier = mod, modifier = mod,
) )
}, },
) )
searchResultRow( searchResultRow(
title = context.getString(R.string.collections), title = R.string.collections,
result = collections, result = collections,
rowIndex = COLLECTION_ROW, rowIndex = COLLECTION_ROW,
position = position, position = position,
@ -498,7 +501,7 @@ fun SearchPage(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
) )
searchResultRow( searchResultRow(
title = context.getString(R.string.discover), title = R.string.discover,
result = seerrResults, result = seerrResults,
rowIndex = SEERR_ROW, rowIndex = SEERR_ROW,
position = position, position = position,
@ -525,7 +528,7 @@ fun SearchPage(
} }
fun LazyListScope.searchResultRow( fun LazyListScope.searchResultRow(
title: String, @StringRes title: Int,
result: SearchResult, result: SearchResult,
rowIndex: Int, rowIndex: Int,
position: RowColumn, position: RowColumn,
@ -549,6 +552,7 @@ fun LazyListScope.searchResultRow(
}, },
onLongClick = onLongClick, onLongClick = onLongClick,
imageHeight = Cards.height2x3, imageHeight = Cards.height2x3,
showImageOverlay = true,
modifier = mod, modifier = mod,
) )
}, },
@ -557,7 +561,7 @@ fun LazyListScope.searchResultRow(
when (val r = result) { when (val r = result) {
is SearchResult.Error -> { is SearchResult.Error -> {
SearchResultPlaceholder( SearchResultPlaceholder(
title = title, title = stringResource(title),
message = r.ex.localizedMessage ?: "Error occurred during search", message = r.ex.localizedMessage ?: "Error occurred during search",
messageColor = MaterialTheme.colorScheme.error, messageColor = MaterialTheme.colorScheme.error,
modifier = Modifier, modifier = Modifier,
@ -570,7 +574,7 @@ fun LazyListScope.searchResultRow(
SearchResult.Searching -> { SearchResult.Searching -> {
SearchResultPlaceholder( SearchResultPlaceholder(
title = title, title = stringResource(title),
message = stringResource(R.string.searching), message = stringResource(R.string.searching),
modifier = modifier, modifier = modifier,
) )
@ -579,13 +583,13 @@ fun LazyListScope.searchResultRow(
is SearchResult.Success -> { is SearchResult.Success -> {
if (r.items.isEmpty()) { if (r.items.isEmpty()) {
SearchResultPlaceholder( SearchResultPlaceholder(
title = title, title = stringResource(title),
message = stringResource(R.string.no_results), message = stringResource(R.string.no_results),
modifier = modifier, modifier = modifier,
) )
} else { } else {
ItemRow( ItemRow(
title = title, title = stringResource(title),
items = r.items, items = r.items,
onClickItem = onClickItem, onClickItem = onClickItem,
onLongClickItem = { _, _ -> }, onLongClickItem = { _, _ -> },
@ -598,13 +602,13 @@ fun LazyListScope.searchResultRow(
is SearchResult.SuccessSeerr -> { is SearchResult.SuccessSeerr -> {
if (r.items.isEmpty()) { if (r.items.isEmpty()) {
SearchResultPlaceholder( SearchResultPlaceholder(
title = title, title = stringResource(title),
message = stringResource(R.string.no_results), message = stringResource(R.string.no_results),
modifier = modifier, modifier = modifier,
) )
} else { } else {
ItemRow( ItemRow(
title = title, title = stringResource(title),
items = r.items, items = r.items,
onClickItem = { index, item -> onClickItem = { index, item ->
onClickPosition.invoke(RowColumn(rowIndex, index)) onClickPosition.invoke(RowColumn(rowIndex, index))