From 8ca5eb442952a40c16486b8abdc197087b7d7c2b Mon Sep 17 00:00:00 2001 From: Mishiranu Date: Fri, 16 Sep 2016 02:15:07 +0300 Subject: [PATCH] Allow text selection with multiple links in message --- .../ui/adapter/MessageAdapter.java | 51 +++++-------------- .../ui/widget/ClickableMovementMethod.java | 42 +++++++++++++++ 2 files changed, 56 insertions(+), 37 deletions(-) create mode 100644 src/main/java/eu/siacs/conversations/ui/widget/ClickableMovementMethod.java diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java index 6f5369830..ae31adcbb 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java @@ -15,6 +15,7 @@ import android.os.Build; import android.support.v4.content.FileProvider; import android.text.Spannable; import android.text.SpannableString; +import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.style.ForegroundColorSpan; import android.text.style.RelativeSizeSpan; @@ -51,6 +52,7 @@ import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.entities.Message.FileParams; import eu.siacs.conversations.entities.Transferable; import eu.siacs.conversations.ui.ConversationActivity; +import eu.siacs.conversations.ui.widget.ClickableMovementMethod; import eu.siacs.conversations.utils.CryptoHelper; import eu.siacs.conversations.utils.GeoHelper; import eu.siacs.conversations.utils.UIHelper; @@ -314,7 +316,7 @@ public class MessageAdapter extends ArrayAdapter { if (body.length() > Config.MAX_DISPLAY_MESSAGE_CHARS) { body = body.substring(0, Config.MAX_DISPLAY_MESSAGE_CHARS)+"\u2026"; } - final SpannableString formattedBody = new SpannableString(body); + Spannable formattedBody = new SpannableString(body); int i = body.indexOf(Message.MERGE_SEPARATOR); while(i >= 0) { final int end = i + Message.MERGE_SEPARATOR.length(); @@ -323,12 +325,8 @@ public class MessageAdapter extends ArrayAdapter { } if (message.getType() != Message.TYPE_PRIVATE) { if (message.hasMeCommand()) { - final Spannable span = new SpannableString(formattedBody); - span.setSpan(new StyleSpan(Typeface.BOLD_ITALIC), 0, nick.length(), + formattedBody.setSpan(new StyleSpan(Typeface.BOLD_ITALIC), 0, nick.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - viewHolder.messageBody.setText(span); - } else { - viewHolder.messageBody.setText(formattedBody); } } else { String privateMarker; @@ -344,46 +342,25 @@ public class MessageAdapter extends ArrayAdapter { } privateMarker = activity.getString(R.string.private_message_to, to); } - final Spannable span = new SpannableString(privateMarker + " " - + formattedBody); - span.setSpan(new ForegroundColorSpan(getMessageTextColor(darkBackground,false)), 0, privateMarker + formattedBody = new SpannableStringBuilder().append(privateMarker).append(' ').append(formattedBody); + formattedBody.setSpan(new ForegroundColorSpan(getMessageTextColor(darkBackground,false)), 0, privateMarker .length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - span.setSpan(new StyleSpan(Typeface.BOLD), 0, + formattedBody.setSpan(new StyleSpan(Typeface.BOLD), 0, privateMarker.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); if (message.hasMeCommand()) { - span.setSpan(new StyleSpan(Typeface.BOLD_ITALIC), privateMarker.length() + 1, + formattedBody.setSpan(new StyleSpan(Typeface.BOLD_ITALIC), privateMarker.length() + 1, privateMarker.length() + 1 + nick.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } - viewHolder.messageBody.setText(span); } - int urlCount = 0; - final Matcher matcher = Patterns.WEB_URL.matcher(body); - int beginWebURL = Integer.MAX_VALUE; - int endWebURL = 0; - while (matcher.find()) { - MatchResult result = matcher.toMatchResult(); - beginWebURL = result.start(); - endWebURL = result.end(); - urlCount++; - } - final Matcher geoMatcher = GeoHelper.GEO_URI.matcher(body); - while (geoMatcher.find()) { - urlCount++; - } - final Matcher xmppMatcher = XMPP_PATTERN.matcher(body); - while (xmppMatcher.find()) { - MatchResult result = xmppMatcher.toMatchResult(); - if (beginWebURL < result.start() || endWebURL > result.end()) { - urlCount++; - } - } - viewHolder.messageBody.setTextIsSelectable(urlCount <= 1); + Linkify.addLinks(formattedBody, Linkify.WEB_URLS); + Linkify.addLinks(formattedBody, XMPP_PATTERN, "xmpp"); + Linkify.addLinks(formattedBody, GeoHelper.GEO_URI, "geo"); viewHolder.messageBody.setAutoLinkMask(0); - Linkify.addLinks(viewHolder.messageBody, Linkify.WEB_URLS); - Linkify.addLinks(viewHolder.messageBody, XMPP_PATTERN, "xmpp"); - Linkify.addLinks(viewHolder.messageBody, GeoHelper.GEO_URI, "geo"); + viewHolder.messageBody.setText(formattedBody); + viewHolder.messageBody.setTextIsSelectable(true); + viewHolder.messageBody.setMovementMethod(ClickableMovementMethod.getInstance()); } else { viewHolder.messageBody.setText(""); viewHolder.messageBody.setTextIsSelectable(false); diff --git a/src/main/java/eu/siacs/conversations/ui/widget/ClickableMovementMethod.java b/src/main/java/eu/siacs/conversations/ui/widget/ClickableMovementMethod.java new file mode 100644 index 000000000..8659a192e --- /dev/null +++ b/src/main/java/eu/siacs/conversations/ui/widget/ClickableMovementMethod.java @@ -0,0 +1,42 @@ +package eu.siacs.conversations.ui.widget; + +import android.text.Layout; +import android.text.Spannable; +import android.text.method.ArrowKeyMovementMethod; +import android.text.style.ClickableSpan; +import android.view.MotionEvent; +import android.widget.TextView; + +public class ClickableMovementMethod extends ArrowKeyMovementMethod { + + @Override + public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) { + // Just copied from android.text.method.LinkMovementMethod + if (event.getAction() == MotionEvent.ACTION_UP) { + int x = (int) event.getX(); + int y = (int) event.getY(); + x -= widget.getTotalPaddingLeft(); + y -= widget.getTotalPaddingTop(); + x += widget.getScrollX(); + y += widget.getScrollY(); + Layout layout = widget.getLayout(); + int line = layout.getLineForVertical(y); + int off = layout.getOffsetForHorizontal(line, x); + ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class); + if (link.length != 0) { + link[0].onClick(widget); + return true; + } + } + return super.onTouchEvent(widget, buffer, event); + } + + public static ClickableMovementMethod getInstance() { + if (sInstance == null) { + sInstance = new ClickableMovementMethod(); + } + return sInstance; + } + + private static ClickableMovementMethod sInstance; +} \ No newline at end of file