From d24eff19ccb9702343fc4a6211e3fc1b843d45c5 Mon Sep 17 00:00:00 2001 From: Barnabas Balogh Date: Tue, 27 Jan 2026 19:16:23 +0100 Subject: [PATCH] refactor: improve player gesture feedback with timed visibility components - Replace `LaunchedEffect` and manual state handling for showing/hiding player overlays (brightness, volume, seek feedback) with new reusable timed visibility composables. - Introduce `ValueChangeTimedVisibility` to automatically show brightness and volume sliders for a short duration when their values change. - Implement `EmptyValueTimedVisibility` to display the horizontal seek amount indicator and hide it after a delay. - Remove redundant state variables (`brightnessOverlayVisible`, `volumeOverlayVisible`, `showFeedbackPreview`) and related logic from `PlayerScreen`. - Clean up `PlayerGesturesLayer` by removing the `setFeedBackPreview` callback, simplifying its responsibility. - Remove the auto-hide `LaunchedEffect` from `PlayerSideSliders` as this is now handled externally. --- .../bbara/purefin/player/ui/PlayerScreen.kt | 60 +++++++++---------- .../ui/components/PlayerGesturesLayer.kt | 5 -- .../player/ui/components/PlayerSideSliders.kt | 10 ---- 3 files changed, 28 insertions(+), 47 deletions(-) diff --git a/app/src/main/java/hu/bbara/purefin/player/ui/PlayerScreen.kt b/app/src/main/java/hu/bbara/purefin/player/ui/PlayerScreen.kt index 719dd15..dc3c6fd 100644 --- a/app/src/main/java/hu/bbara/purefin/player/ui/PlayerScreen.kt +++ b/app/src/main/java/hu/bbara/purefin/player/ui/PlayerScreen.kt @@ -33,6 +33,8 @@ import androidx.compose.ui.viewinterop.AndroidView import androidx.media3.common.util.UnstableApi import androidx.media3.ui.AspectRatioFrameLayout import androidx.media3.ui.PlayerView +import hu.bbara.purefin.common.ui.components.EmptyValueTimedVisibility +import hu.bbara.purefin.common.ui.components.ValueChangeTimedVisibility import hu.bbara.purefin.player.ui.components.PlayerControlsOverlay import hu.bbara.purefin.player.ui.components.PlayerGesturesLayer import hu.bbara.purefin.player.ui.components.PlayerLoadingErrorEndCard @@ -40,7 +42,6 @@ import hu.bbara.purefin.player.ui.components.PlayerQueuePanel import hu.bbara.purefin.player.ui.components.PlayerSettingsSheet import hu.bbara.purefin.player.ui.components.PlayerSideSliders import hu.bbara.purefin.player.viewmodel.PlayerViewModel -import kotlinx.coroutines.delay import kotlin.math.abs import kotlin.math.roundToInt @@ -61,18 +62,8 @@ fun PlayerScreen( var volume by remember { mutableStateOf(audioManager.getStreamVolume(AudioManager.STREAM_MUSIC) / maxVolume.toFloat()) } var brightness by remember { mutableStateOf(readCurrentBrightness(activity)) } var showSettings by remember { mutableStateOf(false) } - var brightnessOverlayVisible by remember { mutableStateOf(false) } - var volumeOverlayVisible by remember { mutableStateOf(false) } var showQueuePanel by remember { mutableStateOf(false) } var horizontalSeekFeedback by remember { mutableStateOf(null) } - var showFeedbackPreview by remember { mutableStateOf(false) } - - LaunchedEffect(showFeedbackPreview) { - if (!showFeedbackPreview) { - delay(1000) - horizontalSeekFeedback = null - } - } LaunchedEffect(uiState.isPlaying) { if (uiState.isPlaying) { @@ -111,22 +102,17 @@ fun PlayerScreen( onVerticalDragLeft = { delta -> val diff = (-delta / 800f) brightness = (brightness + diff).coerceIn(0f, 1f) - brightnessOverlayVisible = true applyBrightness(activity, brightness) }, onVerticalDragRight = { delta -> val diff = (-delta / 800f) volume = (volume + diff).coerceIn(0f, 1f) - volumeOverlayVisible = true audioManager.setStreamVolume( AudioManager.STREAM_MUSIC, (volume * maxVolume).roundToInt(), 0 ) }, - setFeedBackPreview = { - showFeedbackPreview = it - }, onHorizontalDragPreview = { horizontalSeekFeedback = it }, @@ -136,30 +122,40 @@ fun PlayerScreen( } ) - horizontalSeekFeedback?.let { delta -> + EmptyValueTimedVisibility( + value = horizontalSeekFeedback, + hideAfterMillis = 1_000 + ) { SeekAmountIndicator( - deltaMs = delta, + deltaMs = it, modifier = Modifier .align(Alignment.Center) ) } - AnimatedVisibility( - visible = volumeOverlayVisible || brightnessOverlayVisible, - enter = fadeIn(), - exit = fadeOut() - ) { + ValueChangeTimedVisibility( + value = brightness, + hideAfterMillis = 800 + ) { currentBrightness -> PlayerSideSliders( - modifier = Modifier - .fillMaxSize(), - brightness = brightness, + modifier = Modifier.fillMaxSize(), + brightness = currentBrightness, volume = volume, - showBrightness = brightnessOverlayVisible, - showVolume = volumeOverlayVisible, - onHide = { - brightnessOverlayVisible = false - volumeOverlayVisible = false - } + showBrightness = true, + showVolume = false, + ) + } + + ValueChangeTimedVisibility( + value = volume, + hideAfterMillis = 800 + ) { currentVolume -> + PlayerSideSliders( + modifier = Modifier.fillMaxSize(), + brightness = brightness, + volume = currentVolume, + showBrightness = false, + showVolume = true, ) } diff --git a/app/src/main/java/hu/bbara/purefin/player/ui/components/PlayerGesturesLayer.kt b/app/src/main/java/hu/bbara/purefin/player/ui/components/PlayerGesturesLayer.kt index f484691..6b26085 100644 --- a/app/src/main/java/hu/bbara/purefin/player/ui/components/PlayerGesturesLayer.kt +++ b/app/src/main/java/hu/bbara/purefin/player/ui/components/PlayerGesturesLayer.kt @@ -21,7 +21,6 @@ fun PlayerGesturesLayer( onVerticalDragRight: (delta: Float) -> Unit, onHorizontalDragPreview: (deltaMs: Long?) -> Unit = {}, onHorizontalDrag: (deltaMs: Long) -> Unit, - setFeedBackPreview: (show: Boolean) -> Unit ) { val density = LocalDensity.current val horizontalThresholdPx = with(density) { HorizontalSeekGestureHelper.START_THRESHOLD.toPx() } @@ -66,14 +65,12 @@ fun PlayerGesturesLayer( accumulatedHorizontalDrag = 0f isHorizontalDragActive = false lastPreviewDelta = null - setFeedBackPreview(false) onHorizontalDragPreview(null) }, onHorizontalDrag = { change, dragAmount -> accumulatedHorizontalDrag += dragAmount if (!isHorizontalDragActive && kotlin.math.abs(accumulatedHorizontalDrag) >= horizontalThresholdPx) { isHorizontalDragActive = true - setFeedBackPreview(true) } if (isHorizontalDragActive) { change.consume() @@ -95,14 +92,12 @@ fun PlayerGesturesLayer( accumulatedHorizontalDrag = 0f isHorizontalDragActive = false lastPreviewDelta = null - setFeedBackPreview(false) onHorizontalDragPreview(null) }, onDragCancel = { accumulatedHorizontalDrag = 0f isHorizontalDragActive = false lastPreviewDelta = null - setFeedBackPreview(false) onHorizontalDragPreview(null) } ) diff --git a/app/src/main/java/hu/bbara/purefin/player/ui/components/PlayerSideSliders.kt b/app/src/main/java/hu/bbara/purefin/player/ui/components/PlayerSideSliders.kt index 07529f8..cbeaeb7 100644 --- a/app/src/main/java/hu/bbara/purefin/player/ui/components/PlayerSideSliders.kt +++ b/app/src/main/java/hu/bbara/purefin/player/ui/components/PlayerSideSliders.kt @@ -15,12 +15,10 @@ import androidx.compose.material3.Icon import androidx.compose.material3.LinearProgressIndicator import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.unit.dp -import kotlinx.coroutines.delay @Composable fun PlayerSideSliders( @@ -29,17 +27,9 @@ fun PlayerSideSliders( volume: Float, showBrightness: Boolean, showVolume: Boolean, - onHide: () -> Unit ) { val scheme = MaterialTheme.colorScheme - LaunchedEffect(showBrightness, showVolume) { - if (showBrightness || showVolume) { - delay(800) - onHide() - } - } - Box(modifier = modifier.fillMaxWidth()) { if (showBrightness) { SideOverlay(