Skip to content

Commit 9098d5d

Browse files
authored
Merge pull request #6236 from nextcloud/backport/6193/stable-24.0
[stable-24.0] fix links
2 parents 98c8734 + 595abd5 commit 9098d5d

5 files changed

Lines changed: 91 additions & 27 deletions

File tree

app/src/main/java/com/nextcloud/talk/chat/ui/model/ChatMessageUi.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,7 @@ fun resolveStatusIcon(
244244
}
245245

246246
fun getMessageTypeContent(user: User, message: ChatMessage): MessageTypeContent? =
247+
247248
if (message.isSystemMessage) {
248249
MessageTypeContent.SystemMessage
249250
} else if (message.isVoiceMessage) {

app/src/main/java/com/nextcloud/talk/ui/chat/ChatMessageScaffold.kt

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -711,23 +711,38 @@ fun CommonMessageQuote(message: ChatMessageUi) {
711711
iconRes = R.drawable.baseline_location_pin_24,
712712
label = c.name
713713
)
714-
else -> QuoteTextContent(message)
714+
else -> QuoteTextContent(message, onClick = { onQuotedMessageClick(message.id) })
715715
}
716716
}
717717
}
718718

719719
@Composable
720-
private fun QuoteTextContent(message: ChatMessageUi) {
721-
Column {
720+
private fun QuoteTextContent(message: ChatMessageUi, onClick: () -> Unit) {
721+
Column(modifier = Modifier.combinedClickable(onClick = onClick)) {
722722
Text(
723723
message.actorDisplayName,
724724
fontSize = authorTextSize,
725725
color = colorResource(R.color.no_emphasis_text)
726726
)
727-
EnrichedText(
727+
728+
val isInspectionMode = LocalInspectionMode.current
729+
val isSingleEmoji = !isInspectionMode &&
730+
message.messageParameters.isEmpty() &&
731+
TextMatchers.isMessageWithSingleEmoticonOnly(message.plainMessage)
732+
val fontSize = if (isSingleEmoji) regularTextSize * SINGLE_EMOJI_SIZE_MULTIPLIER else regularTextSize
733+
734+
MentionEnrichedText(
728735
message = message,
729736
modifier = Modifier.padding(end = 4.dp),
730-
maxLines = 4
737+
textStyle = TextStyle(
738+
fontSize = fontSize,
739+
color = colorScheme.onSurface,
740+
lineHeight = fontSize * LINE_SPACING
741+
),
742+
maxLines = 4,
743+
enableMentionClicks = false,
744+
enableLinks = false,
745+
onDisabledMentionClick = onClick
731746
)
732747
}
733748
}

app/src/main/java/com/nextcloud/talk/ui/chat/MarkdownText.kt

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,15 @@ private const val CHIP_START_PADDING_DP = 2f
6060
private const val CHIP_END_PADDING_DP = 5f
6161
private const val CHIP_VERTICAL_PADDING_DP = 2f
6262
private const val CHIP_CORNER_RADIUS_DP = 16f
63-
private const val MESSAGE_LINKIFY_MASK = Linkify.WEB_URLS or
64-
Linkify.PHONE_NUMBERS or
63+
64+
private const val MESSAGE_LINKIFY_MASK = Linkify.PHONE_NUMBERS or
6565
Linkify.EMAIL_ADDRESSES
6666

67+
val validLinkRegex = Regex(
68+
"""(?<!\w)https?://(?:www\.)?[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)+(?:/[^\s)]*)?""",
69+
RegexOption.IGNORE_CASE
70+
)
71+
6772
@Suppress("LongMethod", "LongParameterList")
6873
@Composable
6974
fun MarkdownText(
@@ -152,7 +157,10 @@ fun MarkdownText(
152157
avatarSizePx = avatarSizePx,
153158
avatarGapPx = avatarGapPx
154159
)
155-
val hasLinks = Linkify.addLinks(ssb, MESSAGE_LINKIFY_MASK)
160+
161+
val hasOtherLinks = Linkify.addLinks(ssb, MESSAGE_LINKIFY_MASK)
162+
val hasLinks = Linkify.addLinks(ssb, validLinkRegex.toPattern(), null) || hasOtherLinks
163+
156164
resolveFileParams(ssb, message)
157165
applySearchHighlight(ssb, highlightSearchTerm, searchHighlightColorArgb)
158166
textView.text = ssb

app/src/main/java/com/nextcloud/talk/ui/chat/MentionChip.kt

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import androidx.compose.runtime.Composable
2525
import androidx.compose.runtime.remember
2626
import androidx.compose.ui.Alignment
2727
import androidx.compose.ui.Modifier
28+
import androidx.compose.ui.draw.clip
2829
import androidx.compose.ui.graphics.Color
2930
import androidx.compose.ui.platform.LocalContext
3031
import androidx.compose.ui.platform.LocalDensity
@@ -34,7 +35,6 @@ import androidx.compose.ui.res.stringResource
3435
import androidx.compose.ui.semantics.Role
3536
import androidx.compose.ui.semantics.contentDescription
3637
import androidx.compose.ui.semantics.role
37-
import androidx.compose.ui.draw.clip
3838
import androidx.compose.ui.semantics.semantics
3939
import androidx.compose.ui.text.AnnotatedString
4040
import androidx.compose.ui.text.Placeholder
@@ -88,7 +88,8 @@ fun parseMentionChipModel(
8888
messageParameters: Map<String, Map<String, String>>,
8989
activeUserId: String?,
9090
activeUserBaseUrl: String?,
91-
roomToken: String?
91+
roomToken: String?,
92+
enableMentionClicks: Boolean = true
9293
): MentionChipModel? =
9394
messageParameters[key]
9495
?.takeIf { it["type"] in mentionParameterTypes }
@@ -117,7 +118,7 @@ fun parseMentionChipModel(
117118
type = type,
118119
isFederated = isFederated,
119120
isSelfMention = isSelfMention,
120-
isClickableUserMention = type == "user" && !isSelfMention && !isFederated,
121+
isClickableUserMention = enableMentionClicks && type == "user" && !isSelfMention && !isFederated,
121122
avatarUrl = avatarUrl
122123
)
123124
}
@@ -170,7 +171,8 @@ fun estimateMentionChipWidthInEm(label: String, fontSizeSp: Float): Float {
170171
fun buildMentionInlineContent(
171172
mention: MentionChipModel,
172173
textStyle: TextStyle,
173-
isMultilineLayout: Boolean
174+
isMultilineLayout: Boolean,
175+
onDisabledMentionClick: (() -> Unit)? = null
174176
): InlineTextContent {
175177
val fontSizeSp = if (textStyle.fontSize.isSpecified) textStyle.fontSize.value else CHIP_FALLBACK_FONT_SIZE_SP
176178
val width = estimateMentionChipWidthInEm(mention.name, fontSizeSp)
@@ -192,7 +194,8 @@ fun buildMentionInlineContent(
192194
MentionChip(
193195
mention = mention,
194196
textStyle = textStyle,
195-
isMultilineLayout = isMultilineLayout
197+
isMultilineLayout = isMultilineLayout,
198+
onDisabledMentionClick = onDisabledMentionClick
196199
)
197200
}
198201
}
@@ -203,9 +206,10 @@ fun AnnotatedString.Builder.appendMentionChip(
203206
mention: MentionChipModel,
204207
inlineContent: MutableMap<String, InlineTextContent>,
205208
textStyle: TextStyle,
206-
isMultilineLayout: Boolean
209+
isMultilineLayout: Boolean,
210+
onDisabledMentionClick: (() -> Unit)? = null
207211
) {
208-
inlineContent[inlineId] = buildMentionInlineContent(mention, textStyle, isMultilineLayout)
212+
inlineContent[inlineId] = buildMentionInlineContent(mention, textStyle, isMultilineLayout, onDisabledMentionClick)
209213
appendInlineContent(inlineId, "@${mention.name}")
210214
}
211215

@@ -215,8 +219,14 @@ fun AnnotatedString.Builder.appendBoldToken(text: String) {
215219
addStyle(SpanStyle(fontWeight = FontWeight.Bold), start, length)
216220
}
217221

222+
@Suppress("LongMethod")
218223
@Composable
219-
fun MentionChip(mention: MentionChipModel, textStyle: TextStyle, isMultilineLayout: Boolean) {
224+
fun MentionChip(
225+
mention: MentionChipModel,
226+
textStyle: TextStyle,
227+
isMultilineLayout: Boolean,
228+
onDisabledMentionClick: (() -> Unit)? = null
229+
) {
220230
val context = LocalContext.current
221231
val viewThemeUtils = LocalViewThemeUtils.current
222232
val density = LocalDensity.current
@@ -246,6 +256,18 @@ fun MentionChip(mention: MentionChipModel, textStyle: TextStyle, isMultilineLayo
246256
mention.name
247257
}
248258

259+
val clickModifier = when {
260+
mention.isClickableUserMention -> Modifier.clickable {
261+
EventBus.getDefault().post(UserMentionClickEvent(mention.id))
262+
}
263+
264+
onDisabledMentionClick != null -> Modifier.clickable {
265+
onDisabledMentionClick()
266+
}
267+
268+
else -> Modifier
269+
}
270+
249271
Row(
250272
modifier = Modifier
251273
.semantics {
@@ -254,9 +276,7 @@ fun MentionChip(mention: MentionChipModel, textStyle: TextStyle, isMultilineLayo
254276
}
255277
.clip(RoundedCornerShape(chipCornerRadius))
256278
.background(backgroundColor)
257-
.clickable(enabled = mention.isClickableUserMention) {
258-
EventBus.getDefault().post(UserMentionClickEvent(mention.id))
259-
}
279+
.then(clickModifier)
260280
.padding(start = verticalPadding, top = verticalPadding, end = 4.dp, bottom = verticalPadding),
261281
verticalAlignment = Alignment.CenterVertically,
262282
horizontalArrangement = Arrangement.spacedBy(4.dp)

app/src/main/java/com/nextcloud/talk/ui/chat/MentionEnrichedText.kt

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,10 @@ fun MentionEnrichedText(
3939
modifier: Modifier = Modifier,
4040
textStyle: TextStyle,
4141
maxLines: Int = Int.MAX_VALUE,
42-
highlightSearchTerm: String? = null
42+
highlightSearchTerm: String? = null,
43+
enableMentionClicks: Boolean = true,
44+
enableLinks: Boolean = true,
45+
onDisabledMentionClick: (() -> Unit)? = null
4346
) {
4447
var isMultilineLayout by remember(message.id, message.message) {
4548
mutableStateOf(message.message.contains("\n") || message.message.contains("\r"))
@@ -51,14 +54,18 @@ fun MentionEnrichedText(
5154
isMultilineLayout,
5255
linkColor,
5356
codeBackground,
54-
textStyle
57+
textStyle,
58+
enableLinks
5559
) {
5660
buildMentionRichText(
5761
message = message,
5862
linkColor = linkColor,
5963
codeBackground = codeBackground,
6064
textStyle = textStyle,
61-
isMultilineLayout = isMultilineLayout
65+
isMultilineLayout = isMultilineLayout,
66+
enableMentionClicks = enableMentionClicks,
67+
enableLinks = enableLinks,
68+
onDisabledMentionClick = onDisabledMentionClick
6269
)
6370
}
6471
val highlightedText = remember(richText.annotated, highlightSearchTerm) {
@@ -91,7 +98,10 @@ private fun buildMentionRichText(
9198
linkColor: Color,
9299
codeBackground: Color,
93100
textStyle: TextStyle,
94-
isMultilineLayout: Boolean
101+
isMultilineLayout: Boolean,
102+
enableMentionClicks: Boolean,
103+
enableLinks: Boolean,
104+
onDisabledMentionClick: (() -> Unit)?
95105
): MentionRichText {
96106
val inlineContent = linkedMapOf<String, InlineTextContent>()
97107
var mentionCounter = 0
@@ -113,14 +123,22 @@ private fun buildMentionRichText(
113123
messageParameters = message.messageParameters,
114124
activeUserId = message.activeUserId,
115125
activeUserBaseUrl = message.activeUserBaseUrl,
116-
roomToken = message.roomToken
126+
roomToken = message.roomToken,
127+
enableMentionClicks = enableMentionClicks
117128
)
118129
if (mention == null) {
119130
appendFallbackParameter(token, message.messageParameters)
120131
} else {
121132
val inlineId = "mention-${message.id}-$mentionCounter"
122133
mentionCounter += 1
123-
appendMentionChip(inlineId, mention, inlineContent, textStyle, isMultilineLayout)
134+
appendMentionChip(
135+
inlineId,
136+
mention,
137+
inlineContent,
138+
textStyle,
139+
isMultilineLayout,
140+
onDisabledMentionClick
141+
)
124142
}
125143
}
126144

@@ -146,10 +164,12 @@ private fun buildMentionRichText(
146164
token.startsWith("[") -> {
147165
val textPart = token.substringAfter("[").substringBefore("]")
148166
val url = token.substringAfter("(").substringBefore(")")
149-
appendLinkedToken(textPart, url, linkColor)
167+
if (enableLinks) appendLinkedToken(textPart, url, linkColor) else append(textPart)
150168
}
151169

152-
token.startsWith("http") -> appendLinkedToken(token, token, linkColor)
170+
token.startsWith("http") -> {
171+
if (enableLinks) appendLinkedToken(token, token, linkColor) else append(token)
172+
}
153173
}
154174

155175
lastIndex = range.last + 1

0 commit comments

Comments
 (0)