From cf5cb9745d9502952b89ab18b9f573cee5fdae08 Mon Sep 17 00:00:00 2001 From: Sage Gavin Davids Date: Tue, 12 May 2026 08:10:26 +0000 Subject: [PATCH 1/2] fix: normalize genre labels to proper case Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../com/arflix/tv/ui/screens/details/DetailsScreen.kt | 3 ++- .../com/arflix/tv/ui/screens/tv/live/MiniPlayer.kt | 3 ++- .../com/arflix/tv/ui/screens/tv/live/SearchOverlay.kt | 3 ++- app/src/main/kotlin/com/arflix/tv/util/MediaBadges.kt | 11 +++++++++++ 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/app/src/main/kotlin/com/arflix/tv/ui/screens/details/DetailsScreen.kt b/app/src/main/kotlin/com/arflix/tv/ui/screens/details/DetailsScreen.kt index 2d2bd8ed2..a80b5de22 100644 --- a/app/src/main/kotlin/com/arflix/tv/ui/screens/details/DetailsScreen.kt +++ b/app/src/main/kotlin/com/arflix/tv/ui/screens/details/DetailsScreen.kt @@ -166,6 +166,7 @@ import com.arflix.tv.ui.theme.Purple import com.arflix.tv.ui.theme.TextPrimary import com.arflix.tv.ui.theme.TextSecondary import com.arflix.tv.util.LocalDeviceType +import com.arflix.tv.util.formatGenreName import com.arflix.tv.util.isInCinema import com.arflix.tv.util.parseRatingValue import java.text.SimpleDateFormat @@ -3959,7 +3960,7 @@ private fun GenreBadge(genre: String) { .padding(horizontal = 10.dp, vertical = 5.dp) ) { Text( - text = genre.uppercase(), + text = formatGenreName(genre), style = ArflixTypography.label, color = Pink ) diff --git a/app/src/main/kotlin/com/arflix/tv/ui/screens/tv/live/MiniPlayer.kt b/app/src/main/kotlin/com/arflix/tv/ui/screens/tv/live/MiniPlayer.kt index 691499ec1..b8801b729 100644 --- a/app/src/main/kotlin/com/arflix/tv/ui/screens/tv/live/MiniPlayer.kt +++ b/app/src/main/kotlin/com/arflix/tv/ui/screens/tv/live/MiniPlayer.kt @@ -46,6 +46,7 @@ import androidx.tv.material3.ExperimentalTvMaterial3Api import androidx.tv.material3.Text import com.arflix.tv.data.model.IptvNowNext import com.arflix.tv.data.model.IptvProgram +import com.arflix.tv.util.formatGenreName @OptIn(ExperimentalTvMaterial3Api::class) @Composable @@ -264,7 +265,7 @@ private fun ChannelIdentityRow(channel: EnrichedChannel?) { style = LiveType.SectionTag.copy(color = LiveColors.FgMute), ) Text( - text = channel.genre.name.uppercase(), + text = formatGenreName(channel.genre.name), style = LiveType.SectionTag.copy(color = LiveColors.FgMute), ) } diff --git a/app/src/main/kotlin/com/arflix/tv/ui/screens/tv/live/SearchOverlay.kt b/app/src/main/kotlin/com/arflix/tv/ui/screens/tv/live/SearchOverlay.kt index b23a6583d..b4348aabf 100644 --- a/app/src/main/kotlin/com/arflix/tv/ui/screens/tv/live/SearchOverlay.kt +++ b/app/src/main/kotlin/com/arflix/tv/ui/screens/tv/live/SearchOverlay.kt @@ -54,6 +54,7 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.tv.material3.ExperimentalTvMaterial3Api import androidx.tv.material3.Text +import com.arflix.tv.util.formatGenreName import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.withContext @@ -283,7 +284,7 @@ private fun SearchResultRow( overflow = TextOverflow.Ellipsis, ) Text( - text = channel.genre.name.uppercase(), + text = formatGenreName(channel.genre.name), style = LiveType.SectionTag.copy(color = LiveColors.FgMute), ) } diff --git a/app/src/main/kotlin/com/arflix/tv/util/MediaBadges.kt b/app/src/main/kotlin/com/arflix/tv/util/MediaBadges.kt index 4ec666792..a670a4163 100644 --- a/app/src/main/kotlin/com/arflix/tv/util/MediaBadges.kt +++ b/app/src/main/kotlin/com/arflix/tv/util/MediaBadges.kt @@ -7,6 +7,8 @@ import java.time.format.DateTimeFormatter import java.time.temporal.ChronoUnit private val releaseDateFormatter = DateTimeFormatter.ISO_LOCAL_DATE +private val genreWordStartRegex = Regex("(^|[\\s/&-])([\\p{L}])") +private val tvWordRegex = Regex("\\bTv\\b") fun isInCinema(item: MediaItem, now: LocalDate = LocalDate.now()): Boolean { if (item.mediaType != MediaType.MOVIE) return false @@ -23,3 +25,12 @@ fun parseRatingValue(raw: String): Float { if (raw.isBlank()) return 0f return raw.trim().replace(',', '.').toFloatOrNull() ?: 0f } + +fun formatGenreName(raw: String): String { + val trimmed = raw.trim() + if (trimmed.isEmpty()) return trimmed + val titled = trimmed.lowercase().replace(genreWordStartRegex) { match -> + match.groupValues[1] + match.groupValues[2].replaceFirstChar { it.titlecase() } + } + return titled.replace(tvWordRegex, "TV") +} From ea5781066ae321f705af723bbe1d3c0f661f89fc Mon Sep 17 00:00:00 2001 From: Arvin Date: Thu, 14 May 2026 12:47:38 +0200 Subject: [PATCH 2/2] fix: format details genre metadata --- .../kotlin/com/arflix/tv/ui/screens/details/DetailsScreen.kt | 4 ++-- app/src/main/kotlin/com/arflix/tv/util/MediaBadges.kt | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/src/main/kotlin/com/arflix/tv/ui/screens/details/DetailsScreen.kt b/app/src/main/kotlin/com/arflix/tv/ui/screens/details/DetailsScreen.kt index a80b5de22..1544e8d92 100644 --- a/app/src/main/kotlin/com/arflix/tv/ui/screens/details/DetailsScreen.kt +++ b/app/src/main/kotlin/com/arflix/tv/ui/screens/details/DetailsScreen.kt @@ -1178,7 +1178,7 @@ private fun DetailsContent( } } - val genreText = genres.take(2).joinToString(" / ").ifBlank { + val genreText = genres.take(2).map(::formatGenreName).joinToString(" / ").ifBlank { if (item.mediaType == MediaType.TV) "TV Series" else "Movie" } val displayDate = item.year.takeIf { it.isNotBlank() } @@ -1806,7 +1806,7 @@ private fun DetailsContent( Spacer(modifier = Modifier.height(4.dp)) - val genreText = genres.take(2).joinToString(" / ").ifEmpty { + val genreText = genres.take(2).map(::formatGenreName).joinToString(" / ").ifEmpty { if (item.mediaType == MediaType.TV) "TV Series" else "Movie" } val isCompactHeight = configuration.screenHeightDp < 720 diff --git a/app/src/main/kotlin/com/arflix/tv/util/MediaBadges.kt b/app/src/main/kotlin/com/arflix/tv/util/MediaBadges.kt index a670a4163..09153ad98 100644 --- a/app/src/main/kotlin/com/arflix/tv/util/MediaBadges.kt +++ b/app/src/main/kotlin/com/arflix/tv/util/MediaBadges.kt @@ -5,6 +5,7 @@ import com.arflix.tv.data.model.MediaType import java.time.LocalDate import java.time.format.DateTimeFormatter import java.time.temporal.ChronoUnit +import java.util.Locale private val releaseDateFormatter = DateTimeFormatter.ISO_LOCAL_DATE private val genreWordStartRegex = Regex("(^|[\\s/&-])([\\p{L}])") @@ -29,8 +30,8 @@ fun parseRatingValue(raw: String): Float { fun formatGenreName(raw: String): String { val trimmed = raw.trim() if (trimmed.isEmpty()) return trimmed - val titled = trimmed.lowercase().replace(genreWordStartRegex) { match -> - match.groupValues[1] + match.groupValues[2].replaceFirstChar { it.titlecase() } + val titled = trimmed.lowercase(Locale.ROOT).replace(genreWordStartRegex) { match -> + match.groupValues[1] + match.groupValues[2].replaceFirstChar { it.titlecase(Locale.ROOT) } } return titled.replace(tvWordRegex, "TV") }