fix issue mention links in markdown
This commit is contained in:
@@ -8797,6 +8797,7 @@ private fun IssueCommentCard(
|
||||
members: List<Models.Member> = emptyList(),
|
||||
agents: List<Models.Agent> = emptyList(),
|
||||
currentUser: Models.User? = null,
|
||||
onIssueIdClick: ((String) -> Unit)? = null,
|
||||
onIssueReferenceClick: ((String) -> Unit)? = null,
|
||||
expandedActions: Boolean,
|
||||
contentExpanded: Boolean,
|
||||
@@ -8890,6 +8891,7 @@ private fun IssueCommentCard(
|
||||
members = members,
|
||||
agents = agents,
|
||||
currentUser = currentUser,
|
||||
onIssueIdClick = onIssueIdClick,
|
||||
onIssueReferenceClick = onIssueReferenceClick,
|
||||
)
|
||||
if (collapseContent) {
|
||||
@@ -9891,6 +9893,7 @@ private fun PilotIssueDetail(
|
||||
members = data.members,
|
||||
agents = data.agents,
|
||||
currentUser = currentUser,
|
||||
onIssueIdClick = { onOpenIssue(it) },
|
||||
onIssueReferenceClick = { openIssueReference(it) },
|
||||
)
|
||||
}
|
||||
@@ -10037,6 +10040,7 @@ private fun PilotIssueDetail(
|
||||
members = data.members,
|
||||
agents = data.agents,
|
||||
currentUser = currentUser,
|
||||
onIssueIdClick = { onOpenIssue(it) },
|
||||
onIssueReferenceClick = { openIssueReference(it) },
|
||||
expandedActions = expandedCommentActionsId == comment.id,
|
||||
contentExpanded = comment.id in expandedCommentContentIds,
|
||||
@@ -11448,12 +11452,13 @@ private fun MarkdownBlock(
|
||||
members: List<Models.Member> = emptyList(),
|
||||
agents: List<Models.Agent> = emptyList(),
|
||||
currentUser: Models.User? = null,
|
||||
onIssueIdClick: ((String) -> Unit)? = null,
|
||||
onIssueReferenceClick: ((String) -> Unit)? = null,
|
||||
) {
|
||||
val textColor = MulticaColors.Text.toArgb()
|
||||
val mutedColor = MulticaColors.Muted.toArgb()
|
||||
val borderColor = MulticaColors.Border.toArgb()
|
||||
val linkHandler = remember(members, agents, currentUser, onIssueReferenceClick) {
|
||||
val linkHandler = remember(members, agents, currentUser, onIssueIdClick, onIssueReferenceClick) {
|
||||
object : MarkdownRenderer.LinkHandler {
|
||||
override fun resolveMentionLabel(
|
||||
mentionType: String,
|
||||
@@ -11470,6 +11475,10 @@ private fun MarkdownBlock(
|
||||
)
|
||||
}
|
||||
|
||||
override fun openIssueId(issueId: String) {
|
||||
if (issueId.isNotBlank()) onIssueIdClick?.invoke(issueId)
|
||||
}
|
||||
|
||||
override fun openIssueIdentifier(identifier: String) {
|
||||
if (identifier.isNotBlank()) onIssueReferenceClick?.invoke(identifier)
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package ai.multica.app;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.graphics.Typeface;
|
||||
import android.text.Layout;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.Spanned;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
@@ -12,6 +13,7 @@ import android.text.style.ForegroundColorSpan;
|
||||
import android.text.style.StyleSpan;
|
||||
import android.text.style.TypefaceSpan;
|
||||
import android.text.style.UnderlineSpan;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.View;
|
||||
import android.widget.HorizontalScrollView;
|
||||
@@ -30,6 +32,7 @@ final class MarkdownRenderer {
|
||||
|
||||
interface LinkHandler {
|
||||
String resolveMentionLabel(String mentionType, String mentionId, String fallbackLabel);
|
||||
void openIssueId(String issueId);
|
||||
void openIssueIdentifier(String identifier);
|
||||
}
|
||||
|
||||
@@ -124,6 +127,7 @@ final class MarkdownRenderer {
|
||||
TextView bullet = text(context, "• " + trimmed.substring(2), 15, textColor);
|
||||
bullet.setText(applyInline(bullet.getText().toString(), linkHandler));
|
||||
bullet.setMovementMethod(LinkMovementMethod.getInstance());
|
||||
enableClickableSpans(bullet);
|
||||
bullet.setPadding(dp(context, 8), dp(context, 2), 0, dp(context, 2));
|
||||
parent.addView(bullet);
|
||||
} else {
|
||||
@@ -148,6 +152,7 @@ final class MarkdownRenderer {
|
||||
TextView p = text(context, String.join("\n", paragraph), 15, textColor);
|
||||
p.setText(applyInline(p.getText().toString(), linkHandler));
|
||||
p.setMovementMethod(LinkMovementMethod.getInstance());
|
||||
enableClickableSpans(p);
|
||||
p.setPadding(0, dp(context, 2), 0, dp(context, 6));
|
||||
parent.addView(p);
|
||||
paragraph.clear();
|
||||
@@ -194,6 +199,7 @@ final class MarkdownRenderer {
|
||||
TextView tv = text(context, "", 14, r == 0 ? textColor : mutedColor);
|
||||
tv.setText(applyInline(cellText, linkHandler));
|
||||
tv.setMovementMethod(LinkMovementMethod.getInstance());
|
||||
enableClickableSpans(tv);
|
||||
tv.setTypeface(r == 0 ? Typeface.DEFAULT_BOLD : Typeface.DEFAULT);
|
||||
tv.setPadding(dp(context, 10), dp(context, 8), dp(context, 10), dp(context, 8));
|
||||
tv.setBackgroundColor(r == 0 ? palette.tableHeaderBackground : palette.tableCellBackground);
|
||||
@@ -325,6 +331,12 @@ final class MarkdownRenderer {
|
||||
private static void appendMarkdownLink(SpannableStringBuilder out, ParsedMarkdownLink link, LinkHandler linkHandler) {
|
||||
MentionUri mention = MentionUri.parse(link.url);
|
||||
if (mention != null) {
|
||||
if ("issue".equals(mention.type)) {
|
||||
appendLinkedText(out, link.label, view -> {
|
||||
if (linkHandler != null) linkHandler.openIssueId(mention.id);
|
||||
});
|
||||
return;
|
||||
}
|
||||
String label = linkHandler == null
|
||||
? IssueCommentRichText.mentionDisplayLabel(mention.type, mention.id, link.label, new ArrayList<>(), new ArrayList<>(), null)
|
||||
: linkHandler.resolveMentionLabel(mention.type, mention.id, link.label);
|
||||
@@ -364,6 +376,35 @@ final class MarkdownRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
private static void enableClickableSpans(TextView textView) {
|
||||
CharSequence text = textView.getText();
|
||||
if (!(text instanceof Spanned)) return;
|
||||
Spanned spanned = (Spanned) text;
|
||||
if (spanned.getSpans(0, spanned.length(), ClickableSpan.class).length == 0) return;
|
||||
textView.setOnTouchListener((view, event) -> {
|
||||
if (event.getAction() != MotionEvent.ACTION_UP && event.getAction() != MotionEvent.ACTION_DOWN) return false;
|
||||
TextView touchedTextView = (TextView) view;
|
||||
ClickableSpan span = clickableSpanAt(touchedTextView, event);
|
||||
if (span == null) return false;
|
||||
if (event.getAction() == MotionEvent.ACTION_UP) span.onClick(touchedTextView);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private static ClickableSpan clickableSpanAt(TextView textView, MotionEvent event) {
|
||||
CharSequence text = textView.getText();
|
||||
Layout layout = textView.getLayout();
|
||||
if (!(text instanceof Spanned) || layout == null) return null;
|
||||
int x = (int) event.getX() - textView.getTotalPaddingLeft() + textView.getScrollX();
|
||||
int y = (int) event.getY() - textView.getTotalPaddingTop() + textView.getScrollY();
|
||||
if (x < 0 || y < 0 || y > layout.getHeight()) return null;
|
||||
int line = layout.getLineForVertical(y);
|
||||
if (x < layout.getLineLeft(line) || x > layout.getLineRight(line)) return null;
|
||||
int offset = layout.getOffsetForHorizontal(line, x);
|
||||
ClickableSpan[] spans = ((Spanned) text).getSpans(offset, offset, ClickableSpan.class);
|
||||
return spans.length == 0 ? null : spans[0];
|
||||
}
|
||||
|
||||
private static ParsedMarkdownLink parseMarkdownLink(String value, int start) {
|
||||
int labelEnd = value.indexOf("](", start + 1);
|
||||
if (labelEnd <= start + 1) return null;
|
||||
|
||||
Reference in New Issue
Block a user