From 03b332e4c423e9fa05b08a39a2488fc29f79fc1b Mon Sep 17 00:00:00 2001 From: Ray <154766448+damontecres@users.noreply.github.com> Date: Fri, 16 Jan 2026 13:43:59 -0500 Subject: [PATCH] Fixes a few discover page UI bugs (#710) ## Description - Fixes when to show/hide Request & Cancel buttons - Removes the More button - Uses a larger 16x9 backdrop so that the fade is better - Fix reloading the backdrop on series pages ### Related issues Fixes #706 --- .../wholphin/data/model/DiscoverItem.kt | 2 +- .../detail/discover/DiscoverMovieDetails.kt | 12 ++------ .../detail/discover/DiscoverMovieViewModel.kt | 28 +++++++++++++++++++ .../detail/discover/DiscoverSeriesDetails.kt | 12 ++------ .../discover/DiscoverSeriesViewModel.kt | 14 ++++++++++ .../discover/ExpandableDiscoverButtons.kt | 22 +++++++-------- .../ui/detail/series/SeriesDetails.kt | 6 ++-- .../ui/detail/series/SeriesOverview.kt | 6 ++-- .../ui/detail/series/SeriesViewModel.kt | 18 ++++++------ 9 files changed, 73 insertions(+), 47 deletions(-) diff --git a/app/src/main/java/com/github/damontecres/wholphin/data/model/DiscoverItem.kt b/app/src/main/java/com/github/damontecres/wholphin/data/model/DiscoverItem.kt index ed121277..a274caa1 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/data/model/DiscoverItem.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/data/model/DiscoverItem.kt @@ -91,7 +91,7 @@ data class DiscoverItem( override val playable: Boolean = false override val sortName: String get() = title ?: "" - val backDropUrl: String? get() = backdropPath?.let { "https://image.tmdb.org/t/p/w1920_and_h800_multi_faces$it" } + val backDropUrl: String? get() = backdropPath?.let { "https://image.tmdb.org/t/p/w1920_and_h1080_multi_faces$it" } val posterUrl: String? get() = posterPath?.let { "https://image.tmdb.org/t/p/w500$it" } val destination: Destination diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/discover/DiscoverMovieDetails.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/discover/DiscoverMovieDetails.kt index 264af8cf..9ddf4bc3 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/discover/DiscoverMovieDetails.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/discover/DiscoverMovieDetails.kt @@ -94,6 +94,7 @@ fun DiscoverMovieDetails( val loading by viewModel.loading.observeAsState(LoadingState.Loading) val userConfig by viewModel.userConfig.collectAsState(null) val request4kEnabled by viewModel.request4kEnabled.collectAsState(false) + val canCancel by viewModel.canCancelRequest.collectAsState() var overviewDialog by remember { mutableStateOf(null) } var moreDialog by remember { mutableStateOf(null) } @@ -127,6 +128,7 @@ fun DiscoverMovieDetails( movie = movie, userConfig = userConfig, rating = rating, + canCancel = canCancel, people = people, trailers = trailers, similar = similar, @@ -234,6 +236,7 @@ fun DiscoverMovieDetailsContent( userConfig: SeerrUserConfig?, movie: MovieDetails, rating: DiscoverRating?, + canCancel: Boolean, people: List, trailers: List, similar: List, @@ -284,15 +287,6 @@ fun DiscoverMovieDetailsContent( .fillMaxWidth() .padding(top = 32.dp, bottom = 16.dp), ) - val canCancel = - remember(movie, userConfig) { - ( - // User requested this - userConfig.hasPermission(SeerrPermission.REQUEST) && - movie.mediaInfo?.requests?.any { it.requestedBy?.id == userConfig?.id } == true - ) || - userConfig.hasPermission(SeerrPermission.MANAGE_REQUESTS) - } ExpandableDiscoverButtons( availability = SeerrAvailability.from(movie.mediaInfo?.status) diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/discover/DiscoverMovieViewModel.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/discover/DiscoverMovieViewModel.kt index 1e55d1f6..d10a03dc 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/discover/DiscoverMovieViewModel.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/discover/DiscoverMovieViewModel.kt @@ -4,6 +4,7 @@ import android.content.Context import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.github.damontecres.wholphin.api.seerr.model.MediaRequest import com.github.damontecres.wholphin.api.seerr.model.MovieDetails import com.github.damontecres.wholphin.api.seerr.model.RelatedVideo import com.github.damontecres.wholphin.api.seerr.model.RequestPostRequest @@ -11,11 +12,14 @@ import com.github.damontecres.wholphin.data.ServerRepository import com.github.damontecres.wholphin.data.model.DiscoverItem import com.github.damontecres.wholphin.data.model.DiscoverRating import com.github.damontecres.wholphin.data.model.RemoteTrailer +import com.github.damontecres.wholphin.data.model.SeerrPermission import com.github.damontecres.wholphin.data.model.Trailer +import com.github.damontecres.wholphin.data.model.hasPermission import com.github.damontecres.wholphin.services.BackdropService import com.github.damontecres.wholphin.services.NavigationManager import com.github.damontecres.wholphin.services.SeerrServerRepository import com.github.damontecres.wholphin.services.SeerrService +import com.github.damontecres.wholphin.services.SeerrUserConfig import com.github.damontecres.wholphin.ui.isNotNullOrBlank import com.github.damontecres.wholphin.ui.launchIO import com.github.damontecres.wholphin.ui.nav.Destination @@ -31,7 +35,10 @@ import kotlinx.coroutines.Deferred import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.async +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.jellyfin.sdk.api.client.ApiClient @@ -62,6 +69,7 @@ class DiscoverMovieViewModel val people = MutableLiveData>(listOf()) val similar = MutableLiveData>(listOf()) val recommended = MutableLiveData>(listOf()) + val canCancelRequest = MutableStateFlow(false) val userConfig = seerrServerRepository.current.map { it?.config } val request4kEnabled = seerrServerRepository.current.map { it?.request4kMovieEnabled ?: false } @@ -95,6 +103,8 @@ class DiscoverMovieViewModel val discoveredItem = DiscoverItem(movie) backdropService.submit(discoveredItem) + updateCanCancel() + withContext(Dispatchers.Main) { loading.value = LoadingState.Success } @@ -142,6 +152,12 @@ class DiscoverMovieViewModel this@DiscoverMovieViewModel.trailers.setValueOnMain(trailers) } + private suspend fun updateCanCancel() { + val user = userConfig.firstOrNull() + val canCancel = canUserCancelRequest(user, movie.value?.mediaInfo?.requests) + canCancelRequest.update { canCancel } + } + fun navigateTo(destination: Destination) { navigationManager.navigateTo(destination) } @@ -160,6 +176,7 @@ class DiscoverMovieViewModel ), ) fetchAndSetItem().await() + updateCanCancel() } } @@ -169,7 +186,18 @@ class DiscoverMovieViewModel // TODO handle multiple requests? Or just delete self's request? seerrService.api.requestApi.requestRequestIdDelete(it.id.toString()) fetchAndSetItem().await() + updateCanCancel() } } } } + +fun canUserCancelRequest( + user: SeerrUserConfig?, + requests: List?, +) = user.hasPermission(SeerrPermission.MANAGE_REQUESTS) || + ( + // User requested this + user.hasPermission(SeerrPermission.REQUEST) && + requests?.any { it.requestedBy?.id == user?.id } == true + ) diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/discover/DiscoverSeriesDetails.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/discover/DiscoverSeriesDetails.kt index 22bd8df2..2cf93e8b 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/discover/DiscoverSeriesDetails.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/discover/DiscoverSeriesDetails.kt @@ -93,6 +93,7 @@ fun DiscoverSeriesDetails( val recommended by viewModel.recommended.observeAsState(listOf()) val userConfig by viewModel.userConfig.collectAsState(null) val request4kEnabled by viewModel.request4kEnabled.collectAsState(false) + val canCancel by viewModel.canCancelRequest.collectAsState() var overviewDialog by remember { mutableStateOf(null) } var seasonDialog by remember { mutableStateOf(null) } @@ -120,6 +121,7 @@ fun DiscoverSeriesDetails( series = item, userConfig = userConfig, rating = rating, + canCancel = canCancel, seasons = seasons, people = people, similar = similar, @@ -230,6 +232,7 @@ fun DiscoverSeriesDetailsContent( userConfig: SeerrUserConfig?, series: TvDetails, rating: DiscoverRating?, + canCancel: Boolean, seasons: List, similar: List, recommended: List, @@ -290,15 +293,6 @@ fun DiscoverSeriesDetailsContent( .fillMaxWidth() .padding(top = 32.dp, bottom = 16.dp), ) - val canCancel = - remember(series, userConfig) { - ( - // User requested this - userConfig.hasPermission(SeerrPermission.REQUEST) && - series.mediaInfo?.requests?.any { it.requestedBy?.id == userConfig?.id } == true - ) || - userConfig.hasPermission(SeerrPermission.MANAGE_REQUESTS) - } ExpandableDiscoverButtons( availability = SeerrAvailability.from(series.mediaInfo?.status) diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/discover/DiscoverSeriesViewModel.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/discover/DiscoverSeriesViewModel.kt index 21c259f0..c2909bdc 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/discover/DiscoverSeriesViewModel.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/discover/DiscoverSeriesViewModel.kt @@ -29,7 +29,10 @@ import kotlinx.coroutines.Deferred import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.async +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.jellyfin.sdk.api.client.ApiClient @@ -61,6 +64,7 @@ class DiscoverSeriesViewModel val people = MutableLiveData>(listOf()) val similar = MutableLiveData>(listOf()) val recommended = MutableLiveData>(listOf()) + val canCancelRequest = MutableStateFlow(false) val userConfig = seerrServerRepository.current.map { it?.config } val request4kEnabled = seerrServerRepository.current.map { it?.request4kMovieEnabled ?: false } @@ -94,6 +98,8 @@ class DiscoverSeriesViewModel val discoveredItem = DiscoverItem(tv) backdropService.submit(discoveredItem) + updateCanCancel() + withContext(Dispatchers.Main) { loading.value = LoadingState.Success } @@ -137,6 +143,12 @@ class DiscoverSeriesViewModel navigationManager.navigateTo(destination) } + private suspend fun updateCanCancel() { + val user = userConfig.firstOrNull() + val canCancel = canUserCancelRequest(user, tvSeries.value?.mediaInfo?.requests) + canCancelRequest.update { canCancel } + } + fun request( id: Int, is4k: Boolean, @@ -152,6 +164,7 @@ class DiscoverSeriesViewModel ), ) fetchAndSetItem().await() + updateCanCancel() } } @@ -161,6 +174,7 @@ class DiscoverSeriesViewModel // TODO handle multiple requests? Or just delete self's request? seerrService.api.requestApi.requestRequestIdDelete(it.id.toString()) fetchAndSetItem().await() + updateCanCancel() } } } diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/discover/ExpandableDiscoverButtons.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/discover/ExpandableDiscoverButtons.kt index 725acbb1..4b73a0b2 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/discover/ExpandableDiscoverButtons.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/discover/ExpandableDiscoverButtons.kt @@ -6,7 +6,6 @@ import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.lazy.LazyRow import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Delete -import androidx.compose.material.icons.filled.MoreVert import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Modifier @@ -140,15 +139,16 @@ fun ExpandableDiscoverButtons( } // More button - item("more") { - ExpandablePlayButton( - R.string.more, - Duration.ZERO, - Icons.Default.MoreVert, - { moreOnClick.invoke() }, - Modifier - .onFocusChanged(buttonOnFocusChanged), - ) - } + // No functionality yet +// item("more") { +// ExpandablePlayButton( +// R.string.more, +// Duration.ZERO, +// Icons.Default.MoreVert, +// { moreOnClick.invoke() }, +// Modifier +// .onFocusChanged(buttonOnFocusChanged), +// ) +// } } } diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/series/SeriesDetails.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/series/SeriesDetails.kt index b938af8e..305c6451 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/series/SeriesDetails.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/series/SeriesDetails.kt @@ -131,10 +131,8 @@ fun SeriesDetails( LoadingState.Success -> { item?.let { item -> LifecycleResumeEffect(destination.itemId) { - viewModel.maybePlayThemeSong( - destination.itemId, - preferences.appPreferences.interfacePreferences.playThemeSongs, - ) + viewModel.onResumePage() + onPauseOrDispose { viewModel.release() } diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/series/SeriesOverview.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/series/SeriesOverview.kt index 718e73dd..d95a5bbb 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/series/SeriesOverview.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/series/SeriesOverview.kt @@ -170,10 +170,8 @@ fun SeriesOverview( "series_overview", ) LifecycleResumeEffect(destination.itemId) { - viewModel.maybePlayThemeSong( - destination.itemId, - preferences.appPreferences.interfacePreferences.playThemeSongs, - ) + viewModel.onResumePage() + onPauseOrDispose { viewModel.release() } diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/series/SeriesViewModel.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/series/SeriesViewModel.kt index 95ce6e14..4e5f33c7 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/series/SeriesViewModel.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/series/SeriesViewModel.kt @@ -13,7 +13,6 @@ import com.github.damontecres.wholphin.data.model.DiscoverItem import com.github.damontecres.wholphin.data.model.ItemPlayback import com.github.damontecres.wholphin.data.model.Person import com.github.damontecres.wholphin.data.model.Trailer -import com.github.damontecres.wholphin.preferences.ThemeSongVolume import com.github.damontecres.wholphin.services.BackdropService import com.github.damontecres.wholphin.services.ExtrasService import com.github.damontecres.wholphin.services.FavoriteWatchManager @@ -222,15 +221,16 @@ class SeriesViewModel } } - /** - * If the series has a theme song & app settings allow, play it - */ - fun maybePlayThemeSong( - seriesId: UUID, - playThemeSongs: ThemeSongVolume, - ) { + fun onResumePage() { viewModelScope.launchIO { - themeSongPlayer.playThemeFor(seriesId, playThemeSongs) + item.value?.let { + backdropService.submit(it) + val playThemeSongs = + userPreferencesService + .getCurrent() + .appPreferences.interfacePreferences.playThemeSongs + themeSongPlayer.playThemeFor(seriesId, playThemeSongs) + } } }