mirror of
https://github.com/bbara04/Purefin.git
synced 2026-07-24 03:36:51 +00:00
feat(player): enhance UI responsiveness with animated color states for buttons and track selection
This commit is contained in:
@@ -54,6 +54,18 @@ internal fun TvIconButton(
|
|||||||
targetValue = if (isFocused) scheme.primary else Color.Transparent,
|
targetValue = if (isFocused) scheme.primary else Color.Transparent,
|
||||||
label = "border"
|
label = "border"
|
||||||
)
|
)
|
||||||
|
val backgroundColor by animateColorAsState(
|
||||||
|
targetValue = if (isFocused) {
|
||||||
|
scheme.primaryContainer
|
||||||
|
} else {
|
||||||
|
scheme.surfaceContainerHigh.copy(alpha = 0.72f)
|
||||||
|
},
|
||||||
|
label = "background"
|
||||||
|
)
|
||||||
|
val contentColor by animateColorAsState(
|
||||||
|
targetValue = if (isFocused) scheme.onPrimaryContainer else scheme.onSurface,
|
||||||
|
label = "content"
|
||||||
|
)
|
||||||
val shape = RoundedCornerShape(50)
|
val shape = RoundedCornerShape(50)
|
||||||
val iconSize = (size - 24).coerceAtLeast(0).dp
|
val iconSize = (size - 24).coerceAtLeast(0).dp
|
||||||
|
|
||||||
@@ -69,10 +81,7 @@ internal fun TvIconButton(
|
|||||||
shape = shape
|
shape = shape
|
||||||
)
|
)
|
||||||
.clip(shape)
|
.clip(shape)
|
||||||
.background(
|
.background(backgroundColor)
|
||||||
if (isFocused) scheme.primary.copy(alpha = 0.5f)
|
|
||||||
else scheme.background.copy(alpha = 0.65f)
|
|
||||||
)
|
|
||||||
.focusProperties { canFocus = enabled }
|
.focusProperties { canFocus = enabled }
|
||||||
.semantics {
|
.semantics {
|
||||||
if (!enabled) {
|
if (!enabled) {
|
||||||
@@ -86,7 +95,7 @@ internal fun TvIconButton(
|
|||||||
Icon(
|
Icon(
|
||||||
imageVector = icon,
|
imageVector = icon,
|
||||||
contentDescription = contentDescription,
|
contentDescription = contentDescription,
|
||||||
tint = scheme.onBackground,
|
tint = contentColor,
|
||||||
modifier = buttonModifier
|
modifier = buttonModifier
|
||||||
.size(size.dp)
|
.size(size.dp)
|
||||||
.padding(12.dp)
|
.padding(12.dp)
|
||||||
@@ -104,12 +113,12 @@ internal fun TvIconButton(
|
|||||||
Icon(
|
Icon(
|
||||||
imageVector = icon,
|
imageVector = icon,
|
||||||
contentDescription = contentDescription,
|
contentDescription = contentDescription,
|
||||||
tint = scheme.onBackground,
|
tint = contentColor,
|
||||||
modifier = Modifier.size(iconSize)
|
modifier = Modifier.size(iconSize)
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
text = label,
|
text = label,
|
||||||
color = scheme.onBackground,
|
color = contentColor,
|
||||||
style = MaterialTheme.typography.labelLarge,
|
style = MaterialTheme.typography.labelLarge,
|
||||||
fontWeight = FontWeight.SemiBold
|
fontWeight = FontWeight.SemiBold
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package hu.bbara.purefin.ui.screen.player.components
|
package hu.bbara.purefin.ui.screen.player.components
|
||||||
|
|
||||||
|
import androidx.compose.animation.animateColorAsState
|
||||||
|
import androidx.compose.animation.core.animateFloatAsState
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.border
|
import androidx.compose.foundation.border
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
@@ -7,14 +9,19 @@ 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.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.aspectRatio
|
import androidx.compose.foundation.layout.aspectRatio
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.lazy.LazyRow
|
import androidx.compose.foundation.lazy.LazyRow
|
||||||
import androidx.compose.foundation.lazy.itemsIndexed
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.outlined.PlayArrow
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Surface
|
import androidx.compose.material3.Surface
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
@@ -25,11 +32,14 @@ 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.runtime.withFrameNanos
|
import androidx.compose.runtime.withFrameNanos
|
||||||
|
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.focus.FocusRequester
|
import androidx.compose.ui.focus.FocusRequester
|
||||||
import androidx.compose.ui.focus.focusRequester
|
import androidx.compose.ui.focus.focusRequester
|
||||||
import androidx.compose.ui.focus.onFocusChanged
|
import androidx.compose.ui.focus.onFocusChanged
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.graphics.graphicsLayer
|
||||||
import androidx.compose.ui.graphics.painter.ColorPainter
|
import androidx.compose.ui.graphics.painter.ColorPainter
|
||||||
import androidx.compose.ui.input.key.Key
|
import androidx.compose.ui.input.key.Key
|
||||||
import androidx.compose.ui.input.key.KeyEventType
|
import androidx.compose.ui.input.key.KeyEventType
|
||||||
@@ -82,75 +92,56 @@ internal fun TvPlayerQueuePanel(
|
|||||||
shape = RoundedCornerShape(24.dp),
|
shape = RoundedCornerShape(24.dp),
|
||||||
color = scheme.surface.copy(alpha = 0.94f)
|
color = scheme.surface.copy(alpha = 0.94f)
|
||||||
) {
|
) {
|
||||||
Column(
|
if (uiState.queue.isEmpty()) {
|
||||||
modifier = Modifier.padding(horizontal = 22.dp, vertical = 20.dp),
|
Text(
|
||||||
verticalArrangement = Arrangement.spacedBy(16.dp)
|
text = "Add something to the queue to browse it here.",
|
||||||
) {
|
color = scheme.onSurfaceVariant,
|
||||||
Column(verticalArrangement = Arrangement.spacedBy(4.dp)) {
|
style = MaterialTheme.typography.bodyMedium
|
||||||
Text(
|
)
|
||||||
text = "Playlist",
|
} else {
|
||||||
color = scheme.onSurface,
|
LazyRow(
|
||||||
style = MaterialTheme.typography.titleLarge,
|
modifier = Modifier
|
||||||
fontWeight = FontWeight.Bold
|
.fillMaxWidth()
|
||||||
)
|
.testTag(TvPlayerPlaylistRowTag),
|
||||||
Text(
|
state = listState,
|
||||||
text = queueCountLabel,
|
horizontalArrangement = Arrangement.spacedBy(14.dp),
|
||||||
color = scheme.onSurfaceVariant,
|
contentPadding = PaddingValues(16.dp)
|
||||||
style = MaterialTheme.typography.bodyMedium
|
) {
|
||||||
)
|
itemsIndexed(uiState.queue, key = { _, item -> item.id }) { index, item ->
|
||||||
}
|
val isEntryItem = index == entryIndex
|
||||||
|
TvQueueRowCard(
|
||||||
if (uiState.queue.isEmpty()) {
|
item = item,
|
||||||
Text(
|
isCurrent = item.isCurrent,
|
||||||
text = "Add something to the queue to browse it here.",
|
isFirst = index == 0,
|
||||||
color = scheme.onSurfaceVariant,
|
isLast = index == uiState.queue.lastIndex,
|
||||||
style = MaterialTheme.typography.bodyMedium
|
onClick = { onSelect(item.id) },
|
||||||
)
|
onReturnToControls = onReturnToControls,
|
||||||
} else {
|
modifier = Modifier
|
||||||
LazyRow(
|
.width(228.dp)
|
||||||
modifier = Modifier
|
.then(
|
||||||
.fillMaxWidth()
|
if (isEntryItem) {
|
||||||
.testTag(TvPlayerPlaylistRowTag),
|
Modifier
|
||||||
state = listState,
|
.focusRequester(firstItemFocusRequester)
|
||||||
horizontalArrangement = Arrangement.spacedBy(14.dp),
|
.testTag(TvPlayerPlaylistCurrentItemTag)
|
||||||
contentPadding = PaddingValues(end = 4.dp)
|
} else {
|
||||||
) {
|
Modifier
|
||||||
itemsIndexed(uiState.queue, key = { _, item -> item.id }) { index, item ->
|
}
|
||||||
val isEntryItem = index == entryIndex
|
)
|
||||||
TvQueueRowCard(
|
.then(
|
||||||
item = item,
|
if (index == 0 && !isEntryItem) {
|
||||||
isCurrent = item.isCurrent,
|
Modifier.testTag(TvPlayerPlaylistFirstItemTag)
|
||||||
isFirst = index == 0,
|
} else {
|
||||||
isLast = index == uiState.queue.lastIndex,
|
Modifier
|
||||||
onClick = { onSelect(item.id) },
|
}
|
||||||
onReturnToControls = onReturnToControls,
|
)
|
||||||
modifier = Modifier
|
.then(
|
||||||
.width(228.dp)
|
if (index == uiState.queue.lastIndex && !isEntryItem) {
|
||||||
.then(
|
Modifier.testTag(TvPlayerPlaylistLastItemTag)
|
||||||
if (isEntryItem) {
|
} else {
|
||||||
Modifier
|
Modifier
|
||||||
.focusRequester(firstItemFocusRequester)
|
}
|
||||||
.testTag(TvPlayerPlaylistCurrentItemTag)
|
)
|
||||||
} else {
|
)
|
||||||
Modifier
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.then(
|
|
||||||
if (index == 0 && !isEntryItem) {
|
|
||||||
Modifier.testTag(TvPlayerPlaylistFirstItemTag)
|
|
||||||
} else {
|
|
||||||
Modifier
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.then(
|
|
||||||
if (index == uiState.queue.lastIndex && !isEntryItem) {
|
|
||||||
Modifier.testTag(TvPlayerPlaylistLastItemTag)
|
|
||||||
} else {
|
|
||||||
Modifier
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -169,25 +160,49 @@ private fun TvQueueRowCard(
|
|||||||
) {
|
) {
|
||||||
val scheme = MaterialTheme.colorScheme
|
val scheme = MaterialTheme.colorScheme
|
||||||
var isFocused by remember { mutableStateOf(false) }
|
var isFocused by remember { mutableStateOf(false) }
|
||||||
val borderColor = when {
|
val scale by animateFloatAsState(
|
||||||
isFocused -> scheme.primary
|
targetValue = if (isFocused) 1.06f else 1f,
|
||||||
isCurrent -> scheme.primary.copy(alpha = 0.55f)
|
label = "queueCardScale"
|
||||||
else -> scheme.outlineVariant.copy(alpha = 0.35f)
|
)
|
||||||
}
|
val borderColor by animateColorAsState(
|
||||||
val backgroundColor = when {
|
targetValue = when {
|
||||||
isFocused -> scheme.primary.copy(alpha = 0.18f)
|
isFocused -> scheme.primary
|
||||||
isCurrent -> scheme.surfaceVariant.copy(alpha = 0.78f)
|
isCurrent -> scheme.tertiary
|
||||||
else -> scheme.surfaceVariant.copy(alpha = 0.62f)
|
else -> scheme.outlineVariant.copy(alpha = 0.5f)
|
||||||
|
},
|
||||||
|
label = "queueCardBorder"
|
||||||
|
)
|
||||||
|
val backgroundColor by animateColorAsState(
|
||||||
|
targetValue = when {
|
||||||
|
isFocused -> scheme.primaryContainer.copy(alpha = 0.96f)
|
||||||
|
isCurrent -> scheme.tertiaryContainer.copy(alpha = 0.86f)
|
||||||
|
else -> scheme.surfaceContainerHigh.copy(alpha = 0.72f)
|
||||||
|
},
|
||||||
|
label = "queueCardBackground"
|
||||||
|
)
|
||||||
|
val contentColor = when {
|
||||||
|
isFocused -> scheme.onPrimaryContainer
|
||||||
|
isCurrent -> scheme.onTertiaryContainer
|
||||||
|
else -> scheme.onSurface
|
||||||
}
|
}
|
||||||
|
val shape = RoundedCornerShape(18.dp)
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
|
.graphicsLayer {
|
||||||
|
scaleX = scale
|
||||||
|
scaleY = scale
|
||||||
|
}
|
||||||
.border(
|
.border(
|
||||||
width = if (isFocused) 2.dp else 1.dp,
|
width = when {
|
||||||
|
isFocused -> 3.dp
|
||||||
|
isCurrent -> 2.dp
|
||||||
|
else -> 1.dp
|
||||||
|
},
|
||||||
color = borderColor,
|
color = borderColor,
|
||||||
shape = RoundedCornerShape(18.dp)
|
shape = shape
|
||||||
)
|
)
|
||||||
.clip(RoundedCornerShape(18.dp))
|
.clip(shape)
|
||||||
.background(backgroundColor)
|
.background(backgroundColor)
|
||||||
.onFocusChanged { isFocused = it.isFocused }
|
.onFocusChanged { isFocused = it.isFocused }
|
||||||
.onPreviewKeyEvent { event ->
|
.onPreviewKeyEvent { event ->
|
||||||
@@ -207,37 +222,34 @@ private fun TvQueueRowCard(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.clickable { onClick() }
|
.clickable { onClick() }
|
||||||
.padding(12.dp),
|
.padding(4.dp),
|
||||||
verticalArrangement = Arrangement.spacedBy(10.dp)
|
verticalArrangement = Arrangement.spacedBy(10.dp)
|
||||||
) {
|
) {
|
||||||
TvQueueArtwork(
|
TvQueueArtwork(
|
||||||
artworkUrl = item.artworkUrl,
|
artworkUrl = item.artworkUrl,
|
||||||
|
isCurrent = isCurrent,
|
||||||
|
badgeColor = if (isFocused) scheme.primary else scheme.tertiary,
|
||||||
|
badgeContentColor = if (isFocused) scheme.onPrimary else scheme.onTertiary,
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier.fillMaxWidth()
|
||||||
)
|
)
|
||||||
Column(verticalArrangement = Arrangement.spacedBy(4.dp)) {
|
Text(
|
||||||
if (isCurrent) {
|
text = item.title,
|
||||||
Text(
|
color = contentColor,
|
||||||
text = "Current",
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
color = scheme.primary,
|
fontWeight = if (isCurrent || isFocused) FontWeight.Bold else FontWeight.Medium,
|
||||||
style = MaterialTheme.typography.labelMedium,
|
maxLines = 1,
|
||||||
fontWeight = FontWeight.SemiBold
|
overflow = TextOverflow.Ellipsis,
|
||||||
)
|
modifier = Modifier.padding(horizontal = 8.dp)
|
||||||
}
|
)
|
||||||
Text(
|
|
||||||
text = item.title,
|
|
||||||
color = scheme.onSurface,
|
|
||||||
style = MaterialTheme.typography.bodyLarge,
|
|
||||||
fontWeight = FontWeight.SemiBold,
|
|
||||||
maxLines = 2,
|
|
||||||
overflow = TextOverflow.Ellipsis
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun TvQueueArtwork(
|
private fun TvQueueArtwork(
|
||||||
artworkUrl: String?,
|
artworkUrl: String?,
|
||||||
|
isCurrent: Boolean,
|
||||||
|
badgeColor: Color,
|
||||||
|
badgeContentColor: Color,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
val scheme = MaterialTheme.colorScheme
|
val scheme = MaterialTheme.colorScheme
|
||||||
@@ -268,5 +280,30 @@ private fun TvQueueArtwork(
|
|||||||
.background(scheme.surfaceContainerHigh)
|
.background(scheme.surfaceContainerHigh)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
if (isCurrent) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.align(Alignment.TopStart)
|
||||||
|
.padding(8.dp)
|
||||||
|
.clip(RoundedCornerShape(50))
|
||||||
|
.background(badgeColor)
|
||||||
|
.padding(horizontal = 9.dp, vertical = 5.dp),
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(4.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Outlined.PlayArrow,
|
||||||
|
contentDescription = null,
|
||||||
|
tint = badgeContentColor,
|
||||||
|
modifier = Modifier.size(14.dp)
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = "Now playing",
|
||||||
|
color = badgeContentColor,
|
||||||
|
style = MaterialTheme.typography.labelSmall,
|
||||||
|
fontWeight = FontWeight.Bold
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,30 @@
|
|||||||
package hu.bbara.purefin.ui.screen.player.components
|
package hu.bbara.purefin.ui.screen.player.components
|
||||||
|
|
||||||
|
import androidx.compose.animation.animateColorAsState
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.border
|
import androidx.compose.foundation.border
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
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.fillMaxHeight
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
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.size
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.itemsIndexed
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.outlined.Check
|
||||||
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.material3.Icon
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Surface
|
import androidx.compose.material3.Surface
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
@@ -211,23 +216,42 @@ private fun TvTrackOptionRow(
|
|||||||
) {
|
) {
|
||||||
val scheme = MaterialTheme.colorScheme
|
val scheme = MaterialTheme.colorScheme
|
||||||
var isFocused by remember { mutableStateOf(false) }
|
var isFocused by remember { mutableStateOf(false) }
|
||||||
|
val backgroundColor by animateColorAsState(
|
||||||
|
targetValue = when {
|
||||||
|
isFocused -> scheme.primaryContainer
|
||||||
|
selected -> scheme.secondaryContainer.copy(alpha = 0.9f)
|
||||||
|
else -> scheme.surfaceContainerHigh.copy(alpha = 0.72f)
|
||||||
|
},
|
||||||
|
label = "trackOptionBackground"
|
||||||
|
)
|
||||||
|
val contentColor by animateColorAsState(
|
||||||
|
targetValue = when {
|
||||||
|
isFocused -> scheme.onPrimaryContainer
|
||||||
|
selected -> scheme.onSecondaryContainer
|
||||||
|
else -> scheme.onSurface
|
||||||
|
},
|
||||||
|
label = "trackOptionContent"
|
||||||
|
)
|
||||||
|
val borderColor by animateColorAsState(
|
||||||
|
targetValue = when {
|
||||||
|
isFocused -> scheme.primary
|
||||||
|
selected -> scheme.secondary
|
||||||
|
else -> scheme.outlineVariant.copy(alpha = 0.45f)
|
||||||
|
},
|
||||||
|
label = "trackOptionBorder"
|
||||||
|
)
|
||||||
|
val shape = RoundedCornerShape(12.dp)
|
||||||
|
|
||||||
Box(
|
Box(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.then(
|
.border(
|
||||||
if (isFocused) {
|
width = if (isFocused) 3.dp else if (selected) 2.dp else 1.dp,
|
||||||
Modifier.border(2.dp, scheme.primary, RoundedCornerShape(12.dp))
|
color = borderColor,
|
||||||
} else {
|
shape = shape
|
||||||
Modifier
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.clip(RoundedCornerShape(12.dp))
|
|
||||||
.background(
|
|
||||||
if (isFocused) scheme.primary.copy(alpha = 0.3f)
|
|
||||||
else if (selected) scheme.primary.copy(alpha = 0.15f)
|
|
||||||
else scheme.surfaceVariant.copy(alpha = 0.6f)
|
|
||||||
)
|
)
|
||||||
|
.clip(shape)
|
||||||
|
.background(backgroundColor)
|
||||||
.onFocusChanged { isFocused = it.isFocused }
|
.onFocusChanged { isFocused = it.isFocused }
|
||||||
.onPreviewKeyEvent { event ->
|
.onPreviewKeyEvent { event ->
|
||||||
if (event.type != KeyEventType.KeyDown) {
|
if (event.type != KeyEventType.KeyDown) {
|
||||||
@@ -244,11 +268,25 @@ private fun TvTrackOptionRow(
|
|||||||
.clickable { onClick() }
|
.clickable { onClick() }
|
||||||
.padding(horizontal = 20.dp, vertical = 14.dp)
|
.padding(horizontal = 20.dp, vertical = 14.dp)
|
||||||
) {
|
) {
|
||||||
Text(
|
Row(
|
||||||
text = label,
|
modifier = Modifier.fillMaxWidth(),
|
||||||
color = scheme.onSurface,
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
style = MaterialTheme.typography.bodyLarge,
|
verticalAlignment = Alignment.CenterVertically
|
||||||
fontWeight = if (selected) FontWeight.SemiBold else FontWeight.Normal
|
) {
|
||||||
)
|
Text(
|
||||||
|
text = label,
|
||||||
|
color = contentColor,
|
||||||
|
style = MaterialTheme.typography.bodyLarge,
|
||||||
|
fontWeight = if (selected || isFocused) FontWeight.SemiBold else FontWeight.Normal
|
||||||
|
)
|
||||||
|
if (selected) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Outlined.Check,
|
||||||
|
contentDescription = null,
|
||||||
|
tint = contentColor,
|
||||||
|
modifier = Modifier.size(22.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user