From d17e4c6e808b9e05d66242486be6631f8802438d Mon Sep 17 00:00:00 2001 From: Amonoman Date: Mon, 18 May 2026 16:28:00 +0200 Subject: [PATCH 1/3] feat(lyrics): match predictive back transform to app-wide full-screen pattern MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously the lyrics sheet only applied a translationY of 8 % on back gesture progress. Full-screen destinations across the rest of the app (and Android's own predictive back spec) also shrink and fade the surface so the screen behind is revealed naturally. - scaleX/Y: 1f → 0.92f - translationY: 0 → 8 % of height (unchanged) - alpha: 1f → 0.72f All three are read inside graphicsLayer (draw phase) via the existing backProgressProvider lambda — zero recomposition per gesture frame, consistent with the SheetVisualState pattern. --- .../pixelplay/presentation/components/LyricsSheet.kt | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/theveloper/pixelplay/presentation/components/LyricsSheet.kt b/app/src/main/java/com/theveloper/pixelplay/presentation/components/LyricsSheet.kt index 7a3b71920..16aa137ae 100644 --- a/app/src/main/java/com/theveloper/pixelplay/presentation/components/LyricsSheet.kt +++ b/app/src/main/java/com/theveloper/pixelplay/presentation/components/LyricsSheet.kt @@ -523,10 +523,16 @@ fun LyricsSheet( // Read backProgressProvider inside graphicsLayer (draw-phase) — no layout // pass is triggered per gesture frame, same pattern as SheetVisualState. // 0f = fully visible, 1f = fully dismissed. - // Effect: slides down 8 % of height (no fade). + // Effect: scale down to 92 % + slide down 8 % of height + fade to 72 % alpha. + // Matches Android predictive back spec for full-screen destinations and + // mirrors the scale+alpha treatment used across the rest of the app. .graphicsLayer { val p = backProgressProvider.value - translationY = androidx.compose.ui.util.lerp(0f, size.height * 0.08f, p) + val scale = lerp(1f, 0.92f, p) + scaleX = scale + scaleY = scale + translationY = lerp(0f, size.height * 0.08f, p) + alpha = lerp(1f, 0.72f, p) } .clip(RoundedCornerShape(32.dp)) .pointerInput(Unit) { From 1b401904f8d530c057bccc985bdc03ad52533d87 Mon Sep 17 00:00:00 2001 From: Amonoman Date: Mon, 18 May 2026 16:30:21 +0200 Subject: [PATCH 2/3] feat(lyrics): add scale pop and alpha dim to word-level highlight animation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When animated lyrics is enabled, the active word now springs up to 1.15× scale on highlight and neighbouring words dim to 55 % alpha, making the active word read clearly without relying on colour contrast alone. Both values are driven by animateFloatAsState with the same StiffnessVeryLow / DampingRatioMediumBouncy spring already used for the colour transition, so the whole word feels like a single cohesive motion. Scale and alpha are applied inside graphicsLayer on the visible Text only — the invisible bold spacer Text is unaffected, so layout never changes and there is zero reflow per animation frame. When useAnimatedLyrics is off both animations resolve to their identity values (scale = 1f, alpha = 1f) and are effectively no-ops, keeping the plain mode unchanged. feat(lyrics): add keep-screen-on toggle to lyrics sheet - Toggle persisted to DataStore under "keep_screen_on_lyrics" key - Sets FLAG_KEEP_SCREEN_ON via view.keepScreenOn (no permissions required) - Registers BroadcastReceiver for ACTION_SCREEN_OFF to auto-reset the flag when the screen is turned off by power button or OEM sleep gesture - Flag and receiver are scoped to LyricsSheet composition lifetime - New "Keep screen on" switch added to LyricsMoreBottomSheet Controls group --- .../presentation/components/LyricsSheet.kt | 81 +++++++++++++++++++ .../subcomps/LyricsMoreBottomSheet.kt | 57 +++++++++++-- .../main/res/values-de/strings_components.xml | 1 + .../main/res/values-es/strings_components.xml | 1 + .../main/res/values-fr/strings_components.xml | 1 + .../main/res/values-in/strings_components.xml | 1 + .../main/res/values-it/strings_components.xml | 1 + .../main/res/values-ko/strings_components.xml | 1 + .../main/res/values-nb/strings_components.xml | 1 + .../main/res/values-ru/strings_components.xml | 1 + .../res/values-zh-rCN/strings_components.xml | 1 + .../main/res/values/strings_components.xml | 1 + 12 files changed, 143 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/theveloper/pixelplay/presentation/components/LyricsSheet.kt b/app/src/main/java/com/theveloper/pixelplay/presentation/components/LyricsSheet.kt index 16aa137ae..c4c1674a7 100644 --- a/app/src/main/java/com/theveloper/pixelplay/presentation/components/LyricsSheet.kt +++ b/app/src/main/java/com/theveloper/pixelplay/presentation/components/LyricsSheet.kt @@ -116,6 +116,10 @@ import com.theveloper.pixelplay.presentation.components.snapping.rememberLazyLis import com.theveloper.pixelplay.presentation.components.snapping.rememberSnapperFlingBehavior import com.theveloper.pixelplay.utils.LyricsUtils import com.theveloper.pixelplay.presentation.components.subcomps.LyricsMoreBottomSheet +import android.content.BroadcastReceiver +import android.content.Intent +import android.content.IntentFilter +import androidx.compose.ui.platform.LocalView import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.map import androidx.datastore.preferences.core.booleanPreferencesKey @@ -348,6 +352,27 @@ fun LyricsSheet( } val animatedLyricsBlurStrength by animatedLyricsBlurStrengthFlow.collectAsStateWithLifecycle(initialValue = 2.5f) + // Read keep-screen-on preference from DataStore + val keepScreenOnFlow = remember(context) { + context.dataStore.data.map { it[booleanPreferencesKey("keep_screen_on_lyrics")] ?: false } + } + var keepScreenOn by remember { mutableStateOf(false) } + // Sync DataStore → local state + LaunchedEffect(Unit) { + keepScreenOnFlow.collect { keepScreenOn = it } + } + + // Apply FLAG_KEEP_SCREEN_ON via the window when enabled + val view = LocalView.current + DisposableEffect(keepScreenOn) { + if (keepScreenOn) { + view.keepScreenOn = true + } + onDispose { + view.keepScreenOn = false + } + } + val resolvedAutoscrollSpec = autoscrollAnimationSpec ?: if (useAnimatedLyrics) { spring( stiffness = Spring.StiffnessMediumLow, @@ -397,6 +422,25 @@ fun LyricsSheet( val swipeProgress = remember { Animatable(0f) } val coroutineScope = rememberCoroutineScope() + // Reset keep-screen-on when the physical screen goes off (power button / OEM sleep gesture). + // ACTION_SCREEN_OFF is a guaranteed platform broadcast; no OEM can suppress it. + DisposableEffect(Unit) { + val receiver = object : BroadcastReceiver() { + override fun onReceive(ctx: android.content.Context, intent: Intent) { + if (intent.action == Intent.ACTION_SCREEN_OFF) { + keepScreenOn = false + coroutineScope.launch { + context.dataStore.edit { prefs -> + prefs[booleanPreferencesKey("keep_screen_on_lyrics")] = false + } + } + } + } + } + context.registerReceiver(receiver, IntentFilter(Intent.ACTION_SCREEN_OFF)) + onDispose { context.unregisterReceiver(receiver) } + } + // Auto-hide controls logic LaunchedEffect(immersiveLyricsEnabled, lastInteractionTime, showSyncedLyrics, isImmersiveTemporarilyDisabled) { if (immersiveLyricsEnabled && showSyncedLyrics == true && !isImmersiveTemporarilyDisabled) { @@ -944,6 +988,15 @@ fun LyricsSheet( resetImmersiveTimer() onSetImmersiveTemporarilyDisabled(it) }, + keepScreenOn = keepScreenOn, + onKeepScreenOnChange = { enabled -> + keepScreenOn = enabled + coroutineScope.launch { + context.dataStore.edit { prefs -> + prefs[booleanPreferencesKey("keep_screen_on_lyrics")] = enabled + } + } + }, lyricsAlignment = lyricsAlignment, onLyricsAlignmentChange = { newAlignment -> coroutineScope.launch { @@ -1568,6 +1621,11 @@ fun LyricWordSpan( unhighlightedColor: Color, modifier: Modifier = Modifier ) { + val wordAnimSpec = if (useAnimatedLyrics) spring( + stiffness = Spring.StiffnessVeryLow, + dampingRatio = Spring.DampingRatioMediumBouncy + ) else tween(durationMillis = 200) + val color by animateColorAsState( targetValue = if (isHighlighted) highlightedColor else unhighlightedColor, animationSpec = if (useAnimatedLyrics) spring( @@ -1576,6 +1634,23 @@ fun LyricWordSpan( ) else tween(durationMillis = 200), label = "wordColor" ) + + // Scale: pop up to 1.15 on highlight, settle back to 1f. Only active when + // animated lyrics is on — layout is untouched because it's applied in graphicsLayer. + val scale by animateFloatAsState( + targetValue = if (useAnimatedLyrics && isHighlighted) 1.15f else 1f, + animationSpec = wordAnimSpec, + label = "wordScale" + ) + + // Alpha: unhighlighted words dim slightly so the active word pops without + // needing a hard color contrast. Only active when animated lyrics is on. + val alpha by animateFloatAsState( + targetValue = if (useAnimatedLyrics && !isHighlighted) 0.55f else 1f, + animationSpec = wordAnimSpec, + label = "wordAlpha" + ) + Box( modifier = modifier, contentAlignment = Alignment.Center @@ -1592,6 +1667,12 @@ fun LyricWordSpan( style = style, color = color, fontWeight = if (isHighlighted) FontWeight.Bold else FontWeight.Normal, + // Scale and alpha applied at draw phase — zero layout impact per frame. + modifier = Modifier.graphicsLayer { + scaleX = scale + scaleY = scale + this.alpha = alpha + } ) } } diff --git a/app/src/main/java/com/theveloper/pixelplay/presentation/components/subcomps/LyricsMoreBottomSheet.kt b/app/src/main/java/com/theveloper/pixelplay/presentation/components/subcomps/LyricsMoreBottomSheet.kt index bd2512416..d6ce2269c 100644 --- a/app/src/main/java/com/theveloper/pixelplay/presentation/components/subcomps/LyricsMoreBottomSheet.kt +++ b/app/src/main/java/com/theveloper/pixelplay/presentation/components/subcomps/LyricsMoreBottomSheet.kt @@ -21,6 +21,7 @@ import androidx.compose.material.icons.rounded.Abc import androidx.compose.material.icons.rounded.FormatAlignCenter import androidx.compose.material.icons.rounded.Tune import androidx.compose.material.icons.rounded.Translate +import androidx.compose.material.icons.rounded.BrightnessHigh import androidx.compose.material.icons.rounded.VisibilityOff import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi @@ -66,6 +67,8 @@ fun LyricsMoreBottomSheet( onToggleSyncControls: () -> Unit, isImmersiveTemporarilyDisabled: Boolean, onSetImmersiveTemporarilyDisabled: (Boolean) -> Unit, + keepScreenOn: Boolean, + onKeepScreenOnChange: (Boolean) -> Unit, lyricsAlignment: String, onLyricsAlignmentChange: (String) -> Unit, hasTranslatedLyrics: Boolean, @@ -292,15 +295,17 @@ fun LyricsMoreBottomSheet( val isRomanizationVisible = hasRomanizedLyrics val isTranslationVisible = hasTranslatedLyrics val isImmersiveVisible = showSyncedLyrics && immersiveLyricsEnabled + val isKeepScreenOnVisible = true - if (isSyncVisible || isRomanizationVisible || isTranslationVisible) { + if (isSyncVisible || isRomanizationVisible || isTranslationVisible || isKeepScreenOnVisible) { // Determine first and last items for rounding val isRomanizationFirst = isRomanizationVisible && !isSyncVisible val isTranslationFirst = isTranslationVisible && !isSyncVisible && !isRomanizationVisible - val isSyncLast = isSyncVisible && !isRomanizationVisible && !isTranslationVisible && !isImmersiveVisible - val isRomanizationLast = isRomanizationVisible && !isTranslationVisible && !isImmersiveVisible - val isTranslationLast = isTranslationVisible && !isImmersiveVisible + val isSyncLast = isSyncVisible && !isRomanizationVisible && !isTranslationVisible && !isImmersiveVisible && !isKeepScreenOnVisible + val isRomanizationLast = isRomanizationVisible && !isTranslationVisible && !isImmersiveVisible && !isKeepScreenOnVisible + val isTranslationLast = isTranslationVisible && !isImmersiveVisible && !isKeepScreenOnVisible + val isImmersiveLast = isImmersiveVisible && !isKeepScreenOnVisible Column( verticalArrangement = Arrangement.spacedBy(2.dp), @@ -461,6 +466,47 @@ fun LyricsMoreBottomSheet( ) ) }, + modifier = Modifier + .fillMaxWidth() + .clip( + RoundedCornerShape( + topStart = 8.dp, + topEnd = 8.dp, + bottomStart = if (isImmersiveLast) 24.dp else 8.dp, + bottomEnd = if (isImmersiveLast) 24.dp else 8.dp + ) + ) + .background(itemBackgroundColor), + colors = ListItemDefaults.colors( + containerColor = Color.Transparent, + headlineColor = contentColor, + leadingIconColor = contentColor + ) + ) + } + + // Keep Screen On Toggle + if (isKeepScreenOnVisible) { + ListItem( + headlineContent = { Text(stringResource(R.string.lyrics_more_keep_screen_on)) }, + leadingContent = { + Icon( + imageVector = Icons.Rounded.BrightnessHigh, + contentDescription = null + ) + }, + trailingContent = { + Switch( + checked = keepScreenOn, + onCheckedChange = onKeepScreenOnChange, + colors = SwitchDefaults.colors( + checkedThumbColor = onAccentColor, + checkedTrackColor = accentColor, + uncheckedThumbColor = contentColor, + uncheckedTrackColor = contentColor.copy(alpha = 0.3f) + ) + ) + }, modifier = Modifier .fillMaxWidth() .clip( @@ -471,7 +517,8 @@ fun LyricsMoreBottomSheet( bottomEnd = 24.dp ) ) - .background(itemBackgroundColor), + .background(itemBackgroundColor) + .clickable { onKeepScreenOnChange(!keepScreenOn) }, colors = ListItemDefaults.colors( containerColor = Color.Transparent, headlineColor = contentColor, diff --git a/app/src/main/res/values-de/strings_components.xml b/app/src/main/res/values-de/strings_components.xml index 54d6661cc..e109fa39e 100644 --- a/app/src/main/res/values-de/strings_components.xml +++ b/app/src/main/res/values-de/strings_components.xml @@ -23,6 +23,7 @@ Romanisierung anzeigen Übersetzungen anzeigen Immersive einmal deaktivieren + Bildschirm an lassen Lyrics linksbündig Lyrics zentriert Lyrics rechtsbündig diff --git a/app/src/main/res/values-es/strings_components.xml b/app/src/main/res/values-es/strings_components.xml index 86dcfd8cd..860e34c1c 100644 --- a/app/src/main/res/values-es/strings_components.xml +++ b/app/src/main/res/values-es/strings_components.xml @@ -23,6 +23,7 @@ Mostrar romanización Mostrar traducciones Desactivar inmersivo (una vez) + Keep screen on Alinear letras a la izquierda Alinear letras al centro Alinear letras a la derecha diff --git a/app/src/main/res/values-fr/strings_components.xml b/app/src/main/res/values-fr/strings_components.xml index 3850470c3..4c600584c 100644 --- a/app/src/main/res/values-fr/strings_components.xml +++ b/app/src/main/res/values-fr/strings_components.xml @@ -23,6 +23,7 @@ Afficher la romanisation Afficher les traductions Désactiver l\'immersion (une fois) + Keep screen on Aligner les paroles à gauche Aligner les paroles au centre Aligner les paroles à droite diff --git a/app/src/main/res/values-in/strings_components.xml b/app/src/main/res/values-in/strings_components.xml index 5d8e655f9..70f0c06c4 100644 --- a/app/src/main/res/values-in/strings_components.xml +++ b/app/src/main/res/values-in/strings_components.xml @@ -23,6 +23,7 @@ Tampilkan romanisasi Tampilkan terjemahan Nonaktifkan imersif (sekali) + Keep screen on Rata kiri lirik Rata tengah lirik Rata kanan lirik diff --git a/app/src/main/res/values-it/strings_components.xml b/app/src/main/res/values-it/strings_components.xml index fad80402c..41b2d1fdf 100644 --- a/app/src/main/res/values-it/strings_components.xml +++ b/app/src/main/res/values-it/strings_components.xml @@ -23,6 +23,7 @@ Mostra romanizzazione Mostra traduzioni Disabilita immersivo (una volta) + Keep screen on Allinea testo a sinistra Allinea testo al centro Allinea testo a destra diff --git a/app/src/main/res/values-ko/strings_components.xml b/app/src/main/res/values-ko/strings_components.xml index 0418da88c..bbf76cfba 100644 --- a/app/src/main/res/values-ko/strings_components.xml +++ b/app/src/main/res/values-ko/strings_components.xml @@ -23,6 +23,7 @@ 로마자 표기 표시 번역 표시 몰입 모드 해제 (1회) + Keep screen on 가사 왼쪽 정렬 가사 가운데 정렬 가사 오른쪽 정렬 diff --git a/app/src/main/res/values-nb/strings_components.xml b/app/src/main/res/values-nb/strings_components.xml index fbe10278c..3952f2e06 100644 --- a/app/src/main/res/values-nb/strings_components.xml +++ b/app/src/main/res/values-nb/strings_components.xml @@ -23,6 +23,7 @@ Vis romanisering Vis oversettelser Deaktiver immersiv modus (én gang) + Keep screen on Venstrejuster tekst Midtstill tekst Høyrejuster tekst diff --git a/app/src/main/res/values-ru/strings_components.xml b/app/src/main/res/values-ru/strings_components.xml index f60c007a7..8f9d051ee 100644 --- a/app/src/main/res/values-ru/strings_components.xml +++ b/app/src/main/res/values-ru/strings_components.xml @@ -23,6 +23,7 @@ Показать романизацию Показать перевод Выйти из иммерсивного (раз) + Keep screen on По левому краю По центру По правому краю diff --git a/app/src/main/res/values-zh-rCN/strings_components.xml b/app/src/main/res/values-zh-rCN/strings_components.xml index a23f7f816..150201e7d 100644 --- a/app/src/main/res/values-zh-rCN/strings_components.xml +++ b/app/src/main/res/values-zh-rCN/strings_components.xml @@ -23,6 +23,7 @@ 显示罗马音 显示翻译 关闭沉浸模式(仅本次) + Keep screen on 歌词左对齐 歌词居中对齐 歌词右对齐 diff --git a/app/src/main/res/values/strings_components.xml b/app/src/main/res/values/strings_components.xml index 898e50583..6105eff3b 100644 --- a/app/src/main/res/values/strings_components.xml +++ b/app/src/main/res/values/strings_components.xml @@ -23,6 +23,7 @@ Show romanization Show translations Disable immersive (once) + Keep screen on Align lyrics left Align lyrics center Align lyrics right From 76ba269ebcb38a1d447a361b175601dfa55a4b4b Mon Sep 17 00:00:00 2001 From: theo Date: Mon, 18 May 2026 01:46:06 -0300 Subject: [PATCH 3/3] Fix compact navbar gradient height feat(lyrics): add keep-screen-on toggle and improve animations --- .../presentation/components/LyricsSheet.kt | 48 +++++++++++++++++-- .../components/PlayerInternalNavigationBar.kt | 4 ++ .../subcomps/LyricsMoreBottomSheet.kt | 2 + .../presentation/screens/HomeScreen.kt | 6 ++- .../presentation/screens/LibraryScreen.kt | 4 +- .../presentation/screens/SearchScreen.kt | 4 +- 6 files changed, 59 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/com/theveloper/pixelplay/presentation/components/LyricsSheet.kt b/app/src/main/java/com/theveloper/pixelplay/presentation/components/LyricsSheet.kt index c4c1674a7..ba47c08ea 100644 --- a/app/src/main/java/com/theveloper/pixelplay/presentation/components/LyricsSheet.kt +++ b/app/src/main/java/com/theveloper/pixelplay/presentation/components/LyricsSheet.kt @@ -361,15 +361,55 @@ fun LyricsSheet( LaunchedEffect(Unit) { keepScreenOnFlow.collect { keepScreenOn = it } } + val coroutineScope = rememberCoroutineScope() // Apply FLAG_KEEP_SCREEN_ON via the window when enabled val view = LocalView.current - DisposableEffect(keepScreenOn) { + val lifecycleOwner = androidx.lifecycle.compose.LocalLifecycleOwner.current + + DisposableEffect(keepScreenOn, lifecycleOwner) { + val observer = androidx.lifecycle.LifecycleEventObserver { _, event -> + if (event == androidx.lifecycle.Lifecycle.Event.ON_STOP && keepScreenOn) { + keepScreenOn = false + coroutineScope.launch { + context.dataStore.edit { prefs -> + prefs[booleanPreferencesKey("keep_screen_on_lyrics")] = false + } + } + } + } + + if (keepScreenOn) { + view.keepScreenOn = true + } + + lifecycleOwner.lifecycle.addObserver(observer) + onDispose { + view.keepScreenOn = false + lifecycleOwner.lifecycle.removeObserver(observer) + } + } + + DisposableEffect(keepScreenOn, lifecycleOwner) { + val observer = androidx.lifecycle.LifecycleEventObserver { _, event -> + if (event == androidx.lifecycle.Lifecycle.Event.ON_STOP && keepScreenOn) { + keepScreenOn = false + coroutineScope.launch { + context.dataStore.edit { prefs -> + prefs[booleanPreferencesKey("keep_screen_on_lyrics")] = false + } + } + } + } + if (keepScreenOn) { view.keepScreenOn = true } + + lifecycleOwner.lifecycle.addObserver(observer) onDispose { view.keepScreenOn = false + lifecycleOwner.lifecycle.removeObserver(observer) } } @@ -420,7 +460,6 @@ fun LyricsSheet( val swipeThresholdPx = with(LocalDensity.current) { swipeThreshold.toPx() } val overlayTranslation = remember { Animatable(0f) } val swipeProgress = remember { Animatable(0f) } - val coroutineScope = rememberCoroutineScope() // Reset keep-screen-on when the physical screen goes off (power button / OEM sleep gesture). // ACTION_SCREEN_OFF is a guaranteed platform broadcast; no OEM can suppress it. @@ -576,7 +615,6 @@ fun LyricsSheet( scaleX = scale scaleY = scale translationY = lerp(0f, size.height * 0.08f, p) - alpha = lerp(1f, 0.72f, p) } .clip(RoundedCornerShape(32.dp)) .pointerInput(Unit) { @@ -1635,10 +1673,10 @@ fun LyricWordSpan( label = "wordColor" ) - // Scale: pop up to 1.15 on highlight, settle back to 1f. Only active when + // Scale: pop up to 1.10 on highlight, settle back to 1f. Only active when // animated lyrics is on — layout is untouched because it's applied in graphicsLayer. val scale by animateFloatAsState( - targetValue = if (useAnimatedLyrics && isHighlighted) 1.15f else 1f, + targetValue = if (useAnimatedLyrics && isHighlighted) 1.10f else 1f, animationSpec = wordAnimSpec, label = "wordScale" ) diff --git a/app/src/main/java/com/theveloper/pixelplay/presentation/components/PlayerInternalNavigationBar.kt b/app/src/main/java/com/theveloper/pixelplay/presentation/components/PlayerInternalNavigationBar.kt index 91dbb0355..26cd5b9f9 100644 --- a/app/src/main/java/com/theveloper/pixelplay/presentation/components/PlayerInternalNavigationBar.kt +++ b/app/src/main/java/com/theveloper/pixelplay/presentation/components/PlayerInternalNavigationBar.kt @@ -37,6 +37,7 @@ import kotlinx.coroutines.launch internal val NavBarContentHeight = 90.dp // Altura del contenido de la barra de navegación internal val NavBarCompactContentHeight = 64.dp internal val NavBarContentHeightFullWidth = NavBarContentHeight // Altura del contenido de la barra de navegación en modo completo +private val MainScreenBottomGradientExtraHeight = MiniPlayerHeight + MiniPlayerBottomSpacer + 8.dp // Some OEM freeform/floating-window modes can report a bottom inset close to the whole window height. internal val MaxNavigationBarBottomInset = 96.dp @@ -64,6 +65,9 @@ internal fun calculatePlayerSheetCollapsedTargetY( internal fun resolveNavBarContentHeight(compactMode: Boolean): Dp = if (compactMode) NavBarCompactContentHeight else NavBarContentHeight +internal fun resolveMainScreenBottomGradientHeight(compactMode: Boolean): Dp = + resolveNavBarContentHeight(compactMode) + MainScreenBottomGradientExtraHeight + internal fun resolveNavBarSurfaceHeight( navBarStyle: String, systemNavBarInset: Dp, diff --git a/app/src/main/java/com/theveloper/pixelplay/presentation/components/subcomps/LyricsMoreBottomSheet.kt b/app/src/main/java/com/theveloper/pixelplay/presentation/components/subcomps/LyricsMoreBottomSheet.kt index d6ce2269c..64b66eeef 100644 --- a/app/src/main/java/com/theveloper/pixelplay/presentation/components/subcomps/LyricsMoreBottomSheet.kt +++ b/app/src/main/java/com/theveloper/pixelplay/presentation/components/subcomps/LyricsMoreBottomSheet.kt @@ -22,6 +22,8 @@ import androidx.compose.material.icons.rounded.FormatAlignCenter import androidx.compose.material.icons.rounded.Tune import androidx.compose.material.icons.rounded.Translate import androidx.compose.material.icons.rounded.BrightnessHigh +import androidx.compose.material.icons.rounded.Check +import androidx.compose.material.icons.rounded.Close import androidx.compose.material.icons.rounded.VisibilityOff import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi diff --git a/app/src/main/java/com/theveloper/pixelplay/presentation/screens/HomeScreen.kt b/app/src/main/java/com/theveloper/pixelplay/presentation/screens/HomeScreen.kt index c3177f731..2a386b601 100644 --- a/app/src/main/java/com/theveloper/pixelplay/presentation/screens/HomeScreen.kt +++ b/app/src/main/java/com/theveloper/pixelplay/presentation/screens/HomeScreen.kt @@ -96,11 +96,11 @@ import com.theveloper.pixelplay.presentation.components.DailyMixSection import com.theveloper.pixelplay.presentation.components.HomeGradientTopBar import com.theveloper.pixelplay.presentation.components.HomeOptionsBottomSheet import com.theveloper.pixelplay.presentation.components.MiniPlayerHeight -import com.theveloper.pixelplay.presentation.components.NavBarContentHeight import com.theveloper.pixelplay.presentation.components.RecentlyPlayedSection import com.theveloper.pixelplay.presentation.components.RecentlyPlayedSectionMinSongsToShow import com.theveloper.pixelplay.presentation.components.SmartImage import com.theveloper.pixelplay.presentation.components.StatsOverviewCard +import com.theveloper.pixelplay.presentation.components.resolveMainScreenBottomGradientHeight import com.theveloper.pixelplay.presentation.model.collectRecentlyPlayedSongIds import com.theveloper.pixelplay.presentation.model.mapRecentlyPlayedSongs import com.theveloper.pixelplay.presentation.components.subcomps.PlayingEqIcon @@ -244,6 +244,8 @@ fun HomeScreen( // Padding inferior si hay canción en reproducción val bottomPadding = if (currentSong != null) MiniPlayerHeight else 0.dp + val navBarCompactMode by playerViewModel.navBarCompactMode.collectAsStateWithLifecycle() + val bottomGradientHeight = resolveMainScreenBottomGradientHeight(navBarCompactMode) var showOptionsBottomSheet by remember { mutableStateOf(false) } var showChangelogBottomSheet by remember { mutableStateOf(false) } @@ -494,7 +496,7 @@ fun HomeScreen( modifier = Modifier .fillMaxWidth() .align(Alignment.BottomCenter) - .height(170.dp) + .height(bottomGradientHeight) .background( brush = Brush.verticalGradient( colorStops = arrayOf( diff --git a/app/src/main/java/com/theveloper/pixelplay/presentation/screens/LibraryScreen.kt b/app/src/main/java/com/theveloper/pixelplay/presentation/screens/LibraryScreen.kt index 425c81cd1..97817275a 100644 --- a/app/src/main/java/com/theveloper/pixelplay/presentation/screens/LibraryScreen.kt +++ b/app/src/main/java/com/theveloper/pixelplay/presentation/screens/LibraryScreen.kt @@ -140,6 +140,7 @@ import com.theveloper.pixelplay.data.model.SortOption import com.theveloper.pixelplay.data.model.StorageFilter import com.theveloper.pixelplay.presentation.components.MiniPlayerHeight import com.theveloper.pixelplay.presentation.components.SmartImage +import com.theveloper.pixelplay.presentation.components.resolveMainScreenBottomGradientHeight import com.theveloper.pixelplay.presentation.components.resolveNavBarOccupiedHeight import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.navigationBars @@ -799,6 +800,7 @@ fun LibraryScreen( val systemNavBarInset = WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding() val navBarCompactMode by playerViewModel.navBarCompactMode.collectAsStateWithLifecycle() val bottomBarHeightDp = resolveNavBarOccupiedHeight(systemNavBarInset, navBarCompactMode) + val bottomGradientHeight = resolveMainScreenBottomGradientHeight(navBarCompactMode) val dm = LocalPixelPlayDarkTheme.current @@ -1733,7 +1735,7 @@ fun LibraryScreen( modifier = Modifier .fillMaxWidth() .align(Alignment.BottomCenter) - .height(170.dp) + .height(bottomGradientHeight) .background( brush = Brush.verticalGradient( colorStops = arrayOf( diff --git a/app/src/main/java/com/theveloper/pixelplay/presentation/screens/SearchScreen.kt b/app/src/main/java/com/theveloper/pixelplay/presentation/screens/SearchScreen.kt index 13ca51f23..f1fdaf33d 100644 --- a/app/src/main/java/com/theveloper/pixelplay/presentation/screens/SearchScreen.kt +++ b/app/src/main/java/com/theveloper/pixelplay/presentation/screens/SearchScreen.kt @@ -109,6 +109,7 @@ import com.theveloper.pixelplay.data.repository.MusicRepository import com.theveloper.pixelplay.presentation.components.MiniPlayerHeight import com.theveloper.pixelplay.presentation.components.PlaylistBottomSheet import com.theveloper.pixelplay.presentation.components.PlaylistCover +import com.theveloper.pixelplay.presentation.components.resolveMainScreenBottomGradientHeight import com.theveloper.pixelplay.presentation.components.resolveNavBarOccupiedHeight import com.theveloper.pixelplay.presentation.navigation.Screen import com.theveloper.pixelplay.presentation.screens.search.components.GenreCategoriesGrid @@ -147,6 +148,7 @@ fun SearchScreen( val systemNavBarInset = WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding() val navBarCompactMode by playerViewModel.navBarCompactMode.collectAsStateWithLifecycle() val bottomBarHeightDp = resolveNavBarOccupiedHeight(systemNavBarInset, navBarCompactMode) + val bottomGradientHeight = resolveMainScreenBottomGradientHeight(navBarCompactMode) var showPlaylistBottomSheet by remember { mutableStateOf(false) } val searchUiState by remember(playerViewModel) { playerViewModel.playerUiState @@ -424,7 +426,7 @@ fun SearchScreen( modifier = Modifier .fillMaxWidth() .align(Alignment.BottomCenter) - .height(170.dp) + .height(bottomGradientHeight) .background(brush = bottomGradientBrush) ) }