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
## 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