mirror of
https://github.com/fromchat-messenger/app.git
synced 2026-09-22 19:15:05 +03:00
Make bubble scale when pressing on empty space
Signed-off-by: denis0001-dev <denis0001.dev@ya.ru>
This commit is contained in:
@@ -44,6 +44,7 @@ import androidx.compose.ui.graphics.Color
|
|||||||
import androidx.compose.ui.graphics.TransformOrigin
|
import androidx.compose.ui.graphics.TransformOrigin
|
||||||
import androidx.compose.ui.graphics.graphicsLayer
|
import androidx.compose.ui.graphics.graphicsLayer
|
||||||
import androidx.compose.ui.input.pointer.pointerInput
|
import androidx.compose.ui.input.pointer.pointerInput
|
||||||
|
import androidx.compose.ui.layout.LayoutCoordinates
|
||||||
import androidx.compose.ui.layout.onGloballyPositioned
|
import androidx.compose.ui.layout.onGloballyPositioned
|
||||||
import androidx.compose.ui.layout.positionInRoot
|
import androidx.compose.ui.layout.positionInRoot
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
@@ -101,6 +102,7 @@ fun MessageItem(
|
|||||||
var isPressed by remember { mutableStateOf(false) }
|
var isPressed by remember { mutableStateOf(false) }
|
||||||
var avatarPressed by remember(message.id) { mutableStateOf(false) }
|
var avatarPressed by remember(message.id) { mutableStateOf(false) }
|
||||||
var bubbleBodyPositionInRoot by remember { mutableStateOf(Offset.Zero) }
|
var bubbleBodyPositionInRoot by remember { mutableStateOf(Offset.Zero) }
|
||||||
|
var slackRowLayoutCoords by remember(message.id) { mutableStateOf<LayoutCoordinates?>(null) }
|
||||||
val scaleTarget = if (isPressed && !isContextMenuForThisMessage && !isContextMenuOpen) 0.96f else 1f
|
val scaleTarget = if (isPressed && !isContextMenuForThisMessage && !isContextMenuOpen) 0.96f else 1f
|
||||||
val avatarScaleTarget = if (avatarPressed && !isContextMenuOpen) 0.96f else 1f
|
val avatarScaleTarget = if (avatarPressed && !isContextMenuOpen) 0.96f else 1f
|
||||||
val scale by animateFloatAsState(
|
val scale by animateFloatAsState(
|
||||||
@@ -210,9 +212,9 @@ fun MessageItem(
|
|||||||
bottomEnd = if (isAuthor) 8.dp else 20.dp
|
bottomEnd = if (isAuthor) 8.dp else 20.dp
|
||||||
)
|
)
|
||||||
|
|
||||||
val bubbleBodyGestures =
|
val bubblePressAndLongPress =
|
||||||
if (isContextMenuOpen) Modifier
|
if (isContextMenuOpen) Modifier
|
||||||
else Modifier.pointerInput(Unit) {
|
else Modifier.pointerInput(isContextMenuOpen, message.id) {
|
||||||
detectTapGestures(
|
detectTapGestures(
|
||||||
onPress = {
|
onPress = {
|
||||||
isPressed = true
|
isPressed = true
|
||||||
@@ -222,17 +224,49 @@ fun MessageItem(
|
|||||||
isPressed = false
|
isPressed = false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onLongPress = { offset ->
|
onLongPress = { localOffset ->
|
||||||
onTapPosition(bubbleBodyPositionInRoot + offset)
|
onTapPosition(bubbleBodyPositionInRoot + localOffset)
|
||||||
onLongPress()
|
onLongPress()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val slackRowPressAndLongPress =
|
||||||
|
if (isContextMenuOpen) Modifier
|
||||||
|
else Modifier.pointerInput(isContextMenuOpen, message.id) {
|
||||||
|
detectTapGestures(
|
||||||
|
onPress = {
|
||||||
|
isPressed = true
|
||||||
|
try {
|
||||||
|
awaitRelease()
|
||||||
|
} finally {
|
||||||
|
isPressed = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onLongPress = { localOffset ->
|
||||||
|
val coords = slackRowLayoutCoords
|
||||||
|
if (coords != null && coords.isAttached) {
|
||||||
|
onTapPosition(coords.localToRoot(localOffset))
|
||||||
|
} else {
|
||||||
|
onTapPosition(bubbleBodyPositionInRoot + localOffset)
|
||||||
|
}
|
||||||
|
onLongPress()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Full-width hit target so pressing empty row space still scales the bubble & long-press menu.
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.onGloballyPositioned { slackRowLayoutCoords = it }
|
||||||
|
.then(slackRowPressAndLongPress)
|
||||||
|
) {
|
||||||
// graphicsLayer must wrap clip/shadow/background so the whole bubble scales on press;
|
// graphicsLayer must wrap clip/shadow/background so the whole bubble scales on press;
|
||||||
// placing it only after background scaled the children but left the bubble chrome unscaled.
|
// placing it only after background scaled the children but left the bubble chrome unscaled.
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
.align(if (isAuthor) Alignment.BottomEnd else Alignment.BottomStart)
|
||||||
.widthIn(max = maxBubbleWidth)
|
.widthIn(max = maxBubbleWidth)
|
||||||
.graphicsLayer(
|
.graphicsLayer(
|
||||||
scaleX = scale,
|
scaleX = scale,
|
||||||
@@ -310,7 +344,7 @@ fun MessageItem(
|
|||||||
.onGloballyPositioned { coordinates ->
|
.onGloballyPositioned { coordinates ->
|
||||||
bubbleBodyPositionInRoot = coordinates.positionInRoot()
|
bubbleBodyPositionInRoot = coordinates.positionInRoot()
|
||||||
}
|
}
|
||||||
.then(bubbleBodyGestures)
|
.then(bubblePressAndLongPress)
|
||||||
) {
|
) {
|
||||||
Column {
|
Column {
|
||||||
// Reply preview
|
// Reply preview
|
||||||
@@ -537,6 +571,7 @@ fun MessageItem(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExperimentalTime
|
@ExperimentalTime
|
||||||
|
|||||||
Reference in New Issue
Block a user