mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-07-26 22:42:17 +00:00
feat: add formatReleaseDateForDisplay function and integrate it across various components for improved release date formatting
This commit is contained in:
parent
828167f9ae
commit
cc7d6b6b59
10 changed files with 74 additions and 13 deletions
|
|
@ -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"
|
||||
}
|
||||
|
|
@ -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()
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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) }
|
||||
|
|
|
|||
|
|
@ -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()) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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"))
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue