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
This commit is contained in:
Ray 2026-02-26 20:27:22 -05:00 committed by GitHub
parent 9b995bf6ba
commit b65e55f4ed
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 99 additions and 26 deletions

View file

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

View file

@ -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
}

View file

@ -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<Person> =
@ -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
}

View file

@ -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)

View file

@ -612,7 +612,7 @@ fun Controller(
fontSize = subtitleTextSize,
)
}
if (showClock) {
var endTimeStr by remember { mutableStateOf("...") }
LaunchedEffect(playerControls) {
while (isActive) {
@ -636,7 +636,6 @@ fun Controller(
)
}
}
}
// TODO need to move these up a level?
val moreFocusRequester = remember { FocusRequester() }
val captionFocusRequester = remember { FocusRequester() }

View file

@ -704,4 +704,17 @@
<item>@string/photos</item>
</string-array>
<string name="actor">Actor</string>
<string name="composer">Composer</string>
<string name="writer">Writer</string>
<string name="guest_star">Guest star</string>
<string name="producer">Producer</string>
<string name="conductor">Conductor</string>
<string name="lyricist">Lyricist</string>
<string name="arranger">Arranger</string>
<string name="engineer">Engineer</string>
<string name="mixer">Mixer</string>
<string name="creator">Creator</string>
<string name="artist">Artist</string>
</resources>