Refactor player track selection overlay

This commit is contained in:
Balogh Barnabás
2026-03-24 20:32:36 +01:00
parent e37006486e
commit ada0e9600a

View File

@@ -3,13 +3,18 @@ package hu.bbara.purefin.player.ui.components
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.safeDrawing
import androidx.compose.foundation.layout.sizeIn
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
@@ -17,7 +22,10 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.ClosedCaption import androidx.compose.material.icons.outlined.ClosedCaption
import androidx.compose.material.icons.outlined.HighQuality import androidx.compose.material.icons.outlined.HighQuality
import androidx.compose.material.icons.outlined.Language import androidx.compose.material.icons.outlined.Language
import androidx.compose.material.icons.outlined.Close
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
@@ -25,6 +33,7 @@ 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.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import hu.bbara.purefin.common.ui.components.PurefinIconButton import hu.bbara.purefin.common.ui.components.PurefinIconButton
import hu.bbara.purefin.core.player.model.TrackOption import hu.bbara.purefin.core.player.model.TrackOption
@@ -37,8 +46,6 @@ fun QualitySelectionButton(
overlayController: PersistentOverlayController, overlayController: PersistentOverlayController,
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
val scheme = MaterialTheme.colorScheme
PurefinIconButton( PurefinIconButton(
icon = Icons.Outlined.HighQuality, icon = Icons.Outlined.HighQuality,
contentDescription = "Quality", contentDescription = "Quality",
@@ -48,6 +55,7 @@ fun QualitySelectionButton(
title = "Quality", title = "Quality",
options = options, options = options,
selectedId = selectedId, selectedId = selectedId,
onClose = { overlayController.hide() },
onSelect = { option -> onSelect = { option ->
onSelect(option) onSelect(option)
overlayController.hide() overlayController.hide()
@@ -76,6 +84,7 @@ fun AudioSelectionButton(
title = "Audio", title = "Audio",
options = options, options = options,
selectedId = selectedId, selectedId = selectedId,
onClose = { overlayController.hide() },
onSelect = { option -> onSelect = { option ->
onSelect(option) onSelect(option)
overlayController.hide() overlayController.hide()
@@ -104,6 +113,7 @@ fun SubtitlesSelectionButton(
title = "Subtitles", title = "Subtitles",
options = options, options = options,
selectedId = selectedId, selectedId = selectedId,
onClose = { overlayController.hide() },
onSelect = { option -> onSelect = { option ->
onSelect(option) onSelect(option)
overlayController.hide() overlayController.hide()
@@ -121,6 +131,7 @@ private fun TrackSelectionPanel(
options: List<TrackOption>, options: List<TrackOption>,
selectedId: String?, selectedId: String?,
onSelect: (TrackOption) -> Unit, onSelect: (TrackOption) -> Unit,
onClose: () -> Unit,
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
val scheme = MaterialTheme.colorScheme val scheme = MaterialTheme.colorScheme
@@ -128,35 +139,65 @@ private fun TrackSelectionPanel(
Box( Box(
modifier = modifier modifier = modifier
.fillMaxWidth() .fillMaxWidth()
.padding(16.dp) .fillMaxHeight()
.windowInsetsPadding(WindowInsets.safeDrawing)
.navigationBarsPadding()
.padding(horizontal = 16.dp, vertical = 12.dp)
.clickable( .clickable(
interactionSource = remember { MutableInteractionSource() }, interactionSource = remember { MutableInteractionSource() },
indication = null, indication = null,
onClick = { /* Prevent clicks from bubbling */ } onClick = { /* Prevent clicks from bubbling */ }
), ),
contentAlignment = Alignment.BottomEnd contentAlignment = Alignment.BottomEnd
) {
Surface(
modifier = Modifier
.sizeIn(
minWidth = 280.dp,
maxWidth = 280.dp,
minHeight = 220.dp,
maxHeight = 360.dp
)
.clip(RoundedCornerShape(topStart = 24.dp, topEnd = 24.dp, bottomStart = 24.dp)),
color = scheme.surface.copy(alpha = 0.97f)
) { ) {
Column( Column(
modifier = Modifier modifier = Modifier
.widthIn(min = 200.dp, max = 320.dp) .padding(horizontal = 12.dp, vertical = 12.dp)
.clip(RoundedCornerShape(12.dp)) ) {
.background(scheme.surface.copy(alpha = 0.98f)) Row(
.padding(vertical = 12.dp, horizontal = 8.dp), modifier = Modifier
verticalArrangement = Arrangement.spacedBy(4.dp) .fillMaxWidth()
.padding(start = 8.dp, end = 4.dp, bottom = 8.dp),
verticalAlignment = Alignment.CenterVertically
) { ) {
Text( Text(
text = title, text = title,
color = scheme.onSurface, color = scheme.onSurface,
style = MaterialTheme.typography.titleMedium, style = MaterialTheme.typography.titleMedium,
fontWeight = FontWeight.Bold, fontWeight = FontWeight.Bold,
modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp) modifier = Modifier.weight(1f)
) )
Box(
modifier = Modifier
.clip(RoundedCornerShape(50))
.clickable(onClick = onClose)
.padding(8.dp),
contentAlignment = Alignment.Center
) {
Icon(
imageVector = Icons.Outlined.Close,
contentDescription = "Close $title",
tint = scheme.onSurface
)
}
}
Column( Column(
modifier = Modifier modifier = Modifier
.heightIn(max = 400.dp) .fillMaxWidth()
.verticalScroll(rememberScrollState()), .heightIn(max = 292.dp)
verticalArrangement = Arrangement.spacedBy(4.dp) .verticalScroll(rememberScrollState())
) { ) {
options.forEach { option -> options.forEach { option ->
val selected = option.id == selectedId val selected = option.id == selectedId
@@ -169,6 +210,7 @@ private fun TrackSelectionPanel(
} }
} }
} }
}
} }
@Composable @Composable
@@ -183,7 +225,8 @@ private fun TrackOptionItem(
Box( Box(
modifier = modifier modifier = modifier
.fillMaxWidth() .fillMaxWidth()
.clip(RoundedCornerShape(10.dp)) .padding(vertical = 3.dp)
.clip(RoundedCornerShape(14.dp))
.background( .background(
if (selected) { if (selected) {
scheme.primary.copy(alpha = 0.15f) scheme.primary.copy(alpha = 0.15f)
@@ -198,7 +241,9 @@ private fun TrackOptionItem(
text = label, text = label,
color = scheme.onSurface, color = scheme.onSurface,
style = MaterialTheme.typography.bodyMedium, style = MaterialTheme.typography.bodyMedium,
fontWeight = if (selected) FontWeight.SemiBold else FontWeight.Normal fontWeight = if (selected) FontWeight.SemiBold else FontWeight.Normal,
maxLines = 2,
overflow = TextOverflow.Ellipsis
) )
} }
} }