mirror of
https://github.com/JustinZeus/Wholphin.git
synced 2026-07-08 23:51:21 +02:00
Discover on person page
This commit is contained in:
parent
e7060cedfd
commit
d454cf0e3d
4 changed files with 112 additions and 0 deletions
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
package com.github.damontecres.wholphin.data.model
|
||||
|
||||
import com.github.damontecres.wholphin.api.seerr.model.CreditCast
|
||||
import com.github.damontecres.wholphin.api.seerr.model.CreditCrew
|
||||
import com.github.damontecres.wholphin.api.seerr.model.MovieDetails
|
||||
import com.github.damontecres.wholphin.api.seerr.model.MovieMovieIdRatingsGet200Response
|
||||
import com.github.damontecres.wholphin.api.seerr.model.MovieResult
|
||||
|
|
@ -164,6 +166,36 @@ data class DiscoverItem(
|
|||
backdropPath = search.backdropPath,
|
||||
jellyfinItemId = search.mediaInfo?.jellyfinMediaId?.toUUIDOrNull(),
|
||||
)
|
||||
|
||||
constructor(credit: CreditCast) : this(
|
||||
id = credit.id!!,
|
||||
type = SeerrItemType.TV,
|
||||
title = credit.name,
|
||||
subtitle = null,
|
||||
overview = credit.overview,
|
||||
availability =
|
||||
SeerrAvailability.from(credit.mediaInfo?.status)
|
||||
?: SeerrAvailability.UNKNOWN,
|
||||
releaseDate = credit.firstAirDate,
|
||||
posterPath = credit.posterPath,
|
||||
backdropPath = credit.backdropPath,
|
||||
jellyfinItemId = credit.mediaInfo?.jellyfinMediaId?.toUUIDOrNull(),
|
||||
)
|
||||
|
||||
constructor(credit: CreditCrew) : this(
|
||||
id = credit.id!!,
|
||||
type = SeerrItemType.TV,
|
||||
title = credit.name,
|
||||
subtitle = null,
|
||||
overview = credit.overview,
|
||||
availability =
|
||||
SeerrAvailability.from(credit.mediaInfo?.status)
|
||||
?: SeerrAvailability.UNKNOWN,
|
||||
releaseDate = credit.firstAirDate,
|
||||
posterPath = credit.posterPath,
|
||||
backdropPath = credit.backdropPath,
|
||||
jellyfinItemId = credit.mediaInfo?.jellyfinMediaId?.toUUIDOrNull(),
|
||||
)
|
||||
}
|
||||
|
||||
data class DiscoverRating(
|
||||
|
|
|
|||
|
|
@ -64,6 +64,24 @@ class SeerrService
|
|||
?.map(::DiscoverItem)
|
||||
}
|
||||
|
||||
BaseItemKind.PERSON -> {
|
||||
api.personApi
|
||||
.personPersonIdCombinedCreditsGet(personId = it)
|
||||
.let { credits ->
|
||||
val cast =
|
||||
credits.cast
|
||||
?.take(25)
|
||||
?.map(::DiscoverItem)
|
||||
.orEmpty()
|
||||
val crew =
|
||||
credits.crew
|
||||
?.take(25)
|
||||
?.map(::DiscoverItem)
|
||||
.orEmpty()
|
||||
cast + crew
|
||||
}
|
||||
}
|
||||
|
||||
else -> {
|
||||
null
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ val SlimItemFields =
|
|||
|
||||
object Cards {
|
||||
val height2x3 = 172.dp
|
||||
val heightEpisode = height2x3 * .75f
|
||||
val playedPercentHeight = 6.dp
|
||||
val serverUserCircle = height2x3 * .75f
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import androidx.compose.foundation.relocation.bringIntoViewRequester
|
|||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
|
|
@ -40,13 +41,17 @@ import androidx.tv.material3.surfaceColorAtElevation
|
|||
import coil3.compose.AsyncImage
|
||||
import com.github.damontecres.wholphin.R
|
||||
import com.github.damontecres.wholphin.data.model.BaseItem
|
||||
import com.github.damontecres.wholphin.data.model.DiscoverItem
|
||||
import com.github.damontecres.wholphin.preferences.UserPreferences
|
||||
import com.github.damontecres.wholphin.services.FavoriteWatchManager
|
||||
import com.github.damontecres.wholphin.services.NavigationManager
|
||||
import com.github.damontecres.wholphin.services.SeerrService
|
||||
import com.github.damontecres.wholphin.ui.Cards
|
||||
import com.github.damontecres.wholphin.ui.LocalImageUrlService
|
||||
import com.github.damontecres.wholphin.ui.OneTimeLaunchedEffect
|
||||
import com.github.damontecres.wholphin.ui.PreviewTvSpec
|
||||
import com.github.damontecres.wholphin.ui.SlimItemFields
|
||||
import com.github.damontecres.wholphin.ui.cards.SeasonCard
|
||||
import com.github.damontecres.wholphin.ui.components.ErrorMessage
|
||||
import com.github.damontecres.wholphin.ui.components.ExpandableFaButton
|
||||
import com.github.damontecres.wholphin.ui.components.LoadingPage
|
||||
|
|
@ -54,7 +59,11 @@ import com.github.damontecres.wholphin.ui.components.LoadingRow
|
|||
import com.github.damontecres.wholphin.ui.components.OverviewText
|
||||
import com.github.damontecres.wholphin.ui.data.ItemDetailsDialog
|
||||
import com.github.damontecres.wholphin.ui.data.ItemDetailsDialogInfo
|
||||
import com.github.damontecres.wholphin.ui.data.RowColumn
|
||||
import com.github.damontecres.wholphin.ui.discover.DiscoverRow
|
||||
import com.github.damontecres.wholphin.ui.discover.DiscoverRowData
|
||||
import com.github.damontecres.wholphin.ui.formatDate
|
||||
import com.github.damontecres.wholphin.ui.ifElse
|
||||
import com.github.damontecres.wholphin.ui.isNotNullOrBlank
|
||||
import com.github.damontecres.wholphin.ui.launchIO
|
||||
import com.github.damontecres.wholphin.ui.nav.Destination
|
||||
|
|
@ -63,11 +72,14 @@ import com.github.damontecres.wholphin.ui.setValueOnMain
|
|||
import com.github.damontecres.wholphin.ui.theme.WholphinTheme
|
||||
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.GetItemsRequestHandler
|
||||
import com.github.damontecres.wholphin.util.LoadingExceptionHandler
|
||||
import com.github.damontecres.wholphin.util.LoadingState
|
||||
import com.github.damontecres.wholphin.util.RowLoadingState
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import org.jellyfin.sdk.api.client.ApiClient
|
||||
import org.jellyfin.sdk.model.api.BaseItemKind
|
||||
import org.jellyfin.sdk.model.api.ImageType
|
||||
|
|
@ -86,10 +98,12 @@ class PersonViewModel
|
|||
api: ApiClient,
|
||||
val navigationManager: NavigationManager,
|
||||
private val favoriteWatchManager: FavoriteWatchManager,
|
||||
private val seerrService: SeerrService,
|
||||
) : LoadingItemViewModel(api) {
|
||||
val movies = MutableLiveData<RowLoadingState>(RowLoadingState.Pending)
|
||||
val series = MutableLiveData<RowLoadingState>(RowLoadingState.Pending)
|
||||
val episodes = MutableLiveData<RowLoadingState>(RowLoadingState.Pending)
|
||||
val discovered = MutableStateFlow<List<DiscoverItem>>(listOf())
|
||||
|
||||
fun init(itemId: UUID) {
|
||||
viewModelScope.launchIO(
|
||||
|
|
@ -115,6 +129,10 @@ class PersonViewModel
|
|||
} else {
|
||||
episodes.setValueOnMain(RowLoadingState.Success(listOf()))
|
||||
}
|
||||
viewModelScope.launchIO {
|
||||
val results = seerrService.similar(person)
|
||||
discovered.update { results }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -177,6 +195,7 @@ fun PersonPage(
|
|||
val movies by viewModel.movies.observeAsState(RowLoadingState.Pending)
|
||||
val series by viewModel.series.observeAsState(RowLoadingState.Pending)
|
||||
val episodes by viewModel.episodes.observeAsState(RowLoadingState.Pending)
|
||||
val discovered by viewModel.discovered.collectAsState()
|
||||
|
||||
val loading by viewModel.loading.observeAsState(LoadingState.Loading)
|
||||
when (val state = loading) {
|
||||
|
|
@ -215,6 +234,10 @@ fun PersonPage(
|
|||
favoriteOnClick = {
|
||||
viewModel.setFavorite(!person.favorite)
|
||||
},
|
||||
discovered = discovered,
|
||||
onClickDiscover = { index, item ->
|
||||
viewModel.navigationManager.navigateTo(item.destination)
|
||||
},
|
||||
modifier = modifier,
|
||||
)
|
||||
AnimatedVisibility(showOverviewDialog) {
|
||||
|
|
@ -239,6 +262,7 @@ private const val HEADER_ROW = 0
|
|||
private const val MOVIE_ROW = 1
|
||||
private const val SERIES_ROW = 2
|
||||
private const val EPISODE_ROW = 3
|
||||
private const val DISCOVER_ROW = EPISODE_ROW + 1
|
||||
|
||||
@Composable
|
||||
fun PersonPageContent(
|
||||
|
|
@ -253,9 +277,11 @@ fun PersonPageContent(
|
|||
movies: RowLoadingState,
|
||||
series: RowLoadingState,
|
||||
episodes: RowLoadingState,
|
||||
discovered: List<DiscoverItem>,
|
||||
onClickItem: (Int, BaseItem) -> Unit,
|
||||
overviewOnClick: () -> Unit,
|
||||
favoriteOnClick: () -> Unit,
|
||||
onClickDiscover: (Int, DiscoverItem) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
|
|
@ -336,7 +362,42 @@ fun PersonPageContent(
|
|||
showIfEmpty = false,
|
||||
horizontalPadding = 32.dp,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
cardContent = { index, item, mod, onClick, onLongClick ->
|
||||
SeasonCard(
|
||||
item = item,
|
||||
onClick = {
|
||||
position = RowColumn(EPISODE_ROW, index)
|
||||
onClick.invoke()
|
||||
},
|
||||
onLongClick = onLongClick,
|
||||
imageHeight = Cards.heightEpisode,
|
||||
modifier =
|
||||
mod
|
||||
.ifElse(
|
||||
position.row == EPISODE_ROW && position.column == index,
|
||||
Modifier.focusRequester(focusRequester),
|
||||
),
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
if (discovered.isNotEmpty()) {
|
||||
item {
|
||||
DiscoverRow(
|
||||
row =
|
||||
DiscoverRowData(
|
||||
stringResource(R.string.discover),
|
||||
DataLoadingState.Success(discovered),
|
||||
),
|
||||
onClickItem = { index: Int, item: DiscoverItem ->
|
||||
position = RowColumn(DISCOVER_ROW, index)
|
||||
onClickDiscover.invoke(index, item)
|
||||
},
|
||||
onLongClickItem = { _, _ -> },
|
||||
onCardFocus = {},
|
||||
focusRequester = focusRequester,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue