mirror of
https://github.com/bbara04/Purefin.git
synced 2026-03-31 17:10:08 +02:00
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.
This commit is contained in:
@@ -33,6 +33,8 @@ import androidx.compose.ui.viewinterop.AndroidView
|
|||||||
import androidx.media3.common.util.UnstableApi
|
import androidx.media3.common.util.UnstableApi
|
||||||
import androidx.media3.ui.AspectRatioFrameLayout
|
import androidx.media3.ui.AspectRatioFrameLayout
|
||||||
import androidx.media3.ui.PlayerView
|
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.PlayerControlsOverlay
|
||||||
import hu.bbara.purefin.player.ui.components.PlayerGesturesLayer
|
import hu.bbara.purefin.player.ui.components.PlayerGesturesLayer
|
||||||
import hu.bbara.purefin.player.ui.components.PlayerLoadingErrorEndCard
|
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.PlayerSettingsSheet
|
||||||
import hu.bbara.purefin.player.ui.components.PlayerSideSliders
|
import hu.bbara.purefin.player.ui.components.PlayerSideSliders
|
||||||
import hu.bbara.purefin.player.viewmodel.PlayerViewModel
|
import hu.bbara.purefin.player.viewmodel.PlayerViewModel
|
||||||
import kotlinx.coroutines.delay
|
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
@@ -61,18 +62,8 @@ fun PlayerScreen(
|
|||||||
var volume by remember { mutableStateOf(audioManager.getStreamVolume(AudioManager.STREAM_MUSIC) / maxVolume.toFloat()) }
|
var volume by remember { mutableStateOf(audioManager.getStreamVolume(AudioManager.STREAM_MUSIC) / maxVolume.toFloat()) }
|
||||||
var brightness by remember { mutableStateOf(readCurrentBrightness(activity)) }
|
var brightness by remember { mutableStateOf(readCurrentBrightness(activity)) }
|
||||||
var showSettings by remember { mutableStateOf(false) }
|
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 showQueuePanel by remember { mutableStateOf(false) }
|
||||||
var horizontalSeekFeedback by remember { mutableStateOf<Long?>(null) }
|
var horizontalSeekFeedback by remember { mutableStateOf<Long?>(null) }
|
||||||
var showFeedbackPreview by remember { mutableStateOf(false) }
|
|
||||||
|
|
||||||
LaunchedEffect(showFeedbackPreview) {
|
|
||||||
if (!showFeedbackPreview) {
|
|
||||||
delay(1000)
|
|
||||||
horizontalSeekFeedback = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LaunchedEffect(uiState.isPlaying) {
|
LaunchedEffect(uiState.isPlaying) {
|
||||||
if (uiState.isPlaying) {
|
if (uiState.isPlaying) {
|
||||||
@@ -111,22 +102,17 @@ fun PlayerScreen(
|
|||||||
onVerticalDragLeft = { delta ->
|
onVerticalDragLeft = { delta ->
|
||||||
val diff = (-delta / 800f)
|
val diff = (-delta / 800f)
|
||||||
brightness = (brightness + diff).coerceIn(0f, 1f)
|
brightness = (brightness + diff).coerceIn(0f, 1f)
|
||||||
brightnessOverlayVisible = true
|
|
||||||
applyBrightness(activity, brightness)
|
applyBrightness(activity, brightness)
|
||||||
},
|
},
|
||||||
onVerticalDragRight = { delta ->
|
onVerticalDragRight = { delta ->
|
||||||
val diff = (-delta / 800f)
|
val diff = (-delta / 800f)
|
||||||
volume = (volume + diff).coerceIn(0f, 1f)
|
volume = (volume + diff).coerceIn(0f, 1f)
|
||||||
volumeOverlayVisible = true
|
|
||||||
audioManager.setStreamVolume(
|
audioManager.setStreamVolume(
|
||||||
AudioManager.STREAM_MUSIC,
|
AudioManager.STREAM_MUSIC,
|
||||||
(volume * maxVolume).roundToInt(),
|
(volume * maxVolume).roundToInt(),
|
||||||
0
|
0
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
setFeedBackPreview = {
|
|
||||||
showFeedbackPreview = it
|
|
||||||
},
|
|
||||||
onHorizontalDragPreview = {
|
onHorizontalDragPreview = {
|
||||||
horizontalSeekFeedback = it
|
horizontalSeekFeedback = it
|
||||||
},
|
},
|
||||||
@@ -136,30 +122,40 @@ fun PlayerScreen(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
horizontalSeekFeedback?.let { delta ->
|
EmptyValueTimedVisibility(
|
||||||
|
value = horizontalSeekFeedback,
|
||||||
|
hideAfterMillis = 1_000
|
||||||
|
) {
|
||||||
SeekAmountIndicator(
|
SeekAmountIndicator(
|
||||||
deltaMs = delta,
|
deltaMs = it,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.align(Alignment.Center)
|
.align(Alignment.Center)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
AnimatedVisibility(
|
ValueChangeTimedVisibility(
|
||||||
visible = volumeOverlayVisible || brightnessOverlayVisible,
|
value = brightness,
|
||||||
enter = fadeIn(),
|
hideAfterMillis = 800
|
||||||
exit = fadeOut()
|
) { currentBrightness ->
|
||||||
) {
|
|
||||||
PlayerSideSliders(
|
PlayerSideSliders(
|
||||||
modifier = Modifier
|
modifier = Modifier.fillMaxSize(),
|
||||||
.fillMaxSize(),
|
brightness = currentBrightness,
|
||||||
brightness = brightness,
|
|
||||||
volume = volume,
|
volume = volume,
|
||||||
showBrightness = brightnessOverlayVisible,
|
showBrightness = true,
|
||||||
showVolume = volumeOverlayVisible,
|
showVolume = false,
|
||||||
onHide = {
|
)
|
||||||
brightnessOverlayVisible = false
|
}
|
||||||
volumeOverlayVisible = false
|
|
||||||
}
|
ValueChangeTimedVisibility(
|
||||||
|
value = volume,
|
||||||
|
hideAfterMillis = 800
|
||||||
|
) { currentVolume ->
|
||||||
|
PlayerSideSliders(
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
brightness = brightness,
|
||||||
|
volume = currentVolume,
|
||||||
|
showBrightness = false,
|
||||||
|
showVolume = true,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ fun PlayerGesturesLayer(
|
|||||||
onVerticalDragRight: (delta: Float) -> Unit,
|
onVerticalDragRight: (delta: Float) -> Unit,
|
||||||
onHorizontalDragPreview: (deltaMs: Long?) -> Unit = {},
|
onHorizontalDragPreview: (deltaMs: Long?) -> Unit = {},
|
||||||
onHorizontalDrag: (deltaMs: Long) -> Unit,
|
onHorizontalDrag: (deltaMs: Long) -> Unit,
|
||||||
setFeedBackPreview: (show: Boolean) -> Unit
|
|
||||||
) {
|
) {
|
||||||
val density = LocalDensity.current
|
val density = LocalDensity.current
|
||||||
val horizontalThresholdPx = with(density) { HorizontalSeekGestureHelper.START_THRESHOLD.toPx() }
|
val horizontalThresholdPx = with(density) { HorizontalSeekGestureHelper.START_THRESHOLD.toPx() }
|
||||||
@@ -66,14 +65,12 @@ fun PlayerGesturesLayer(
|
|||||||
accumulatedHorizontalDrag = 0f
|
accumulatedHorizontalDrag = 0f
|
||||||
isHorizontalDragActive = false
|
isHorizontalDragActive = false
|
||||||
lastPreviewDelta = null
|
lastPreviewDelta = null
|
||||||
setFeedBackPreview(false)
|
|
||||||
onHorizontalDragPreview(null)
|
onHorizontalDragPreview(null)
|
||||||
},
|
},
|
||||||
onHorizontalDrag = { change, dragAmount ->
|
onHorizontalDrag = { change, dragAmount ->
|
||||||
accumulatedHorizontalDrag += dragAmount
|
accumulatedHorizontalDrag += dragAmount
|
||||||
if (!isHorizontalDragActive && kotlin.math.abs(accumulatedHorizontalDrag) >= horizontalThresholdPx) {
|
if (!isHorizontalDragActive && kotlin.math.abs(accumulatedHorizontalDrag) >= horizontalThresholdPx) {
|
||||||
isHorizontalDragActive = true
|
isHorizontalDragActive = true
|
||||||
setFeedBackPreview(true)
|
|
||||||
}
|
}
|
||||||
if (isHorizontalDragActive) {
|
if (isHorizontalDragActive) {
|
||||||
change.consume()
|
change.consume()
|
||||||
@@ -95,14 +92,12 @@ fun PlayerGesturesLayer(
|
|||||||
accumulatedHorizontalDrag = 0f
|
accumulatedHorizontalDrag = 0f
|
||||||
isHorizontalDragActive = false
|
isHorizontalDragActive = false
|
||||||
lastPreviewDelta = null
|
lastPreviewDelta = null
|
||||||
setFeedBackPreview(false)
|
|
||||||
onHorizontalDragPreview(null)
|
onHorizontalDragPreview(null)
|
||||||
},
|
},
|
||||||
onDragCancel = {
|
onDragCancel = {
|
||||||
accumulatedHorizontalDrag = 0f
|
accumulatedHorizontalDrag = 0f
|
||||||
isHorizontalDragActive = false
|
isHorizontalDragActive = false
|
||||||
lastPreviewDelta = null
|
lastPreviewDelta = null
|
||||||
setFeedBackPreview(false)
|
|
||||||
onHorizontalDragPreview(null)
|
onHorizontalDragPreview(null)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -15,12 +15,10 @@ import androidx.compose.material3.Icon
|
|||||||
import androidx.compose.material3.LinearProgressIndicator
|
import androidx.compose.material3.LinearProgressIndicator
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import kotlinx.coroutines.delay
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun PlayerSideSliders(
|
fun PlayerSideSliders(
|
||||||
@@ -29,17 +27,9 @@ fun PlayerSideSliders(
|
|||||||
volume: Float,
|
volume: Float,
|
||||||
showBrightness: Boolean,
|
showBrightness: Boolean,
|
||||||
showVolume: Boolean,
|
showVolume: Boolean,
|
||||||
onHide: () -> Unit
|
|
||||||
) {
|
) {
|
||||||
val scheme = MaterialTheme.colorScheme
|
val scheme = MaterialTheme.colorScheme
|
||||||
|
|
||||||
LaunchedEffect(showBrightness, showVolume) {
|
|
||||||
if (showBrightness || showVolume) {
|
|
||||||
delay(800)
|
|
||||||
onHide()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Box(modifier = modifier.fillMaxWidth()) {
|
Box(modifier = modifier.fillMaxWidth()) {
|
||||||
if (showBrightness) {
|
if (showBrightness) {
|
||||||
SideOverlay(
|
SideOverlay(
|
||||||
|
|||||||
Reference in New Issue
Block a user