diff --git a/composeApp/src/commonMain/composeResources/values/strings.xml b/composeApp/src/commonMain/composeResources/values/strings.xml
index 6f54ce85a..aa83758b8 100644
--- a/composeApp/src/commonMain/composeResources/values/strings.xml
+++ b/composeApp/src/commonMain/composeResources/values/strings.xml
@@ -2072,11 +2072,11 @@
Release has no tag or name
Airs %1$s
- Airs today
- Airs tomorrow
+ Airs Today
+ Airs Tomorrow
- - Airs in %1$d day
- - Airs in %1$d days
+ - Airs in %1$d Day
+ - Airs in %1$d Days
%1$s
Today
diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/components/HomeContinueWatchingSection.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/components/HomeContinueWatchingSection.kt
index 292afb191..04f1e3b2d 100644
--- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/components/HomeContinueWatchingSection.kt
+++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/components/HomeContinueWatchingSection.kt
@@ -638,12 +638,12 @@ private fun ContinueWatchingCard(
)
}
val todayIsoDate = CurrentDateProvider.todayIsoDate()
- val compactAirDateText = if (item.progressFraction <= 0f && item.seasonNumber != null && item.episodeNumber != null) {
- computeAirDateBadgeText(item.released, todayIsoDate, compact = true)
+ val airDateText = if (item.progressFraction <= 0f && item.seasonNumber != null && item.episodeNumber != null) {
+ computeAirDateBadgeText(item.released, todayIsoDate)
} else {
null
}
- val preferBackdropForNextUp = item.isNextUp && compactAirDateText != null && !item.isReleaseAlert
+ val preferBackdropForNextUp = item.isNextUp && airDateText != null && !item.isReleaseAlert
val imageUrl = item.continueWatchingCardArtworkUrl(
useEpisodeThumbnails = useEpisodeThumbnails,
preferBackdropForNextUp = preferBackdropForNextUp,
@@ -654,8 +654,8 @@ private fun ContinueWatchingCard(
} else {
null
}
- val episodeTitle = item.episodeTitle?.trim()?.takeIf { it.isNotBlank() } ?: compactAirDateText
- val badgeText = continueWatchingCardBadgeText(item = item, compactAirDateText = compactAirDateText)
+ val episodeTitle = item.episodeTitle?.trim()?.takeIf { it.isNotBlank() } ?: airDateText
+ val badgeText = continueWatchingCardBadgeText(item = item, airDateText = airDateText)
val backgroundColor = MaterialTheme.colorScheme.background
val badgeBackground = when {
item.isNewSeasonRelease -> ContinueWatchingNewSeasonBadgeColor
@@ -800,7 +800,7 @@ private fun ContinueWatchingCard(
@Composable
private fun continueWatchingCardBadgeText(
item: ContinueWatchingItem,
- compactAirDateText: String?,
+ airDateText: String?,
): String {
if (item.progressFraction > 0f) {
if (item.durationMs <= 0L) {
@@ -827,7 +827,7 @@ private fun continueWatchingCardBadgeText(
return when {
item.isReleaseAlert && item.isNewSeasonRelease -> stringResource(Res.string.cw_new_season)
item.isReleaseAlert -> stringResource(Res.string.cw_new_episode)
- compactAirDateText != null -> compactAirDateText
+ airDateText != null -> airDateText
else -> stringResource(Res.string.home_continue_watching_up_next)
}
}
@@ -903,7 +903,7 @@ private fun ContinueWatchingWideCard(
else stringResource(Res.string.cw_new_episode)
}
else -> {
- computeAirDateBadgeText(item.released, todayIsoDate, compact = isCompact)
+ computeAirDateBadgeText(item.released, todayIsoDate)
?: stringResource(Res.string.home_continue_watching_up_next)
}
}
@@ -1018,7 +1018,7 @@ private fun ContinueWatchingPosterCard(
else stringResource(Res.string.cw_new_episode)
}
else -> {
- computeAirDateBadgeText(item.released, todayIsoDate, compact = true)
+ computeAirDateBadgeText(item.released, todayIsoDate)
?: stringResource(Res.string.home_continue_watching_up_next)
}
}
diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/watching/domain/WatchingPolicies.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/watching/domain/WatchingPolicies.kt
index 92047bb28..020571dc6 100644
--- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/watching/domain/WatchingPolicies.kt
+++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/watching/domain/WatchingPolicies.kt
@@ -58,7 +58,8 @@ internal fun shouldSurfaceNextEpisode(
todayIsoDate = todayIsoDate,
releasedDate = releasedDate,
) ?: return false
- if (!showUnairedNextUp || daysUntilRelease <= 0) return false
+ if (daysUntilRelease <= 0) return true
+ if (!showUnairedNextUp) return false
return !isSeasonRollover || daysUntilRelease <= UpcomingNextSeasonWindowDays
}
if (!isSeasonRollover) {
diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/watchprogress/AirDateUtils.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/watchprogress/AirDateUtils.kt
index d2809caf9..d48bb51d6 100644
--- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/watchprogress/AirDateUtils.kt
+++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/watchprogress/AirDateUtils.kt
@@ -13,7 +13,6 @@ import co.touchlab.kermit.Logger
fun computeAirDateBadgeText(
releasedIso: String?,
todayIsoDate: String,
- compact: Boolean
): String? {
if (releasedIso.isNullOrBlank() || todayIsoDate.isBlank()) {
return null
@@ -31,22 +30,12 @@ fun computeAirDateBadgeText(
return when {
daysUntil < 0 -> null
- daysUntil == 0 -> {
- if (compact) stringResource(Res.string.cw_airs_today_short)
- else stringResource(Res.string.cw_airs_today)
- }
- daysUntil == 1 -> {
- if (compact) stringResource(Res.string.cw_airs_tomorrow_short)
- else stringResource(Res.string.cw_airs_tomorrow)
- }
- daysUntil in 2..7 -> {
- if (compact) pluralStringResource(Res.plurals.cw_airs_in_days_short, daysUntil, daysUntil)
- else pluralStringResource(Res.plurals.cw_airs_in_days, daysUntil, daysUntil)
- }
+ daysUntil == 0 -> stringResource(Res.string.cw_airs_today)
+ daysUntil == 1 -> stringResource(Res.string.cw_airs_tomorrow)
+ daysUntil in 2..7 -> pluralStringResource(Res.plurals.cw_airs_in_days, daysUntil, daysUntil)
else -> {
val formattedDate = formatReleaseDateWithoutYear(releasedIso)
- if (compact) stringResource(Res.string.cw_airs_date_short, formattedDate)
- else stringResource(Res.string.cw_airs_date, formattedDate)
+ stringResource(Res.string.cw_airs_date, formattedDate)
}
}
}
diff --git a/composeApp/src/commonTest/kotlin/com/nuvio/app/features/watching/domain/SeriesContinuityTest.kt b/composeApp/src/commonTest/kotlin/com/nuvio/app/features/watching/domain/SeriesContinuityTest.kt
index e619ae245..126d80696 100644
--- a/composeApp/src/commonTest/kotlin/com/nuvio/app/features/watching/domain/SeriesContinuityTest.kt
+++ b/composeApp/src/commonTest/kotlin/com/nuvio/app/features/watching/domain/SeriesContinuityTest.kt
@@ -285,6 +285,26 @@ class SeriesContinuityTest {
assertEquals("s1e2", nextEpisode.videoId)
}
+ @Test
+ fun nextReleasedEpisodeAfter_keeps_dated_unavailable_episode_on_release_day() {
+ val episodes = listOf(
+ WatchingReleasedEpisode(videoId = "s1e1", seasonNumber = 1, episodeNumber = 1, title = "Episode 1", releasedDate = "2026-07-01"),
+ WatchingReleasedEpisode(videoId = "s1e2", seasonNumber = 1, episodeNumber = 2, title = "Episode 2", releasedDate = "2026-07-12T20:00:00", available = false),
+ )
+
+ val nextEpisode = nextReleasedEpisodeAfter(
+ content = show,
+ episodes = episodes,
+ seasonNumber = 1,
+ episodeNumber = 1,
+ todayIsoDate = "2026-07-12",
+ showUnairedNextUp = true,
+ )
+
+ assertNotNull(nextEpisode)
+ assertEquals("s1e2", nextEpisode.videoId)
+ }
+
@Test
fun decideSeriesPrimaryAction_falls_back_to_specials_when_no_main_season() {
val specialsOnly = listOf(
diff --git a/composeApp/src/commonTest/kotlin/com/nuvio/app/features/watching/domain/WatchingPoliciesTest.kt b/composeApp/src/commonTest/kotlin/com/nuvio/app/features/watching/domain/WatchingPoliciesTest.kt
index 33d3f12ed..b5da7cd1b 100644
--- a/composeApp/src/commonTest/kotlin/com/nuvio/app/features/watching/domain/WatchingPoliciesTest.kt
+++ b/composeApp/src/commonTest/kotlin/com/nuvio/app/features/watching/domain/WatchingPoliciesTest.kt
@@ -114,6 +114,20 @@ class WatchingPoliciesTest {
)
}
+ @Test
+ fun shouldSurfaceNextEpisode_keeps_dated_unavailable_episode_visible_on_release_day() {
+ assertTrue(
+ shouldSurfaceNextEpisode(
+ watchedSeasonNumber = 1,
+ candidateSeasonNumber = 1,
+ todayIsoDate = "2026-07-12",
+ releasedDate = "2026-07-12T20:00:00",
+ showUnairedNextUp = true,
+ available = false,
+ ),
+ )
+ }
+
@Test
fun shouldSurfaceNextEpisode_keeps_unavailable_phantom_episode_hidden() {
assertFalse(