mirror of
https://github.com/bbara04/Purefin.git
synced 2026-04-01 01:30:08 +02:00
refactor(player): replace side sliders with centered adjustment indicators
- Replace the horizontal `PlayerSideSliders` with a new vertical `PlayerAdjustmentIndicator` for brightness and volume, displaying it in the center of the screen. - Create `PlayerAdjustmentIndicator.kt`, a new composable that shows an icon, a vertical progress bar, and a percentage value within a semi-transparent black background. - Update `PlayerScreen` to use the new centered indicator instead of the old side-aligned sliders when brightness or volume is adjusted via gestures. - Pass a `modifier` to `ValueChangeTimedVisibility` to correctly position the new indicators. - Change the background color of the "Seek to" toast message from a theme surface color to semi-transparent black for better consistency.
This commit is contained in:
@@ -9,6 +9,7 @@ import androidx.compose.runtime.getValue
|
|||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -25,7 +26,8 @@ import kotlinx.coroutines.delay
|
|||||||
fun <T> EmptyValueTimedVisibility(
|
fun <T> EmptyValueTimedVisibility(
|
||||||
value: T?,
|
value: T?,
|
||||||
hideAfterMillis: Long = 1_000,
|
hideAfterMillis: Long = 1_000,
|
||||||
content: @Composable (T) -> Unit,
|
modifier: Modifier = Modifier,
|
||||||
|
content: @Composable (T) -> Unit
|
||||||
) {
|
) {
|
||||||
val shownValue = remember { mutableStateOf<T?>(null) }
|
val shownValue = remember { mutableStateOf<T?>(null) }
|
||||||
|
|
||||||
@@ -55,7 +57,8 @@ fun <T> EmptyValueTimedVisibility(
|
|||||||
fun <T> ValueChangeTimedVisibility(
|
fun <T> ValueChangeTimedVisibility(
|
||||||
value: T,
|
value: T,
|
||||||
hideAfterMillis: Long = 1_000,
|
hideAfterMillis: Long = 1_000,
|
||||||
content: @Composable (T) -> Unit,
|
modifier: Modifier = Modifier,
|
||||||
|
content: @Composable (T) -> Unit
|
||||||
) {
|
) {
|
||||||
var displayedValue by remember { mutableStateOf(value) }
|
var displayedValue by remember { mutableStateOf(value) }
|
||||||
var isVisible by remember { mutableStateOf(false) }
|
var isVisible by remember { mutableStateOf(false) }
|
||||||
@@ -75,6 +78,7 @@ fun <T> ValueChangeTimedVisibility(
|
|||||||
|
|
||||||
AnimatedVisibility(
|
AnimatedVisibility(
|
||||||
visible = isVisible,
|
visible = isVisible,
|
||||||
|
modifier = modifier,
|
||||||
enter = EnterTransition.None,
|
enter = EnterTransition.None,
|
||||||
exit = ExitTransition.None
|
exit = ExitTransition.None
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ import androidx.compose.foundation.layout.fillMaxHeight
|
|||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.outlined.BrightnessMedium
|
||||||
|
import androidx.compose.material.icons.outlined.VolumeUp
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
@@ -27,6 +30,7 @@ import androidx.compose.runtime.setValue
|
|||||||
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.graphics.Color
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.viewinterop.AndroidView
|
import androidx.compose.ui.viewinterop.AndroidView
|
||||||
@@ -35,12 +39,12 @@ 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.EmptyValueTimedVisibility
|
||||||
import hu.bbara.purefin.common.ui.components.ValueChangeTimedVisibility
|
import hu.bbara.purefin.common.ui.components.ValueChangeTimedVisibility
|
||||||
|
import hu.bbara.purefin.player.ui.components.PlayerAdjustmentIndicator
|
||||||
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
|
||||||
import hu.bbara.purefin.player.ui.components.PlayerQueuePanel
|
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.viewmodel.PlayerViewModel
|
import hu.bbara.purefin.player.viewmodel.PlayerViewModel
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
@@ -135,27 +139,33 @@ fun PlayerScreen(
|
|||||||
|
|
||||||
ValueChangeTimedVisibility(
|
ValueChangeTimedVisibility(
|
||||||
value = brightness,
|
value = brightness,
|
||||||
hideAfterMillis = 800
|
hideAfterMillis = 800,
|
||||||
|
modifier = Modifier
|
||||||
|
.align(Alignment.CenterStart)
|
||||||
|
.padding(start = 20.dp)
|
||||||
) { currentBrightness ->
|
) { currentBrightness ->
|
||||||
PlayerSideSliders(
|
PlayerAdjustmentIndicator(
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier
|
||||||
brightness = currentBrightness,
|
.align(Alignment.Center),
|
||||||
volume = volume,
|
icon = Icons.Outlined.BrightnessMedium,
|
||||||
showBrightness = true,
|
contentDescription = "Brightness",
|
||||||
showVolume = false,
|
value = currentBrightness
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
ValueChangeTimedVisibility(
|
ValueChangeTimedVisibility(
|
||||||
value = volume,
|
value = volume,
|
||||||
hideAfterMillis = 800
|
hideAfterMillis = 800,
|
||||||
|
modifier = Modifier
|
||||||
|
.align(Alignment.CenterEnd)
|
||||||
|
.padding(end = 20.dp)
|
||||||
) { currentVolume ->
|
) { currentVolume ->
|
||||||
PlayerSideSliders(
|
PlayerAdjustmentIndicator(
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier
|
||||||
brightness = brightness,
|
.align(Alignment.Center),
|
||||||
volume = currentVolume,
|
icon = Icons.Outlined.VolumeUp,
|
||||||
showBrightness = false,
|
contentDescription = "Volume",
|
||||||
showVolume = true,
|
value = currentVolume
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,7 +245,7 @@ private fun SeekAmountIndicator(deltaMs: Long, modifier: Modifier = Modifier) {
|
|||||||
Box(
|
Box(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.clip(RoundedCornerShape(16.dp))
|
.clip(RoundedCornerShape(16.dp))
|
||||||
.background(scheme.surface.copy(alpha = 0.9f))
|
.background(Color.Black.copy(alpha = 0.9f))
|
||||||
.padding(horizontal = 20.dp, vertical = 12.dp)
|
.padding(horizontal = 20.dp, vertical = 12.dp)
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
|
|||||||
@@ -0,0 +1,76 @@
|
|||||||
|
package hu.bbara.purefin.player.ui.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
|
import androidx.compose.ui.unit.Dp
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun PlayerAdjustmentIndicator(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
icon: ImageVector,
|
||||||
|
contentDescription: String?,
|
||||||
|
value: Float,
|
||||||
|
sliderHeight: Dp = 140.dp,
|
||||||
|
) {
|
||||||
|
val scheme = MaterialTheme.colorScheme
|
||||||
|
val percent = (value.coerceIn(0f, 1f) * 100).roundToInt()
|
||||||
|
val clamped = value.coerceIn(0f, 1f)
|
||||||
|
|
||||||
|
Box(
|
||||||
|
modifier = modifier
|
||||||
|
.clip(RoundedCornerShape(16.dp))
|
||||||
|
.background(Color.Black.copy(alpha = 0.5f))
|
||||||
|
.padding(horizontal = 20.dp, vertical = 16.dp),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = icon,
|
||||||
|
contentDescription = contentDescription,
|
||||||
|
tint = scheme.onSurface
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.width(10.dp)
|
||||||
|
.height(sliderHeight)
|
||||||
|
.clip(RoundedCornerShape(5.dp))
|
||||||
|
.background(scheme.onSurface.copy(alpha = 0.2f))
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.align(Alignment.BottomCenter)
|
||||||
|
.width(10.dp)
|
||||||
|
.height(sliderHeight * clamped)
|
||||||
|
.clip(RoundedCornerShape(5.dp))
|
||||||
|
.background(scheme.primary)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
Text(
|
||||||
|
text = "$percent%",
|
||||||
|
color = scheme.onSurface,
|
||||||
|
style = MaterialTheme.typography.titleMedium
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
package hu.bbara.purefin.player.ui.components
|
|
||||||
|
|
||||||
import androidx.compose.foundation.background
|
|
||||||
import androidx.compose.foundation.layout.Box
|
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
import androidx.compose.foundation.layout.fillMaxHeight
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.foundation.layout.wrapContentHeight
|
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
||||||
import androidx.compose.material.icons.Icons
|
|
||||||
import androidx.compose.material.icons.outlined.BrightnessMedium
|
|
||||||
import androidx.compose.material.icons.outlined.VolumeUp
|
|
||||||
import androidx.compose.material3.Icon
|
|
||||||
import androidx.compose.material3.LinearProgressIndicator
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.ui.Alignment
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.draw.clip
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun PlayerSideSliders(
|
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
brightness: Float,
|
|
||||||
volume: Float,
|
|
||||||
showBrightness: Boolean,
|
|
||||||
showVolume: Boolean,
|
|
||||||
) {
|
|
||||||
val scheme = MaterialTheme.colorScheme
|
|
||||||
|
|
||||||
Box(modifier = modifier.fillMaxWidth()) {
|
|
||||||
if (showBrightness) {
|
|
||||||
SideOverlay(
|
|
||||||
modifier = Modifier
|
|
||||||
.align(Alignment.CenterStart)
|
|
||||||
.padding(start = 16.dp),
|
|
||||||
icon = { Icon(Icons.Outlined.BrightnessMedium, contentDescription = null, tint = scheme.onBackground) },
|
|
||||||
progress = brightness,
|
|
||||||
scheme = scheme
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if (showVolume) {
|
|
||||||
SideOverlay(
|
|
||||||
modifier = Modifier
|
|
||||||
.align(Alignment.CenterEnd)
|
|
||||||
.padding(end = 16.dp),
|
|
||||||
icon = { Icon(Icons.Outlined.VolumeUp, contentDescription = null, tint = scheme.onBackground) },
|
|
||||||
progress = volume,
|
|
||||||
scheme = scheme
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun SideOverlay(
|
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
icon: @Composable () -> Unit,
|
|
||||||
progress: Float,
|
|
||||||
scheme: androidx.compose.material3.ColorScheme
|
|
||||||
) {
|
|
||||||
Column(
|
|
||||||
modifier = modifier
|
|
||||||
.fillMaxHeight(0.3f)
|
|
||||||
.wrapContentHeight(align = Alignment.CenterVertically)
|
|
||||||
.clip(RoundedCornerShape(18.dp))
|
|
||||||
.background(scheme.background.copy(alpha = 0.8f))
|
|
||||||
.padding(horizontal = 14.dp, vertical = 12.dp),
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
|
||||||
) {
|
|
||||||
icon()
|
|
||||||
LinearProgressIndicator(
|
|
||||||
progress = { progress.coerceIn(0f, 1f) },
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(top = 10.dp)
|
|
||||||
.fillMaxWidth()
|
|
||||||
.clip(RoundedCornerShape(8.dp)),
|
|
||||||
color = scheme.primary,
|
|
||||||
trackColor = scheme.onBackground.copy(alpha = 0.2f)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user