Add discover person page

This commit is contained in:
Damontecres 2026-01-06 19:17:40 -05:00
parent d175e3f471
commit ec7d012c22
No known key found for this signature in database
10 changed files with 296 additions and 160 deletions

View file

@ -11,6 +11,7 @@ import com.github.damontecres.wholphin.api.seerr.model.TvDetails
import com.github.damontecres.wholphin.api.seerr.model.TvResult
import com.github.damontecres.wholphin.api.seerr.model.TvTvIdRatingsGet200Response
import com.github.damontecres.wholphin.services.SeerrSearchResult
import com.github.damontecres.wholphin.ui.detail.CardGridItem
import com.github.damontecres.wholphin.ui.nav.Destination
import com.github.damontecres.wholphin.ui.toLocalDate
import com.github.damontecres.wholphin.util.LocalDateSerializer
@ -41,13 +42,15 @@ enum class SeerrItemType(
;
companion object {
fun fromString(str: String?) =
when (str) {
"movie" -> MOVIE
"tv" -> TV
"person" -> PERSON
else -> UNKNOWN
}
fun fromString(
str: String?,
fallback: SeerrItemType = UNKNOWN,
) = when (str) {
"movie" -> MOVIE
"tv" -> TV
"person" -> PERSON
else -> fallback
}
}
}
@ -80,7 +83,11 @@ data class DiscoverItem(
val posterPath: String?,
val backdropPath: String?,
val jellyfinItemId: UUID?,
) {
) : CardGridItem {
override val gridId: String get() = id.toString()
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 posterUrl: String? get() = posterPath?.let { "https://image.tmdb.org/t/p/w500$it" }
@ -172,30 +179,30 @@ data class DiscoverItem(
constructor(credit: CreditCast) : this(
id = credit.id!!,
type = SeerrItemType.TV,
title = credit.name,
type = SeerrItemType.fromString(credit.mediaType, SeerrItemType.PERSON),
title = credit.name ?: credit.title,
subtitle = null,
overview = credit.overview,
availability =
SeerrAvailability.from(credit.mediaInfo?.status)
?: SeerrAvailability.UNKNOWN,
releaseDate = toLocalDate(credit.firstAirDate),
posterPath = credit.posterPath,
posterPath = credit.posterPath ?: credit.profilePath,
backdropPath = credit.backdropPath,
jellyfinItemId = credit.mediaInfo?.jellyfinMediaId?.toUUIDOrNull(),
)
constructor(credit: CreditCrew) : this(
id = credit.id!!,
type = SeerrItemType.TV,
title = credit.name,
type = SeerrItemType.fromString(credit.mediaType, SeerrItemType.PERSON),
title = credit.name ?: credit.title,
subtitle = null,
overview = credit.overview,
availability =
SeerrAvailability.from(credit.mediaInfo?.status)
?: SeerrAvailability.UNKNOWN,
releaseDate = toLocalDate(credit.firstAirDate),
posterPath = credit.posterPath,
posterPath = credit.posterPath ?: credit.profilePath,
backdropPath = credit.backdropPath,
jellyfinItemId = credit.mediaInfo?.jellyfinMediaId?.toUUIDOrNull(),
)

View file

@ -374,7 +374,7 @@ fun <T : CardGridItem> CardGrid(
pager
.getOrNull(focusedIndex)
?.sortName
?.first()
?.firstOrNull()
?.uppercaseChar()
?.let {
if (it >= '0' && it <= '9') {

View file

@ -40,7 +40,6 @@ import com.github.damontecres.wholphin.api.seerr.model.MovieDetails
import com.github.damontecres.wholphin.data.model.DiscoverItem
import com.github.damontecres.wholphin.data.model.DiscoverRating
import com.github.damontecres.wholphin.data.model.LocalTrailer
import com.github.damontecres.wholphin.data.model.Person
import com.github.damontecres.wholphin.data.model.RemoteTrailer
import com.github.damontecres.wholphin.data.model.SeerrAvailability
import com.github.damontecres.wholphin.data.model.SeerrPermission
@ -52,7 +51,6 @@ import com.github.damontecres.wholphin.services.TrailerService
import com.github.damontecres.wholphin.ui.Cards
import com.github.damontecres.wholphin.ui.cards.DiscoverItemCard
import com.github.damontecres.wholphin.ui.cards.ItemRow
import com.github.damontecres.wholphin.ui.cards.PersonRow
import com.github.damontecres.wholphin.ui.cards.SeasonCard
import com.github.damontecres.wholphin.ui.components.DialogParams
import com.github.damontecres.wholphin.ui.components.DialogPopup
@ -61,10 +59,12 @@ import com.github.damontecres.wholphin.ui.components.LoadingPage
import com.github.damontecres.wholphin.ui.data.ItemDetailsDialog
import com.github.damontecres.wholphin.ui.data.ItemDetailsDialogInfo
import com.github.damontecres.wholphin.ui.detail.MoreDialogActions
import com.github.damontecres.wholphin.ui.detail.buildMoreDialogItemsForPerson
import com.github.damontecres.wholphin.ui.discover.DiscoverRow
import com.github.damontecres.wholphin.ui.discover.DiscoverRowData
import com.github.damontecres.wholphin.ui.nav.Destination
import com.github.damontecres.wholphin.ui.rememberInt
import com.github.damontecres.wholphin.ui.tryRequestFocus
import com.github.damontecres.wholphin.util.DataLoadingState
import com.github.damontecres.wholphin.util.ExceptionHandler
import com.github.damontecres.wholphin.util.LoadingState
import kotlinx.coroutines.launch
@ -137,7 +137,8 @@ fun DiscoverMovieDetails(
onClickItem = { index, item ->
viewModel.navigateTo(Destination.DiscoveredItem(item))
},
onClickPerson = {
onClickPerson = { item ->
viewModel.navigateTo(Destination.DiscoveredItem(item))
},
overviewOnClick = {
overviewDialog =
@ -166,20 +167,7 @@ fun DiscoverMovieDetails(
items = listOf(),
)
},
onLongClickPerson = { index, person ->
val items =
buildMoreDialogItemsForPerson(
context = context,
person = person,
actions = moreActions,
)
moreDialog =
DialogParams(
fromLongClick = true,
title = person.name ?: "",
items = items,
)
},
onLongClickPerson = { index, person -> },
onLongClickSimilar = { index, similar ->
},
trailerOnClick = {
@ -223,7 +211,7 @@ fun DiscoverMovieDetailsContent(
userConfig: SeerrUserConfig?,
movie: MovieDetails,
rating: DiscoverRating?,
people: List<Person>,
people: List<DiscoverItem>,
trailers: List<Trailer>,
similar: List<DiscoverItem>,
recommended: List<DiscoverItem>,
@ -234,8 +222,8 @@ fun DiscoverMovieDetailsContent(
goToOnClick: () -> Unit,
moreOnClick: () -> Unit,
onClickItem: (Int, DiscoverItem) -> Unit,
onClickPerson: (Person) -> Unit,
onLongClickPerson: (Int, Person) -> Unit,
onClickPerson: (DiscoverItem) -> Unit,
onLongClickPerson: (Int, DiscoverItem) -> Unit,
onLongClickSimilar: (Int, DiscoverItem) -> Unit,
modifier: Modifier = Modifier,
) {
@ -310,20 +298,22 @@ fun DiscoverMovieDetailsContent(
}
if (people.isNotEmpty()) {
item {
PersonRow(
people = people,
onClick = {
DiscoverRow(
row =
DiscoverRowData(
stringResource(R.string.people),
DataLoadingState.Success(people),
),
onClickItem = { index: Int, item: DiscoverItem ->
position = PEOPLE_ROW
onClickPerson.invoke(it)
onClickPerson.invoke(item)
},
onLongClick = { index, person ->
onLongClickItem = { index, person ->
position = PEOPLE_ROW
onLongClickPerson.invoke(index, person)
},
modifier =
Modifier
.fillMaxWidth()
.focusRequester(focusRequesters[PEOPLE_ROW]),
onCardFocus = {},
focusRequester = focusRequesters[PEOPLE_ROW],
)
}
}

View file

@ -10,7 +10,6 @@ import com.github.damontecres.wholphin.api.seerr.model.RequestPostRequest
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.Person
import com.github.damontecres.wholphin.data.model.RemoteTrailer
import com.github.damontecres.wholphin.data.model.Trailer
import com.github.damontecres.wholphin.services.BackdropService
@ -36,8 +35,6 @@ import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.jellyfin.sdk.api.client.ApiClient
import org.jellyfin.sdk.model.UUID
import org.jellyfin.sdk.model.api.PersonKind
@HiltViewModel(assistedFactory = DiscoverMovieViewModel.Factory::class)
class DiscoverMovieViewModel
@ -62,7 +59,7 @@ class DiscoverMovieViewModel
val rating = MutableLiveData<DiscoverRating?>(null)
val trailers = MutableLiveData<List<Trailer>>(listOf())
val people = MutableLiveData<List<Person>>(listOf())
val people = MutableLiveData<List<DiscoverItem>>(listOf())
val similar = MutableLiveData<List<DiscoverItem>>(listOf())
val recommended = MutableLiveData<List<DiscoverItem>>(listOf())
@ -127,28 +124,12 @@ class DiscoverMovieViewModel
val people =
movie.credits
?.cast
?.map {
Person(
id = UUID.randomUUID(),
name = it.name,
role = it.character,
type = PersonKind.UNKNOWN,
imageUrl = "https://image.tmdb.org/t/p/w600_and_h900_bestv2${it.profilePath}",
favorite = false,
)
}.orEmpty() +
?.map(::DiscoverItem)
.orEmpty() +
movie.credits
?.crew
?.map {
Person(
id = UUID.randomUUID(),
name = it.name,
role = it.job,
type = PersonKind.UNKNOWN,
imageUrl = "https://image.tmdb.org/t/p/w600_and_h900_bestv2${it.profilePath}",
favorite = false,
)
}.orEmpty()
?.map(::DiscoverItem)
.orEmpty()
this@DiscoverMovieViewModel.people.setValueOnMain(people)
val trailers =
movie.relatedVideos

View file

@ -0,0 +1,161 @@
package com.github.damontecres.wholphin.ui.detail.discover
import androidx.compose.foundation.focusable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.tv.material3.MaterialTheme
import androidx.tv.material3.Text
import com.github.damontecres.wholphin.R
import com.github.damontecres.wholphin.data.ServerRepository
import com.github.damontecres.wholphin.data.model.DiscoverItem
import com.github.damontecres.wholphin.services.BackdropService
import com.github.damontecres.wholphin.services.NavigationManager
import com.github.damontecres.wholphin.services.SeerrService
import com.github.damontecres.wholphin.ui.cards.DiscoverItemCard
import com.github.damontecres.wholphin.ui.components.ErrorMessage
import com.github.damontecres.wholphin.ui.components.LoadingPage
import com.github.damontecres.wholphin.ui.detail.CardGrid
import com.github.damontecres.wholphin.ui.launchIO
import com.github.damontecres.wholphin.ui.nav.Destination
import com.github.damontecres.wholphin.ui.tryRequestFocus
import com.github.damontecres.wholphin.util.DataLoadingState
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.update
@HiltViewModel(assistedFactory = DiscoverPersonViewModel.Factory::class)
class DiscoverPersonViewModel
@AssistedInject
constructor(
val navigationManager: NavigationManager,
val serverRepository: ServerRepository,
val seerrService: SeerrService,
private val backdropService: BackdropService,
@Assisted val item: DiscoverItem,
) : ViewModel() {
@AssistedFactory
interface Factory {
fun create(item: DiscoverItem): DiscoverPersonViewModel
}
val credits = MutableStateFlow<DataLoadingState<List<DiscoverItem>>>(DataLoadingState.Pending)
init {
viewModelScope.launchIO {
backdropService.clearBackdrop()
val credits =
seerrService.api.personApi
.personPersonIdCombinedCreditsGet(personId = item.id)
.let { credits ->
val cast =
credits.cast
?.map(::DiscoverItem)
.orEmpty()
val crew =
credits.crew
?.map(::DiscoverItem)
.orEmpty()
cast + crew
}
this@DiscoverPersonViewModel.credits.update {
DataLoadingState.Success(credits)
}
}
}
}
@Composable
fun DiscoverPersonPage(
person: DiscoverItem,
modifier: Modifier = Modifier,
viewModel: DiscoverPersonViewModel =
hiltViewModel<DiscoverPersonViewModel, DiscoverPersonViewModel.Factory>(
creationCallback = { it.create(person) },
),
) {
val credits by viewModel.credits.collectAsState()
when (val state = credits) {
is DataLoadingState.Error -> {
ErrorMessage(state.message, state.exception, modifier.focusable())
}
DataLoadingState.Loading,
DataLoadingState.Pending,
-> {
LoadingPage(modifier.focusable())
}
is DataLoadingState.Success<List<DiscoverItem>> -> {
val focusRequester = remember { FocusRequester() }
LaunchedEffect(Unit) {
if (state.data.isNotEmpty()) {
focusRequester.tryRequestFocus()
}
}
Column(modifier = modifier) {
Text(
text = stringResource(R.string.discover) + (person.title?.let { ": $it" } ?: ""),
style = MaterialTheme.typography.displaySmall,
color = MaterialTheme.colorScheme.onBackground,
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth(),
)
if (state.data.isEmpty()) {
Text(
text = stringResource(R.string.no_results),
style = MaterialTheme.typography.titleLarge,
color = MaterialTheme.colorScheme.onBackground,
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxSize(),
)
} else {
CardGrid(
pager = state.data,
onClickItem = { index: Int, item: DiscoverItem ->
viewModel.navigationManager.navigateTo(Destination.DiscoveredItem(item))
},
onLongClickItem = { index: Int, item: DiscoverItem ->
},
onClickPlay = { _, item ->
},
letterPosition = { c: Char -> 0 },
gridFocusRequester = focusRequester,
showJumpButtons = false,
showLetterButtons = false,
spacing = 16.dp,
cardContent = @Composable { item, onClick, onLongClick, mod ->
DiscoverItemCard(
item = item,
onClick = onClick,
onLongClick = onLongClick,
showOverlay = true,
modifier = mod,
)
},
columns = 6,
modifier = Modifier.fillMaxSize(),
)
}
}
}
}
}

View file

@ -40,7 +40,6 @@ import com.github.damontecres.wholphin.api.seerr.model.TvDetails
import com.github.damontecres.wholphin.data.model.BaseItem
import com.github.damontecres.wholphin.data.model.DiscoverItem
import com.github.damontecres.wholphin.data.model.DiscoverRating
import com.github.damontecres.wholphin.data.model.Person
import com.github.damontecres.wholphin.data.model.SeerrAvailability
import com.github.damontecres.wholphin.data.model.SeerrPermission
import com.github.damontecres.wholphin.data.model.Trailer
@ -50,7 +49,6 @@ import com.github.damontecres.wholphin.services.SeerrUserConfig
import com.github.damontecres.wholphin.services.TrailerService
import com.github.damontecres.wholphin.ui.cards.DiscoverItemCard
import com.github.damontecres.wholphin.ui.cards.ItemRow
import com.github.damontecres.wholphin.ui.cards.PersonRow
import com.github.damontecres.wholphin.ui.components.DialogItem
import com.github.damontecres.wholphin.ui.components.DialogParams
import com.github.damontecres.wholphin.ui.components.DialogPopup
@ -61,11 +59,14 @@ import com.github.damontecres.wholphin.ui.components.LoadingPage
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.discover.DiscoverRow
import com.github.damontecres.wholphin.ui.discover.DiscoverRowData
import com.github.damontecres.wholphin.ui.letNotEmpty
import com.github.damontecres.wholphin.ui.nav.Destination
import com.github.damontecres.wholphin.ui.rememberInt
import com.github.damontecres.wholphin.ui.roundMinutes
import com.github.damontecres.wholphin.ui.tryRequestFocus
import com.github.damontecres.wholphin.util.DataLoadingState
import com.github.damontecres.wholphin.util.ExceptionHandler
import com.github.damontecres.wholphin.util.LoadingState
import kotlinx.coroutines.launch
@ -124,12 +125,7 @@ fun DiscoverSeriesDetails(
viewModel.navigateTo(Destination.DiscoveredItem(item))
},
onClickPerson = {
viewModel.navigateTo(
Destination.MediaItem(
it.id,
BaseItemKind.PERSON,
),
)
viewModel.navigateTo(Destination.DiscoveredItem(it))
},
goToOnClick = {
item.mediaInfo?.jellyfinMediaId?.toUUIDOrNull()?.let {
@ -204,7 +200,7 @@ fun DiscoverSeriesDetailsContent(
similar: List<DiscoverItem>,
recommended: List<DiscoverItem>,
trailers: List<Trailer>,
people: List<Person>,
people: List<DiscoverItem>,
requestOnClick: () -> Unit,
cancelOnClick: () -> Unit,
trailerOnClick: (Trailer) -> Unit,
@ -212,8 +208,8 @@ fun DiscoverSeriesDetailsContent(
goToOnClick: () -> Unit,
moreOnClick: () -> Unit,
onClickItem: (Int, DiscoverItem) -> Unit,
onClickPerson: (Person) -> Unit,
onLongClickPerson: (Int, Person) -> Unit,
onClickPerson: (DiscoverItem) -> Unit,
onLongClickPerson: (Int, DiscoverItem) -> Unit,
onLongClickSimilar: (Int, DiscoverItem) -> Unit,
modifier: Modifier = Modifier,
) {
@ -244,49 +240,56 @@ fun DiscoverSeriesDetailsContent(
modifier = Modifier,
) {
item {
DiscoverSeriesDetailsHeader(
series = series,
rating = rating,
overviewOnClick = overviewOnClick,
Column(
verticalArrangement = Arrangement.spacedBy(0.dp),
modifier =
Modifier
.fillMaxWidth()
.bringIntoViewRequester(bringIntoViewRequester)
.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)
?: SeerrAvailability.UNKNOWN,
requestOnClick = requestOnClick,
cancelOnClick = cancelOnClick,
moreOnClick = moreOnClick,
goToOnClick = goToOnClick,
buttonOnFocusChanged = {
if (it.isFocused) {
position = HEADER_ROW
scope.launch(ExceptionHandler()) {
bringIntoViewRequester.bringIntoView()
}
.bringIntoViewRequester(bringIntoViewRequester),
) {
DiscoverSeriesDetailsHeader(
series = series,
rating = rating,
overviewOnClick = overviewOnClick,
modifier =
Modifier
.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)
}
},
canRequest = userConfig.hasPermission(SeerrPermission.REQUEST),
canCancel = canCancel,
modifier =
Modifier
.fillMaxWidth()
.padding(bottom = 16.dp)
.focusRequester(focusRequesters[HEADER_ROW]),
)
ExpandableDiscoverButtons(
availability =
SeerrAvailability.from(series.mediaInfo?.status)
?: SeerrAvailability.UNKNOWN,
requestOnClick = requestOnClick,
cancelOnClick = cancelOnClick,
moreOnClick = moreOnClick,
goToOnClick = goToOnClick,
buttonOnFocusChanged = {
if (it.isFocused) {
position = HEADER_ROW
scope.launch(ExceptionHandler()) {
bringIntoViewRequester.bringIntoView()
}
}
},
canRequest = userConfig.hasPermission(SeerrPermission.REQUEST),
canCancel = canCancel,
modifier =
Modifier
.fillMaxWidth()
.padding(bottom = 16.dp)
.focusRequester(focusRequesters[HEADER_ROW]),
)
}
}
// item {
// ItemRow(
@ -318,18 +321,22 @@ fun DiscoverSeriesDetailsContent(
// }
if (people.isNotEmpty()) {
item {
PersonRow(
people = people,
onClick = {
DiscoverRow(
row =
DiscoverRowData(
stringResource(R.string.people),
DataLoadingState.Success(people),
),
onClickItem = { index: Int, item: DiscoverItem ->
position = PEOPLE_ROW
onClickPerson.invoke(it)
onClickPerson.invoke(item)
},
onLongClick = { index, person ->
onLongClickItem = { index, person ->
position = PEOPLE_ROW
onLongClickPerson.invoke(index, person)
},
modifier =
Modifier
.fillMaxWidth()
.focusRequester(focusRequesters[PEOPLE_ROW]),
onCardFocus = {},
focusRequester = focusRequesters[PEOPLE_ROW],
)
}
}

View file

@ -10,7 +10,6 @@ import com.github.damontecres.wholphin.api.seerr.model.TvDetails
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.Person
import com.github.damontecres.wholphin.data.model.Trailer
import com.github.damontecres.wholphin.services.BackdropService
import com.github.damontecres.wholphin.services.NavigationManager
@ -34,8 +33,6 @@ import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.jellyfin.sdk.api.client.ApiClient
import org.jellyfin.sdk.model.UUID
import org.jellyfin.sdk.model.api.PersonKind
@HiltViewModel(assistedFactory = DiscoverSeriesViewModel.Factory::class)
class DiscoverSeriesViewModel
@ -61,7 +58,7 @@ class DiscoverSeriesViewModel
val seasons = MutableLiveData<List<Season>>(listOf())
val trailers = MutableLiveData<List<Trailer>>(listOf())
val people = MutableLiveData<List<Person>>(listOf())
val people = MutableLiveData<List<DiscoverItem>>(listOf())
val similar = MutableLiveData<List<DiscoverItem>>(listOf())
val recommended = MutableLiveData<List<DiscoverItem>>(listOf())
@ -126,28 +123,12 @@ class DiscoverSeriesViewModel
val people =
tv.credits
?.cast
?.map {
Person(
id = UUID.randomUUID(),
name = it.name,
role = it.character,
type = PersonKind.UNKNOWN,
imageUrl = "https://image.tmdb.org/t/p/w600_and_h900_bestv2${it.profilePath}",
favorite = false,
)
}.orEmpty() +
?.map(::DiscoverItem)
.orEmpty() +
tv.credits
?.crew
?.map {
Person(
id = UUID.randomUUID(),
name = it.name,
role = it.job,
type = PersonKind.UNKNOWN,
imageUrl = "https://image.tmdb.org/t/p/w600_and_h900_bestv2${it.profilePath}",
favorite = false,
)
}.orEmpty()
?.map(::DiscoverItem)
.orEmpty()
this@DiscoverSeriesViewModel.people.setValueOnMain(people)
}

View file

@ -196,7 +196,7 @@ fun SeerrRequestsPage(
gridFocusRequester = focusRequester,
showJumpButtons = false,
showLetterButtons = false,
spacing = 24.dp,
spacing = 16.dp,
cardContent = @Composable { item, onClick, onLongClick, mod ->
DiscoverItemCard(
item = item?.item,

View file

@ -23,6 +23,7 @@ import com.github.damontecres.wholphin.ui.detail.FavoritesPage
import com.github.damontecres.wholphin.ui.detail.PersonPage
import com.github.damontecres.wholphin.ui.detail.PlaylistDetails
import com.github.damontecres.wholphin.ui.detail.discover.DiscoverMovieDetails
import com.github.damontecres.wholphin.ui.detail.discover.DiscoverPersonPage
import com.github.damontecres.wholphin.ui.detail.discover.DiscoverSeriesDetails
import com.github.damontecres.wholphin.ui.detail.episode.EpisodeDetails
import com.github.damontecres.wholphin.ui.detail.movie.MovieDetails
@ -265,6 +266,7 @@ fun DestinationContent(
DiscoverMovieDetails(
preferences = preferences,
destination = destination,
modifier = modifier,
)
}
@ -272,13 +274,14 @@ fun DestinationContent(
DiscoverSeriesDetails(
preferences = preferences,
destination = destination,
modifier = modifier,
)
}
SeerrItemType.PERSON -> {
Text(
text = "Person not supported yet",
color = MaterialTheme.colorScheme.onSurface,
DiscoverPersonPage(
person = destination.item,
modifier = modifier,
)
}

View file

@ -1009,11 +1009,11 @@ components:
cast:
type: array
items:
$ref: '#/components/schemas/Cast'
$ref: '#/components/schemas/CreditCast'
crew:
type: array
items:
$ref: '#/components/schemas/Crew'
$ref: '#/components/schemas/CreditCrew'
collection:
type: object
properties:
@ -1205,11 +1205,11 @@ components:
cast:
type: array
items:
$ref: '#/components/schemas/Cast'
$ref: '#/components/schemas/CreditCast'
crew:
type: array
items:
$ref: '#/components/schemas/Crew'
$ref: '#/components/schemas/CreditCrew'
externalIds:
$ref: '#/components/schemas/ExternalIds'
keywords:
@ -1691,6 +1691,9 @@ components:
type: integer
posterPath:
type: string
profilePath:
type: string
nullable: true
originalTitle:
type: string
video:
@ -1745,6 +1748,9 @@ components:
type: integer
posterPath:
type: string
profilePath:
type: string
nullable: true
originalTitle:
type: string
video: