feat: add formatReleaseDateForDisplay function and integrate it across various components for improved release date formatting

This commit is contained in:
tapframe 2026-03-30 20:57:45 +05:30
parent 828167f9ae
commit cc7d6b6b59
10 changed files with 74 additions and 13 deletions

View file

@ -0,0 +1,32 @@
package com.nuvio.app.core.format
private val MONTH_NAMES = listOf(
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December",
)
/**
* Formats ISO calendar dates (yyyy-MM-dd or yyyy-MM-ddTHH:mm:ss) for UI as "2025 February 1".
* Other strings (e.g. year-only "2024", human text from addons) are returned unchanged.
*/
fun formatReleaseDateForDisplay(raw: String): String {
val trimmed = raw.trim()
if (trimmed.isEmpty()) return raw
val datePart = trimmed.substringBefore('T').trim()
val parts = datePart.split('-')
if (parts.size != 3) return raw
val year = parts[0].toIntOrNull() ?: return raw
val month = parts[1].toIntOrNull()?.takeIf { it in 1..12 } ?: return raw
val day = parts[2].toIntOrNull()?.takeIf { it in 1..31 } ?: return raw
return "$year ${MONTH_NAMES[month - 1]} $day"
}

View file

@ -40,6 +40,7 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import coil3.compose.AsyncImage
import com.nuvio.app.core.format.formatReleaseDateForDisplay
import com.nuvio.app.features.home.MetaPreview
import kotlinx.coroutines.launch
@ -212,7 +213,7 @@ private fun PosterSheetHeader(
overflow = TextOverflow.Ellipsis,
)
Text(
text = item.releaseInfo?.takeIf { it.isNotBlank() }
text = item.releaseInfo?.takeIf { it.isNotBlank() }?.let { formatReleaseDateForDisplay(it) }
?: item.type.replaceFirstChar { char ->
if (char.isLowerCase()) char.titlecase() else char.toString()
},

View file

@ -39,6 +39,7 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import coil3.compose.AsyncImage
import com.nuvio.app.core.format.formatReleaseDateForDisplay
import com.nuvio.app.core.ui.NuvioBackButton
import com.nuvio.app.core.ui.posterCardClickable
import com.nuvio.app.core.ui.nuvioPlatformExtraBottomPadding
@ -217,7 +218,7 @@ private fun CatalogPosterTile(
maxLines = 2,
overflow = TextOverflow.Ellipsis,
)
val detail = item.releaseInfo
val detail = item.releaseInfo?.let { formatReleaseDateForDisplay(it) }
if (detail != null) {
Text(
text = detail,

View file

@ -16,6 +16,7 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import com.nuvio.app.core.format.formatReleaseDateForDisplay
import com.nuvio.app.features.details.MetaDetails
@Composable
@ -27,7 +28,7 @@ fun DetailAdditionalInfoSection(
val title = if (isSeriesLike) "Show Details" else "Movie Details"
val rows = buildList {
meta.status?.let { add("Status" to it) }
meta.releaseInfo?.let { add("Release Info" to it) }
meta.releaseInfo?.let { add("Release Info" to formatReleaseDateForDisplay(it)) }
meta.runtime?.let { add("Runtime" to it.uppercase()) }
meta.ageRating?.let { add("Certification" to it) }
meta.country?.let { add("Origin Country" to it) }

View file

@ -25,6 +25,7 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.nuvio.app.core.format.formatReleaseDateForDisplay
import com.nuvio.app.features.details.MetaDetails
@Composable
@ -37,7 +38,7 @@ fun DetailMetaInfo(
verticalArrangement = Arrangement.spacedBy(12.dp),
) {
val infoParts = buildList {
meta.releaseInfo?.let { add(it) }
meta.releaseInfo?.let { add(formatReleaseDateForDisplay(it)) }
meta.ageRating?.let { add(it) }
meta.runtime?.let { add(it.uppercase()) }
}

View file

@ -49,6 +49,7 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import coil3.compose.AsyncImage
import co.touchlab.kermit.Logger
import com.nuvio.app.core.format.formatReleaseDateForDisplay
import com.nuvio.app.core.ui.NuvioAnimatedWatchedBadge
import com.nuvio.app.core.ui.NuvioProgressBar
import com.nuvio.app.features.details.MetaDetails
@ -583,7 +584,7 @@ private fun EpisodeCard(
overflow = TextOverflow.Ellipsis,
)
video.released?.formattedDate()?.let { formattedDate ->
video.released?.let { formatReleaseDateForDisplay(it) }?.let { formattedDate ->
Text(
text = formattedDate,
style = MaterialTheme.typography.labelMedium.copy(
@ -796,8 +797,3 @@ private fun MetaVideo.episodeBadge(): String =
season != null -> "S${season.toString().padStart(2, '0')}"
else -> "FILE"
}
private fun String.formattedDate(): String {
val isoDate = substringBefore('T')
return if (isoDate.length == 10) isoDate else this
}

View file

@ -37,6 +37,7 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import coil3.compose.AsyncImage
import com.nuvio.app.core.format.formatReleaseDateForDisplay
import com.nuvio.app.features.home.MetaPreview
import kotlinx.coroutines.launch
@ -254,7 +255,7 @@ private fun HeroContentBlock(
}
item.releaseInfo?.takeIf { it.isNotBlank() }?.let { info ->
HeroMetaDot()
HeroMetaText(text = info)
HeroMetaText(text = formatReleaseDateForDisplay(info))
}
}
}

View file

@ -2,6 +2,7 @@ package com.nuvio.app.features.home.components
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.nuvio.app.core.format.formatReleaseDateForDisplay
import com.nuvio.app.core.ui.NuvioPosterCard
import com.nuvio.app.core.ui.NuvioPosterShape
import com.nuvio.app.features.home.MetaPreview
@ -20,7 +21,7 @@ fun HomePosterCard(
imageUrl = item.poster,
modifier = modifier,
shape = item.posterShape.toNuvioPosterShape(),
detailLine = item.releaseInfo,
detailLine = item.releaseInfo?.let { formatReleaseDateForDisplay(it) },
isWatched = isWatched,
onClick = onClick,
onLongClick = onLongClick,

View file

@ -41,6 +41,7 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import coil3.compose.AsyncImage
import com.nuvio.app.core.format.formatReleaseDateForDisplay
import com.nuvio.app.core.ui.NuvioAnimatedWatchedBadge
import com.nuvio.app.core.ui.posterCardClickable
import com.nuvio.app.features.home.MetaPreview
@ -304,7 +305,7 @@ private fun DiscoverPosterTile(
maxLines = 2,
overflow = TextOverflow.Ellipsis,
)
val detail = item.releaseInfo
val detail = item.releaseInfo?.let { formatReleaseDateForDisplay(it) }
if (detail != null) {
Text(
text = detail,

View file

@ -0,0 +1,26 @@
package com.nuvio.app.core.format
import kotlin.test.Test
import kotlin.test.assertEquals
class ReleaseDateDisplayTest {
@Test
fun formatsIsoDate() {
assertEquals("2025 February 1", formatReleaseDateForDisplay("2025-02-01"))
}
@Test
fun stripsTimePortion() {
assertEquals("2024 January 15", formatReleaseDateForDisplay("2024-01-15T12:30:00Z"))
}
@Test
fun leavesYearOnlyUnchanged() {
assertEquals("2024", formatReleaseDateForDisplay("2024"))
}
@Test
fun leavesNonIsoUnchanged() {
assertEquals("TBA", formatReleaseDateForDisplay("TBA"))
}
}