Skip to content

Commit b0081d8

Browse files
committed
chore(fc): add delays for all message actions except tip; add long press to reply preview and date
Signed-off-by: Brandon McAnsh <[email protected]>
1 parent 5d7a0f5 commit b0081d8

File tree

3 files changed

+109
-23
lines changed

3 files changed

+109
-23
lines changed

flipchatApp/src/main/kotlin/xyz/flipchat/app/features/chat/conversation/MessageActionContextSheet.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,9 @@ internal data class MessageActionContextSheet(val actions: List<MessageControlAc
4646
.clickable {
4747
composeScope.launch {
4848
navigator.hide()
49-
delay(300)
49+
if (action.delayUponSelection) {
50+
delay(300)
51+
}
5052
action.onSelect()
5153
}
5254
}

ui/components/src/main/kotlin/com/getcode/ui/components/chat/messagecontents/MessageReplyContent.kt

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.getcode.ui.components.chat.messagecontents
22

33
import androidx.compose.foundation.background
4+
import androidx.compose.foundation.gestures.detectTapGestures
45
import androidx.compose.foundation.layout.Box
56
import androidx.compose.foundation.layout.Column
67
import androidx.compose.foundation.layout.IntrinsicSize
@@ -18,6 +19,7 @@ import androidx.compose.ui.Modifier
1819
import androidx.compose.ui.draw.clip
1920
import androidx.compose.ui.graphics.Color
2021
import androidx.compose.ui.graphics.Shape
22+
import androidx.compose.ui.input.pointer.pointerInput
2123
import androidx.compose.ui.layout.SubcomposeLayout
2224
import androidx.compose.ui.res.stringResource
2325
import androidx.compose.ui.text.AnnotatedString
@@ -92,9 +94,16 @@ internal fun MessageNodeScope.MessageReplyContent(
9294
MessageReplyPreview(
9395
modifier = Modifier
9496
.widthIn(min = messageContentPlaceable.width.toDp())
95-
.noRippleClickable { onOriginalMessageClicked() },
97+
.pointerInput(Unit) {
98+
detectTapGestures(
99+
onLongPress = if (!options.isInteractive) null else {
100+
{ showControls() }
101+
},
102+
onTap = { onOriginalMessageClicked() }
103+
)
104+
},
96105
originalMessage = originalMessage,
97-
backgroundColor = Color.Black.copy(0.1f)
106+
backgroundColor = Color.Black.copy(0.1f),
98107
)
99108
}.first().measure(
100109
constraints.copy(minWidth = messageContentPlaceable.width, maxWidth = constraints.maxWidth)
@@ -121,14 +130,15 @@ fun MessageReplyPreview(
121130
originalMessage: ReplyMessageAnchor,
122131
modifier: Modifier = Modifier,
123132
backgroundColor: Color = Color.Transparent,
133+
124134
) {
125135
val colors = generateComplementaryColorPalette(originalMessage.sender.id!!)
126136
Row(
127137
modifier = modifier
128138
.width(IntrinsicSize.Max)
129139
.height(IntrinsicSize.Min)
130140
.background(backgroundColor, CodeTheme.shapes.extraSmall)
131-
.clip(CodeTheme.shapes.extraSmall)
141+
.clip(CodeTheme.shapes.extraSmall),
132142
) {
133143
Box(
134144
modifier = Modifier

ui/components/src/main/kotlin/com/getcode/ui/components/chat/messagecontents/MessageTextContent.kt

Lines changed: 93 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -58,60 +58,79 @@ import kotlin.math.max
5858

5959
sealed interface MessageControlAction {
6060
val onSelect: () -> Unit
61+
6162
@get:Composable
6263
val painter: Painter
6364
val isDestructive: Boolean
65+
val delayUponSelection: Boolean
6466

6567
data class Copy(override val onSelect: () -> Unit) : MessageControlAction {
6668
override val isDestructive: Boolean = false
69+
override val delayUponSelection: Boolean = false
6770

6871
override val painter: Painter
6972
@Composable get() = rememberVectorPainter(Icons.Default.ContentCopy)
7073
}
74+
7175
data class Reply(override val onSelect: () -> Unit) : MessageControlAction {
7276
override val isDestructive: Boolean = false
7377
override val painter: Painter
7478
@Composable get() = rememberVectorPainter(Icons.AutoMirrored.Default.Reply)
79+
override val delayUponSelection: Boolean = false
7580
}
7681

77-
data class Tip(override val onSelect: () -> Unit): MessageControlAction {
82+
data class Tip(override val onSelect: () -> Unit) : MessageControlAction {
7883
override val isDestructive: Boolean = false
7984
override val painter: Painter
8085
@Composable get() = painterResource(R.drawable.ic_kin_white_small)
86+
override val delayUponSelection: Boolean = true
8187
}
8288

8389
data class Delete(override val onSelect: () -> Unit) : MessageControlAction {
8490
override val isDestructive: Boolean = true
8591
override val painter: Painter
8692
@Composable get() = rememberVectorPainter(Icons.Default.Delete)
93+
override val delayUponSelection: Boolean = false
8794
}
95+
8896
data class RemoveUser(val name: String, override val onSelect: () -> Unit) :
8997
MessageControlAction {
9098
override val isDestructive: Boolean = true
9199
override val painter: Painter
92100
@Composable get() = rememberVectorPainter(Icons.Default.PersonRemove)
101+
override val delayUponSelection: Boolean = false
93102
}
94103

95-
data class MuteUser(val name: String, override val onSelect: () -> Unit) : MessageControlAction {
104+
data class MuteUser(val name: String, override val onSelect: () -> Unit) :
105+
MessageControlAction {
96106
override val isDestructive: Boolean = true
97107
override val painter: Painter
98108
@Composable get() = rememberVectorPainter(Icons.Default.VoiceOverOff)
109+
override val delayUponSelection: Boolean = false
99110
}
111+
100112
data class ReportUserForMessage(val name: String, override val onSelect: () -> Unit) :
101113
MessageControlAction {
102114
override val isDestructive: Boolean = true
103115
override val painter: Painter
104116
@Composable get() = rememberVectorPainter(Icons.Default.Flag)
117+
override val delayUponSelection: Boolean = false
105118
}
106-
data class BlockUser(val name: String, override val onSelect: () -> Unit): MessageControlAction {
119+
120+
data class BlockUser(val name: String, override val onSelect: () -> Unit) :
121+
MessageControlAction {
107122
override val isDestructive: Boolean = true
108123
override val painter: Painter
109124
@Composable get() = rememberVectorPainter(Icons.Default.Block)
125+
override val delayUponSelection: Boolean = false
110126
}
111-
data class UnblockUser(val name: String, override val onSelect: () -> Unit): MessageControlAction {
127+
128+
data class UnblockUser(val name: String, override val onSelect: () -> Unit) :
129+
MessageControlAction {
112130
override val isDestructive: Boolean = false
113131
override val painter: Painter
114132
@Composable get() = rememberVectorPainter(Icons.Default.Person)
133+
override val delayUponSelection: Boolean = false
115134
}
116135
}
117136

@@ -173,9 +192,9 @@ internal fun MessageNodeScope.MessageText(
173192
@Composable
174193
private fun rememberAlignmentRule(
175194
contentTextStyle: TextStyle,
176-
minWidth:Int = 0,
195+
minWidth: Int = 0,
177196
maxWidth: Int,
178-
message: String,
197+
message: AnnotatedString,
179198
date: Instant
180199
): State<AlignmentRule?> {
181200
val density = LocalDensity.current
@@ -243,20 +262,52 @@ internal fun MessageContent(
243262
options: MessageNodeOptions,
244263
onLongPress: () -> Unit = { },
245264
onDoubleClick: () -> Unit = { },
265+
) {
266+
MessageContent(
267+
modifier = modifier,
268+
minWidth = minWidth,
269+
maxWidth = maxWidth,
270+
annotatedMessage = AnnotatedString(message),
271+
date = date,
272+
status = status,
273+
isFromSelf = isFromSelf,
274+
isFromBlockedMember = isFromBlockedMember,
275+
options = options,
276+
onLongPress = onLongPress,
277+
onDoubleClick = onDoubleClick
278+
)
279+
}
280+
281+
@Composable
282+
internal fun MessageContent(
283+
modifier: Modifier = Modifier,
284+
minWidth: Int = 0,
285+
maxWidth: Int,
286+
annotatedMessage: AnnotatedString,
287+
date: Instant,
288+
status: MessageStatus,
289+
isFromSelf: Boolean,
290+
isFromBlockedMember: Boolean,
291+
options: MessageNodeOptions,
292+
onLongPress: () -> Unit = { },
293+
onDoubleClick: () -> Unit = { },
246294
) {
247295
val alignmentRule by rememberAlignmentRule(
248296
contentTextStyle = options.contentStyle,
249297
minWidth = minWidth,
250298
maxWidth = maxWidth,
251-
message = message,
299+
message = annotatedMessage,
252300
date = date,
253301
)
254302

255303
when (alignmentRule) {
256304
AlignmentRule.Column -> {
257-
Column(modifier = modifier, verticalArrangement = Arrangement.spacedBy(CodeTheme.dimens.grid.x1)) {
305+
Column(
306+
modifier = modifier,
307+
verticalArrangement = Arrangement.spacedBy(CodeTheme.dimens.grid.x1)
308+
) {
258309
MarkupTextHandler(
259-
text = message,
310+
text = annotatedMessage,
260311
options = options,
261312
onLongPress = onLongPress,
262313
isFromBlockedMember = isFromBlockedMember,
@@ -265,7 +316,13 @@ internal fun MessageContent(
265316
DateWithStatus(
266317
modifier = Modifier
267318
.align(Alignment.End)
268-
.pointerInput(Unit) { detectTapGestures { }},
319+
.pointerInput(Unit) {
320+
detectTapGestures(
321+
onLongPress = if (!options.isInteractive) null else {
322+
{ onLongPress() }
323+
},
324+
)
325+
},
269326
date = date,
270327
status = status,
271328
isFromSelf = isFromSelf,
@@ -277,9 +334,10 @@ internal fun MessageContent(
277334

278335
AlignmentRule.ParagraphLastLine -> {
279336
Column(
280-
modifier = modifier.padding(CodeTheme.dimens.grid.x1)) {
337+
modifier = modifier.padding(CodeTheme.dimens.grid.x1)
338+
) {
281339
MarkupTextHandler(
282-
text = message,
340+
text = annotatedMessage,
283341
options = options,
284342
onLongPress = onLongPress,
285343
isFromBlockedMember = isFromBlockedMember,
@@ -288,7 +346,13 @@ internal fun MessageContent(
288346
DateWithStatus(
289347
modifier = Modifier
290348
.align(Alignment.End)
291-
.pointerInput(Unit) { detectTapGestures { }},
349+
.pointerInput(Unit) {
350+
detectTapGestures(
351+
onLongPress = if (!options.isInteractive) null else {
352+
{ onLongPress() }
353+
},
354+
)
355+
},
292356
date = date,
293357
status = status,
294358
isFromSelf = isFromSelf,
@@ -304,7 +368,7 @@ internal fun MessageContent(
304368
horizontalArrangement = Arrangement.spacedBy(CodeTheme.dimens.grid.x1)
305369
) {
306370
MarkupTextHandler(
307-
text = message,
371+
text = annotatedMessage,
308372
options = options,
309373
onLongPress = onLongPress,
310374
isFromBlockedMember = isFromBlockedMember,
@@ -313,7 +377,13 @@ internal fun MessageContent(
313377
DateWithStatus(
314378
modifier = Modifier
315379
.padding(top = CodeTheme.dimens.grid.x1 + 2.dp)
316-
.pointerInput(Unit) { detectTapGestures { }},
380+
.pointerInput(Unit) {
381+
detectTapGestures(
382+
onLongPress = if (!options.isInteractive) null else {
383+
{ onLongPress() }
384+
},
385+
)
386+
},
317387
date = date,
318388
status = status,
319389
isFromSelf = isFromSelf,
@@ -329,7 +399,7 @@ internal fun MessageContent(
329399

330400
@Composable
331401
private fun MarkupTextHandler(
332-
text: String,
402+
text: AnnotatedString,
333403
options: MessageNodeOptions,
334404
isFromBlockedMember: Boolean,
335405
modifier: Modifier = Modifier,
@@ -349,12 +419,13 @@ private fun MarkupTextHandler(
349419
)
350420

351421
}
422+
352423
options.onMarkupClicked != null -> {
353424
val handler = options.onMarkupClicked
354425
val markupTextHelper = remember { MarkupTextHelper() }
355426
val markups = options.markupsToResolve.map { Markup.create(it) }
356427

357-
val annotatedString = markupTextHelper.annotate(text, markups)
428+
val annotatedString = markupTextHelper.annotate(text.text, markups)
358429

359430
val handleTouchedContent = { offset: Int ->
360431
annotatedString.getStringAnnotations(
@@ -399,12 +470,15 @@ private fun MarkupTextHandler(
399470
}
400471
},
401472
onDoubleTap = { _ -> onDoubleClick() },
402-
onLongPress = if (!options.isInteractive) null else { { onLongPress() } },
473+
onLongPress = if (!options.isInteractive) null else {
474+
{ onLongPress() }
475+
},
403476
)
404-
},
477+
},
405478
onTextLayout = { layoutResult = it }
406479
)
407480
}
481+
408482
else -> {
409483
Text(modifier = modifier, text = text, style = options.contentStyle)
410484
}

0 commit comments

Comments
 (0)