Improving the ui for reaction row settings

This commit is contained in:
Vitor Pamplona
2026-03-04 17:37:52 -05:00
parent f4ec5735d3
commit cb6391085a
@@ -21,8 +21,10 @@
package com.vitorpamplona.amethyst.ui.screen.loggedIn.settings
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.gestures.detectDragGesturesAfterLongPress
import androidx.compose.foundation.ScrollState
import androidx.compose.foundation.gestures.detectDragGestures
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
@@ -31,10 +33,9 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.DragHandle
import androidx.compose.material.icons.filled.DragIndicator
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
@@ -56,17 +57,32 @@ import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.zIndex
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.model.ReactionRowAction
import com.vitorpamplona.amethyst.model.ReactionRowItem
import com.vitorpamplona.amethyst.ui.navigation.navs.EmptyNav
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.ui.navigation.topbars.TopBarWithBackButton
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel
import com.vitorpamplona.amethyst.ui.stringRes
import com.vitorpamplona.amethyst.ui.theme.Size20dp
import com.vitorpamplona.amethyst.ui.theme.ThemeComparisonRow
@Composable
@Preview(device = "spec:width=2100px,height=2340px,dpi=440")
fun ReactionsSettingsScreenPreview() {
ThemeComparisonRow {
ReactionsSettingsScreen(
mockAccountViewModel(),
EmptyNav(),
)
}
}
@Composable
fun ReactionsSettingsScreen(
@@ -97,13 +113,14 @@ fun ReactionsSettingsContent(accountViewModel: AccountViewModel) {
var draggedItemIndex by remember { mutableIntStateOf(-1) }
var dragOffset by remember { mutableFloatStateOf(0f) }
val itemHeights = remember { mutableStateMapOf<Int, Float>() }
val isDragging = draggedItemIndex >= 0
val scrollState = remember { ScrollState(0) }
Column(
modifier =
Modifier
.fillMaxSize()
.padding(horizontal = Size20dp)
.verticalScroll(rememberScrollState()),
.verticalScroll(scrollState, enabled = !isDragging),
) {
Spacer(modifier = Modifier.height(16.dp))
@@ -111,7 +128,7 @@ fun ReactionsSettingsContent(accountViewModel: AccountViewModel) {
text = stringRes(R.string.reactions_settings_description),
style = MaterialTheme.typography.bodyMedium,
color = Color.Gray,
modifier = Modifier.padding(bottom = 16.dp),
modifier = Modifier.padding(bottom = 16.dp, start = Size20dp, end = Size20dp),
)
items.forEachIndexed { index, item ->
@@ -206,7 +223,7 @@ fun ReactionsSettingsContent(accountViewModel: AccountViewModel) {
.zIndex(if (isDragging) 1f else 0f),
)
if (index < items.lastIndex) {
HorizontalDivider()
HorizontalDivider(modifier = Modifier.padding(horizontal = Size20dp))
}
}
@@ -238,16 +255,25 @@ private fun ReactionRowItemCard(
.fillMaxWidth()
.onGloballyPositioned { coordinates ->
onMeasured(coordinates.size.height.toFloat())
}
.graphicsLayer {
}.graphicsLayer {
translationY = dragOffsetY
shadowElevation = elevation
if (isDragging) {
scaleX = 1.02f
scaleY = 1.02f
}
}
.padding(vertical = 8.dp),
}.padding(vertical = 8.dp, horizontal = Size20dp)
.pointerInput(Unit) {
detectDragGestures(
onDragStart = { onDragStart() },
onDrag = { change, dragAmount ->
change.consume()
onDrag(dragAmount.y)
},
onDragEnd = { onDragEnd() },
onDragCancel = { onDragCancel() },
)
},
) {
Row(
modifier = Modifier.fillMaxWidth(),
@@ -270,25 +296,17 @@ private fun ReactionRowItemCard(
)
}
Icon(
Icons.Default.DragHandle,
contentDescription = stringRes(R.string.reactions_settings_reorder),
modifier =
Modifier
.size(32.dp)
.pointerInput(Unit) {
detectDragGesturesAfterLongPress(
onDragStart = { onDragStart() },
onDrag = { change, dragAmount ->
change.consume()
onDrag(dragAmount.y)
},
onDragEnd = { onDragEnd() },
onDragCancel = { onDragCancel() },
)
},
tint = MaterialTheme.colorScheme.onSurfaceVariant,
)
Box(
modifier = Modifier.size(32.dp),
contentAlignment = Alignment.CenterEnd,
) {
Icon(
Icons.Default.DragIndicator,
contentDescription = stringRes(R.string.reactions_settings_reorder),
modifier = Modifier.size(28.dp),
tint = MaterialTheme.colorScheme.onSurfaceVariant,
)
}
}
Spacer(modifier = Modifier.height(8.dp))