Allow text selection with multiple links in message
This commit is contained in:
parent
7b52e6984c
commit
8ca5eb4429
|
@ -15,6 +15,7 @@ import android.os.Build;
|
||||||
import android.support.v4.content.FileProvider;
|
import android.support.v4.content.FileProvider;
|
||||||
import android.text.Spannable;
|
import android.text.Spannable;
|
||||||
import android.text.SpannableString;
|
import android.text.SpannableString;
|
||||||
|
import android.text.SpannableStringBuilder;
|
||||||
import android.text.Spanned;
|
import android.text.Spanned;
|
||||||
import android.text.style.ForegroundColorSpan;
|
import android.text.style.ForegroundColorSpan;
|
||||||
import android.text.style.RelativeSizeSpan;
|
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.Message.FileParams;
|
||||||
import eu.siacs.conversations.entities.Transferable;
|
import eu.siacs.conversations.entities.Transferable;
|
||||||
import eu.siacs.conversations.ui.ConversationActivity;
|
import eu.siacs.conversations.ui.ConversationActivity;
|
||||||
|
import eu.siacs.conversations.ui.widget.ClickableMovementMethod;
|
||||||
import eu.siacs.conversations.utils.CryptoHelper;
|
import eu.siacs.conversations.utils.CryptoHelper;
|
||||||
import eu.siacs.conversations.utils.GeoHelper;
|
import eu.siacs.conversations.utils.GeoHelper;
|
||||||
import eu.siacs.conversations.utils.UIHelper;
|
import eu.siacs.conversations.utils.UIHelper;
|
||||||
|
@ -314,7 +316,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
|
||||||
if (body.length() > Config.MAX_DISPLAY_MESSAGE_CHARS) {
|
if (body.length() > Config.MAX_DISPLAY_MESSAGE_CHARS) {
|
||||||
body = body.substring(0, Config.MAX_DISPLAY_MESSAGE_CHARS)+"\u2026";
|
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);
|
int i = body.indexOf(Message.MERGE_SEPARATOR);
|
||||||
while(i >= 0) {
|
while(i >= 0) {
|
||||||
final int end = i + Message.MERGE_SEPARATOR.length();
|
final int end = i + Message.MERGE_SEPARATOR.length();
|
||||||
|
@ -323,12 +325,8 @@ public class MessageAdapter extends ArrayAdapter<Message> {
|
||||||
}
|
}
|
||||||
if (message.getType() != Message.TYPE_PRIVATE) {
|
if (message.getType() != Message.TYPE_PRIVATE) {
|
||||||
if (message.hasMeCommand()) {
|
if (message.hasMeCommand()) {
|
||||||
final Spannable span = new SpannableString(formattedBody);
|
formattedBody.setSpan(new StyleSpan(Typeface.BOLD_ITALIC), 0, nick.length(),
|
||||||
span.setSpan(new StyleSpan(Typeface.BOLD_ITALIC), 0, nick.length(),
|
|
||||||
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
viewHolder.messageBody.setText(span);
|
|
||||||
} else {
|
|
||||||
viewHolder.messageBody.setText(formattedBody);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
String privateMarker;
|
String privateMarker;
|
||||||
|
@ -344,46 +342,25 @@ public class MessageAdapter extends ArrayAdapter<Message> {
|
||||||
}
|
}
|
||||||
privateMarker = activity.getString(R.string.private_message_to, to);
|
privateMarker = activity.getString(R.string.private_message_to, to);
|
||||||
}
|
}
|
||||||
final Spannable span = new SpannableString(privateMarker + " "
|
formattedBody = new SpannableStringBuilder().append(privateMarker).append(' ').append(formattedBody);
|
||||||
+ formattedBody);
|
formattedBody.setSpan(new ForegroundColorSpan(getMessageTextColor(darkBackground,false)), 0, privateMarker
|
||||||
span.setSpan(new ForegroundColorSpan(getMessageTextColor(darkBackground,false)), 0, privateMarker
|
|
||||||
.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
span.setSpan(new StyleSpan(Typeface.BOLD), 0,
|
formattedBody.setSpan(new StyleSpan(Typeface.BOLD), 0,
|
||||||
privateMarker.length(),
|
privateMarker.length(),
|
||||||
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
if (message.hasMeCommand()) {
|
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(),
|
privateMarker.length() + 1 + nick.length(),
|
||||||
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
}
|
}
|
||||||
viewHolder.messageBody.setText(span);
|
|
||||||
}
|
}
|
||||||
int urlCount = 0;
|
Linkify.addLinks(formattedBody, Linkify.WEB_URLS);
|
||||||
final Matcher matcher = Patterns.WEB_URL.matcher(body);
|
Linkify.addLinks(formattedBody, XMPP_PATTERN, "xmpp");
|
||||||
int beginWebURL = Integer.MAX_VALUE;
|
Linkify.addLinks(formattedBody, GeoHelper.GEO_URI, "geo");
|
||||||
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);
|
|
||||||
viewHolder.messageBody.setAutoLinkMask(0);
|
viewHolder.messageBody.setAutoLinkMask(0);
|
||||||
Linkify.addLinks(viewHolder.messageBody, Linkify.WEB_URLS);
|
viewHolder.messageBody.setText(formattedBody);
|
||||||
Linkify.addLinks(viewHolder.messageBody, XMPP_PATTERN, "xmpp");
|
viewHolder.messageBody.setTextIsSelectable(true);
|
||||||
Linkify.addLinks(viewHolder.messageBody, GeoHelper.GEO_URI, "geo");
|
viewHolder.messageBody.setMovementMethod(ClickableMovementMethod.getInstance());
|
||||||
} else {
|
} else {
|
||||||
viewHolder.messageBody.setText("");
|
viewHolder.messageBody.setText("");
|
||||||
viewHolder.messageBody.setTextIsSelectable(false);
|
viewHolder.messageBody.setTextIsSelectable(false);
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
Loading…
Reference in a new issue