From b65e55f4ed6c9a6ef428d74bd801b365e56e206a Mon Sep 17 00:00:00 2001 From: Ray <154766448+damontecres@users.noreply.github.com> Date: Thu, 26 Feb 2026 20:27:22 -0500 Subject: [PATCH] A few small UI fixes (#1012) ## Description - Restores corner text for episode cards - Always show end time on playback overlay instead of it being controlled by the "Show Clock" setting - Better logic to determine person's role in media ### Related issues Fixes #1010 Fixes #1004 Fixes #975 ### Testing Emulator ## Screenshots N/A ## AI or LLM usage None --- .../wholphin/data/model/BaseItem.kt | 6 ++- .../damontecres/wholphin/data/model/Person.kt | 51 ++++++++++++++++++- .../wholphin/services/PeopleFavorites.kt | 12 ++++- .../ui/detail/series/SeriesViewModel.kt | 2 +- .../wholphin/ui/playback/PlaybackOverlay.kt | 41 ++++++++------- app/src/main/res/values/strings.xml | 13 +++++ 6 files changed, 99 insertions(+), 26 deletions(-) diff --git a/app/src/main/java/com/github/damontecres/wholphin/data/model/BaseItem.kt b/app/src/main/java/com/github/damontecres/wholphin/data/model/BaseItem.kt index 950e9b40..e88673c1 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/data/model/BaseItem.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/data/model/BaseItem.kt @@ -95,7 +95,11 @@ data class BaseItem( data.indexNumber?.let { "E$it" } ?: data.premiereDate?.let(::formatDateTime), episodeUnplayedCornerText = - if (type == BaseItemKind.SERIES || type == BaseItemKind.SEASON || type == BaseItemKind.BOX_SET) { + if (type == BaseItemKind.SERIES || + type == BaseItemKind.SEASON || + type == BaseItemKind.EPISODE || + type == BaseItemKind.BOX_SET + ) { data.indexNumber?.let { "E$it" } ?: data.userData ?.unplayedItemCount diff --git a/app/src/main/java/com/github/damontecres/wholphin/data/model/Person.kt b/app/src/main/java/com/github/damontecres/wholphin/data/model/Person.kt index c12d37b5..ac4a4710 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/data/model/Person.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/data/model/Person.kt @@ -1,6 +1,10 @@ package com.github.damontecres.wholphin.data.model +import android.content.Context +import androidx.annotation.StringRes import androidx.compose.runtime.Stable +import com.github.damontecres.wholphin.R +import com.github.damontecres.wholphin.ui.isNotNullOrBlank import org.jellyfin.sdk.api.client.ApiClient import org.jellyfin.sdk.api.client.extensions.imageApi import org.jellyfin.sdk.model.UUID @@ -19,19 +23,21 @@ data class Person( ) { companion object { fun fromDto( + context: Context, dto: BaseItemPerson, api: ApiClient, ): Person = Person( id = dto.id, name = dto.name, - role = dto.role, + role = personRole(context, dto.role, dto.type), type = dto.type, imageUrl = api.imageApi.getItemImageUrl(dto.id, ImageType.PRIMARY), favorite = false, ) fun fromDto( + context: Context, dto: BaseItemPerson, favorite: Boolean, api: ApiClient, @@ -39,10 +45,51 @@ data class Person( Person( id = dto.id, name = dto.name, - role = dto.role, + role = personRole(context, dto.role, dto.type), type = dto.type, imageUrl = api.imageApi.getItemImageUrl(dto.id, ImageType.PRIMARY), favorite = favorite, ) } } + +private fun personRole( + context: Context, + role: String?, + type: PersonKind, +): String? = + if (type == PersonKind.ACTOR || type == PersonKind.GUEST_STAR || type == PersonKind.UNKNOWN) { + role + } else if (role.equals(type.name, ignoreCase = true)) { + type.stringRes?.let { context.getString(it) } + } else if (role.isNotNullOrBlank() && role.lowercase().contains(type.name.lowercase())) { + role + } else { + listOfNotNull( + role?.takeIf { it.isNotNullOrBlank() }, + type.stringRes?.let { context.getString(it) }, + ).takeIf { it.isNotEmpty() }?.joinToString(" - ") + } + +@get:StringRes +private val PersonKind.stringRes: Int? + get() = + when (this) { + PersonKind.UNKNOWN -> R.string.unknown + PersonKind.ACTOR -> R.string.actor + PersonKind.DIRECTOR -> R.string.director + PersonKind.COMPOSER -> R.string.composer + PersonKind.WRITER -> R.string.writer + PersonKind.GUEST_STAR -> R.string.guest_star + PersonKind.PRODUCER -> R.string.producer + PersonKind.CONDUCTOR -> R.string.conductor + PersonKind.LYRICIST -> R.string.lyricist + PersonKind.ARRANGER -> R.string.arranger + PersonKind.ENGINEER -> R.string.engineer + PersonKind.MIXER -> R.string.mixer + PersonKind.REMIXER -> R.string.mixer + PersonKind.CREATOR -> R.string.creator + PersonKind.ARTIST -> R.string.artist + PersonKind.ALBUM_ARTIST -> R.string.artist + else -> null + } diff --git a/app/src/main/java/com/github/damontecres/wholphin/services/PeopleFavorites.kt b/app/src/main/java/com/github/damontecres/wholphin/services/PeopleFavorites.kt index b4967b03..6a35dda5 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/services/PeopleFavorites.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/services/PeopleFavorites.kt @@ -1,8 +1,10 @@ package com.github.damontecres.wholphin.services +import android.content.Context import com.github.damontecres.wholphin.data.model.BaseItem import com.github.damontecres.wholphin.data.model.Person import com.github.damontecres.wholphin.ui.letNotEmpty +import dagger.hilt.android.qualifiers.ApplicationContext import org.jellyfin.sdk.api.client.ApiClient import org.jellyfin.sdk.api.client.extensions.itemsApi import javax.inject.Inject @@ -12,6 +14,7 @@ import javax.inject.Singleton class PeopleFavorites @Inject constructor( + @param:ApplicationContext private val context: Context, private val api: ApiClient, ) { suspend fun getPeopleFor(item: BaseItem): List = @@ -27,7 +30,14 @@ class PeopleFavorites val people = item.data.people ?.letNotEmpty { people -> - people.map { Person.fromDto(it, favorites[it.id] ?: false, api) } + people.map { + Person.fromDto( + context, + it, + favorites[it.id] ?: false, + api, + ) + } }.orEmpty() people } 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 3d80aa9d..a299fe3c 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 @@ -528,7 +528,7 @@ class SeriesViewModel api.userLibraryApi .getItem(item.id) .content.people - ?.map { Person.fromDto(it, api) } + ?.map { Person.fromDto(context, it, api) } .orEmpty() PeopleInItem(item.id, list) diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackOverlay.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackOverlay.kt index b1500b60..0886590e 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackOverlay.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackOverlay.kt @@ -612,29 +612,28 @@ fun Controller( fontSize = subtitleTextSize, ) } - if (showClock) { - var endTimeStr by remember { mutableStateOf("...") } - LaunchedEffect(playerControls) { - while (isActive) { - val remaining = - (playerControls.duration - playerControls.currentPosition) - .div(playerControls.playbackParameters.speed) - .toLong() - .milliseconds - val endTime = LocalTime.now().plusSeconds(remaining.inWholeSeconds) - endTimeStr = TimeFormatter.format(endTime) - delay(1.seconds) - } + + var endTimeStr by remember { mutableStateOf("...") } + LaunchedEffect(playerControls) { + while (isActive) { + val remaining = + (playerControls.duration - playerControls.currentPosition) + .div(playerControls.playbackParameters.speed) + .toLong() + .milliseconds + val endTime = LocalTime.now().plusSeconds(remaining.inWholeSeconds) + endTimeStr = TimeFormatter.format(endTime) + delay(1.seconds) } - Text( - text = "Ends $endTimeStr", - color = MaterialTheme.colorScheme.onSurface, - style = MaterialTheme.typography.labelLarge, - modifier = - Modifier - .padding(end = 32.dp), - ) } + Text( + text = "Ends $endTimeStr", + color = MaterialTheme.colorScheme.onSurface, + style = MaterialTheme.typography.labelLarge, + modifier = + Modifier + .padding(end = 32.dp), + ) } } // TODO need to move these up a level? diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 65afe072..967d6922 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -704,4 +704,17 @@ @string/photos + Actor + Composer + Writer + Guest star + Producer + Conductor + Lyricist + Arranger + Engineer + Mixer + Creator + Artist +