diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/player/PlayerEngine.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/player/PlayerEngine.kt index ec41b9f2..bc320feb 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/player/PlayerEngine.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/player/PlayerEngine.kt @@ -52,6 +52,11 @@ data class PlayerControlsState( val episodeText: String = "", val streamTitle: String = "", val providerName: String = "", + val pauseOverlayWatchingLabel: String = "You're watching", + val pauseOverlayLogo: String? = null, + val pauseOverlayEpisodeInfo: String = "", + val pauseOverlayEpisodeTitle: String = "", + val pauseOverlayDescription: String = "", val resizeModeLabel: String = "Fit", val playbackSpeedLabel: String = "1x", val subtitlesLabel: String = "Subs", diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/player/PlayerScreenRuntimeUi.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/player/PlayerScreenRuntimeUi.kt index 66c6d5fe..ac7a07ec 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/player/PlayerScreenRuntimeUi.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/player/PlayerScreenRuntimeUi.kt @@ -163,6 +163,15 @@ internal fun PlayerScreenRuntime.RenderPlayerRuntimeUi() { episodeText = episodeText, streamTitle = activeStreamTitle, providerName = activeProviderName, + pauseOverlayWatchingLabel = stringResource(Res.string.compose_player_youre_watching), + pauseOverlayLogo = logo, + pauseOverlayEpisodeInfo = if (seasonNumber != null && episodeNumber != null) { + stringResource(Res.string.compose_player_episode_code_full, seasonNumber, episodeNumber) + } else { + activeProviderName + }, + pauseOverlayEpisodeTitle = activeEpisodeTitle.orEmpty(), + pauseOverlayDescription = (pauseDescription ?: activeStreamSubtitle).orEmpty(), resizeModeLabel = stringResource(resizeMode.labelRes), playbackSpeedLabel = formatPlaybackSpeedLabel(playbackSnapshot.playbackSpeed), subtitlesLabel = stringResource(Res.string.compose_player_subs), diff --git a/composeApp/src/desktopMain/kotlin/com/nuvio/app/features/player/desktop/NativePlayerController.kt b/composeApp/src/desktopMain/kotlin/com/nuvio/app/features/player/desktop/NativePlayerController.kt index 6665482c..e91d2283 100644 --- a/composeApp/src/desktopMain/kotlin/com/nuvio/app/features/player/desktop/NativePlayerController.kt +++ b/composeApp/src/desktopMain/kotlin/com/nuvio/app/features/player/desktop/NativePlayerController.kt @@ -467,6 +467,16 @@ private fun PlayerControlsState.toControlsJson(): String = append(',') appendJsonField("providerName", providerName) append(',') + appendJsonField("pauseOverlayWatchingLabel", pauseOverlayWatchingLabel) + append(',') + appendJsonField("pauseOverlayLogo", pauseOverlayLogo.orEmpty()) + append(',') + appendJsonField("pauseOverlayEpisodeInfo", pauseOverlayEpisodeInfo) + append(',') + appendJsonField("pauseOverlayEpisodeTitle", pauseOverlayEpisodeTitle) + append(',') + appendJsonField("pauseOverlayDescription", pauseOverlayDescription) + append(',') appendJsonField("resizeModeLabel", resizeModeLabel) append(',') appendJsonField("playbackSpeedLabel", playbackSpeedLabel) diff --git a/composeApp/src/desktopMain/resources/player-ui/controls.css b/composeApp/src/desktopMain/resources/player-ui/controls.css index 4cd77ce5..fcb07112 100644 --- a/composeApp/src/desktopMain/resources/player-ui/controls.css +++ b/composeApp/src/desktopMain/resources/player-ui/controls.css @@ -177,6 +177,7 @@ button:disabled { .player.opening-active .top-gradient, .player.opening-active .bottom-gradient, .player.opening-active .parental-guide, +.player.opening-active .pause-metadata-overlay, .player.opening-active .skip-prompt, .player.opening-active .next-episode-card, .player.opening-active .content { @@ -764,6 +765,163 @@ button:disabled { animation: center-spin 760ms linear infinite; } +.pause-metadata-overlay { + position: absolute; + inset: 0; + z-index: 6; + display: block; + pointer-events: none; + opacity: 0; + background: + linear-gradient( + 90deg, + rgba(0, 0, 0, .85) 0%, + rgba(0, 0, 0, .45) 48%, + rgba(0, 0, 0, 0) 100% + ); + transition: opacity 180ms ease; +} + +.pause-metadata-overlay.visible { + opacity: 1; + transition-duration: 220ms; +} + +.pause-metadata-content { + height: 100%; + display: flex; + flex-direction: column; + justify-content: flex-end; + padding: + 40px + calc(var(--hp) + env(safe-area-inset-right)) + 120px + calc(var(--hp) + env(safe-area-inset-left)); +} + +.pause-kicker { + color: #b8b8b8; + font-size: 18px; + line-height: 1.3; + font-weight: 500; +} + +.pause-logo { + width: min(360px, 62vw); + height: 96px; + margin-top: 12px; + object-fit: contain; + object-position: left bottom; +} + +.pause-logo[hidden], +.pause-title[hidden], +.pause-episode-info[hidden], +.pause-episode-title[hidden], +.pause-description[hidden] { + display: none; +} + +.pause-title { + max-width: 62%; + margin-top: 12px; + color: #fff; + font-size: max(calc(var(--title) * 1.8), 32px); + line-height: 1.08; + font-weight: 800; + overflow: hidden; + text-overflow: ellipsis; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; +} + +.pause-episode-info { + margin-top: 8px; + color: #ccc; + font-size: 18px; + line-height: 1.3; +} + +.pause-episode-title { + max-width: 62%; + margin-top: 12px; + color: #fff; + font-size: 22px; + line-height: 1.25; + font-weight: 700; + overflow: hidden; + text-overflow: ellipsis; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; +} + +.pause-description { + width: 62%; + margin-top: 16px; + color: #d6d6d6; + font-size: 18px; + line-height: 24px; + overflow: hidden; + text-overflow: ellipsis; + display: -webkit-box; + -webkit-line-clamp: 3; + -webkit-box-orient: vertical; +} + +@media (max-height: 419px) { + .pause-metadata-content { + padding-top: 24px; + padding-bottom: 40px; + } + + .pause-kicker, + .pause-episode-info { + font-size: 16px; + } + + .pause-logo { + height: 64px; + margin-top: 8px; + } + + .pause-title { + max-width: 82%; + margin-top: 8px; + font-size: max(calc(var(--title) * 1.35), 32px); + -webkit-line-clamp: 1; + } + + .pause-episode-info { + margin-top: 6px; + } + + .pause-episode-title { + max-width: 82%; + margin-top: 8px; + -webkit-line-clamp: 1; + } + + .pause-description { + width: 82%; + margin-top: 10px; + font-size: 16px; + line-height: 20px; + -webkit-line-clamp: 2; + } +} + +@media (max-height: 339px) { + .pause-metadata-content { + padding-bottom: 24px; + } + + .pause-logo { + height: 48px; + } +} + .opening-overlay { position: absolute; inset: 0; @@ -1844,6 +2002,7 @@ button:focus-visible, .header-actions, .center-controls, .center-status, + .pause-metadata-overlay, .skip-prompt, .next-episode-card, .skip-progress-fill, @@ -1852,6 +2011,7 @@ button:focus-visible, .opening-progress-bar, .opening-artwork, .opening-logo, + .pause-logo, .next-episode-thumb img, .episode-thumb img, .image-loading::before, @@ -1880,4 +2040,4 @@ svg { display: block; fill: currentColor; stroke: none; -} \ No newline at end of file +} diff --git a/composeApp/src/desktopMain/resources/player-ui/controls.html b/composeApp/src/desktopMain/resources/player-ui/controls.html index 134a30ad..1c8328e9 100644 --- a/composeApp/src/desktopMain/resources/player-ui/controls.html +++ b/composeApp/src/desktopMain/resources/player-ui/controls.html @@ -113,6 +113,17 @@ + +