From b5422fe82b83bc96a3ad791a802b3a76595f8e41 Mon Sep 17 00:00:00 2001 From: Ray <154766448+damontecres@users.noreply.github.com> Date: Thu, 16 Apr 2026 00:26:57 -0400 Subject: [PATCH] Show last played date on overview dialog (#1248) ## Description Adds a line to the overview/media info dialog with the date when the item was last played. ### Related issues N/A ### Testing Emulator ## Screenshots last_played Large ## AI or LLM usage None --- .../damontecres/wholphin/ui/Formatting.kt | 2 ++ .../wholphin/ui/data/ItemDetailsDialogInfo.kt | 25 ++++++++++++++++++- .../ui/detail/collection/CollectionDetails.kt | 8 +----- .../ui/detail/episode/EpisodeDetails.kt | 15 ++--------- .../wholphin/ui/detail/movie/MovieDetails.kt | 17 ++----------- .../ui/detail/series/SeriesDetails.kt | 9 +------ .../ui/detail/series/SeriesOverview.kt | 18 ++----------- app/src/main/res/values/strings.xml | 1 + 8 files changed, 35 insertions(+), 60 deletions(-) diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/Formatting.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/Formatting.kt index 7435cca8..7b64b1a4 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/Formatting.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/Formatting.kt @@ -47,6 +47,8 @@ fun formatDateTime(dateTime: LocalDateTime): String = getDateFormatter().format( fun formatDate(dateTime: LocalDate): String = getDateFormatter().format(dateTime) +fun formatDate(dateTime: LocalDateTime): String = getDateFormatter().format(dateTime) + fun toLocalDate(date: String?): LocalDate? = date?.let { try { diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/data/ItemDetailsDialogInfo.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/data/ItemDetailsDialogInfo.kt index 8e7c89b1..67e4cc3e 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/data/ItemDetailsDialogInfo.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/data/ItemDetailsDialogInfo.kt @@ -19,9 +19,12 @@ import androidx.compose.ui.unit.dp import androidx.tv.material3.MaterialTheme import androidx.tv.material3.Text import com.github.damontecres.wholphin.R +import com.github.damontecres.wholphin.data.model.BaseItem +import com.github.damontecres.wholphin.data.model.studioNames import com.github.damontecres.wholphin.ui.components.ScrollableDialog import com.github.damontecres.wholphin.ui.formatBitrate import com.github.damontecres.wholphin.ui.formatBytes +import com.github.damontecres.wholphin.ui.formatDate import com.github.damontecres.wholphin.ui.isNotNullOrBlank import com.github.damontecres.wholphin.ui.letNotEmpty import com.github.damontecres.wholphin.ui.util.StreamFormatting.formatAudioCodec @@ -33,6 +36,7 @@ import org.jellyfin.sdk.model.api.MediaStreamType import org.jellyfin.sdk.model.api.VideoRange import org.jellyfin.sdk.model.api.VideoRangeType import org.jellyfin.sdk.model.extensions.ticks +import java.time.LocalDateTime import java.util.Locale data class ItemDetailsDialogInfo( @@ -41,7 +45,17 @@ data class ItemDetailsDialogInfo( val genres: List, val files: List, val studios: List = emptyList(), -) + val lastPlayed: LocalDateTime? = null, +) { + constructor(item: BaseItem) : this( + title = item.name ?: "", + overview = item.data.overview, + genres = item.data.genres.orEmpty(), + files = item.data.mediaSources.orEmpty(), + studios = item.studioNames, + lastPlayed = item.data.userData?.lastPlayedDate, + ) +} /** * Dialog showing metadata about an item @@ -62,6 +76,7 @@ fun ItemDetailsDialog( val bitrateLabel = stringResource(R.string.bitrate) val unknown = stringResource(R.string.unknown) val runtimeLabel = stringResource(R.string.runtime_sort) + val lastPlayedLabel = stringResource(R.string.last_played) ScrollableDialog( onDismissRequest = onDismissRequest, @@ -93,6 +108,14 @@ fun ItemDetailsDialog( style = MaterialTheme.typography.bodyMedium, ) } + val lastPlayed = + remember(info.lastPlayed) { info.lastPlayed?.let { formatDate(it) } } + if (lastPlayed != null) { + Text( + text = "$lastPlayedLabel: $lastPlayed", + style = MaterialTheme.typography.bodyMedium, + ) + } } } diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/collection/CollectionDetails.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/collection/CollectionDetails.kt index 96a4ea4f..7e0ca325 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/collection/CollectionDetails.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/collection/CollectionDetails.kt @@ -191,13 +191,7 @@ fun CollectionDetails( modifier = modifier, overviewOnClick = { val collection = state.collection!! - overviewDialog = - ItemDetailsDialogInfo( - title = collection.title ?: "", - overview = collection.data.overview, - genres = collection.data.genres.orEmpty(), - files = emptyList(), - ) + overviewDialog = ItemDetailsDialogInfo(collection) }, favoriteOnClick = remember { diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/episode/EpisodeDetails.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/episode/EpisodeDetails.kt index bdacc389..79637ee0 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/episode/EpisodeDetails.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/episode/EpisodeDetails.kt @@ -149,12 +149,7 @@ fun EpisodeDetails( }, overviewOnClick = { overviewDialog = - ItemDetailsDialogInfo( - title = ep.name ?: context.getString(R.string.unknown), - overview = ep.data.overview, - genres = ep.data.genres.orEmpty(), - files = ep.data.mediaSources.orEmpty(), - ) + ItemDetailsDialogInfo(ep) }, moreOnClick = { moreDialog = @@ -218,13 +213,7 @@ fun EpisodeDetails( onShowOverview = { val source = chosenStreams?.source ?: ep.data.mediaSources?.firstOrNull() if (source != null) { - overviewDialog = - ItemDetailsDialogInfo( - title = ep.name ?: context.getString(R.string.unknown), - overview = ep.data.overview, - genres = ep.data.genres.orEmpty(), - files = listOf(source), - ) + overviewDialog = ItemDetailsDialogInfo(ep) } }, onClearChosenStreams = { diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/movie/MovieDetails.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/movie/MovieDetails.kt index bf7d4601..64bf2f1c 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/movie/MovieDetails.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/movie/MovieDetails.kt @@ -35,7 +35,6 @@ import com.github.damontecres.wholphin.data.model.DiscoverItem import com.github.damontecres.wholphin.data.model.Person import com.github.damontecres.wholphin.data.model.Trailer import com.github.damontecres.wholphin.data.model.aspectRatioFloat -import com.github.damontecres.wholphin.data.model.studioNames import com.github.damontecres.wholphin.preferences.UserPreferences import com.github.damontecres.wholphin.services.TrailerService import com.github.damontecres.wholphin.ui.AspectRatios @@ -181,13 +180,7 @@ fun MovieDetails( }, overviewOnClick = { overviewDialog = - ItemDetailsDialogInfo( - title = movie.name ?: unknownStr, - overview = movie.data.overview, - genres = movie.data.genres.orEmpty(), - files = movie.data.mediaSources.orEmpty(), - studios = movie.studioNames, - ) + ItemDetailsDialogInfo(movie) }, moreOnClick = { moreDialog = @@ -250,13 +243,7 @@ fun MovieDetails( } }, onShowOverview = { - overviewDialog = - ItemDetailsDialogInfo( - title = movie.name ?: unknownStr, - overview = movie.data.overview, - genres = movie.data.genres.orEmpty(), - files = movie.data.mediaSources.orEmpty(), - ) + overviewDialog = ItemDetailsDialogInfo(movie) }, onClearChosenStreams = { viewModel.clearChosenStreams(chosenStreams) 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 91baa312..3c6b7d5c 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 @@ -210,14 +210,7 @@ fun SeriesDetails( } }, overviewOnClick = { - overviewDialog = - ItemDetailsDialogInfo( - title = item.name ?: context.getString(R.string.unknown), - overview = item.data.overview, - genres = item.data.genres.orEmpty(), - studios = item.studioNames, - files = listOf(), - ) + overviewDialog = ItemDetailsDialogInfo(item) }, playOnClick = { shuffle -> if (shuffle) { 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 e048a008..23633651 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 @@ -265,13 +265,7 @@ fun SeriesOverview( } }, onShowOverview = { - overviewDialog = - ItemDetailsDialogInfo( - title = ep.name ?: context.getString(R.string.unknown), - overview = ep.data.overview, - genres = ep.data.genres.orEmpty(), - files = ep.data.mediaSources.orEmpty(), - ) + overviewDialog = ItemDetailsDialogInfo(ep) }, onClearChosenStreams = { viewModel.clearChosenStreams(ep, chosenStreams) @@ -357,15 +351,7 @@ fun SeriesOverview( }, overviewOnClick = { episodeList?.getOrNull(position.episodeRowIndex)?.let { - scope.launchDefault { - overviewDialog = - ItemDetailsDialogInfo( - title = it.name ?: context.getString(R.string.unknown), - overview = it.data.overview, - genres = it.data.genres.orEmpty(), - files = it.data.mediaSources.orEmpty(), - ) - } + overviewDialog = ItemDetailsDialogInfo(it) } }, personOnClick = { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 68b2f5d3..5628f293 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -756,6 +756,7 @@ Discover TV Shows Discover Movies Studios in %1$s + Last played Direct play with libass Direct play with ExoPlayer built-in