mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-27 12:05:22 +00:00
parent
f07ce7b1f1
commit
c3164a8e84
@ -75,9 +75,7 @@
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textColor="?conversation_item_received_text_primary_color"
|
||||
android:textColorLink="?conversation_item_received_text_primary_color"
|
||||
android:textSize="@dimen/conversation_item_body_text_size"
|
||||
android:autoLink="all"
|
||||
android:linksClickable="true" />
|
||||
android:textSize="@dimen/conversation_item_body_text_size" />
|
||||
|
||||
<LinearLayout android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
|
@ -57,12 +57,10 @@
|
||||
|
||||
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
|
||||
android:id="@+id/conversation_item_body"
|
||||
android:autoLink="all"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="4dp"
|
||||
android:paddingRight="4dp"
|
||||
android:linksClickable="true"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textColor="?conversation_item_sent_text_primary_color"
|
||||
android:textColorLink="?conversation_item_sent_text_primary_color"
|
||||
|
@ -97,6 +97,7 @@
|
||||
<string name="ConversationItem_click_to_approve_unencrypted_mms_dialog_title">Fallback to unencrypted MMS?</string>
|
||||
<string name="ConversationItem_click_to_approve_unencrypted_dialog_message">This message will <b>not</b> be encrypted because the recipient is no longer a Signal user.\n\nSend unsecured message?</string>
|
||||
<string name="ConversationItem_unable_to_open_media">Can\'t find an app able to open this media.</string>
|
||||
<string name="ConversationItem_copied_text">Copied %s</string>
|
||||
<string name="ConversationItem_from_s">from %s</string>
|
||||
<string name="ConversationItem_to_s">to %s</string>
|
||||
|
||||
|
@ -28,7 +28,10 @@ import android.os.AsyncTask;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.text.SpannableString;
|
||||
import android.text.Spanned;
|
||||
import android.text.TextUtils;
|
||||
import android.text.style.URLSpan;
|
||||
import android.text.util.Linkify;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
@ -69,6 +72,8 @@ import org.thoughtcrime.securesms.recipients.Recipients;
|
||||
import org.thoughtcrime.securesms.service.ExpiringMessageManager;
|
||||
import org.thoughtcrime.securesms.util.DateUtils;
|
||||
import org.thoughtcrime.securesms.util.DynamicTheme;
|
||||
import org.thoughtcrime.securesms.util.LongClickCopySpan;
|
||||
import org.thoughtcrime.securesms.util.LongClickMovementMethod;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.thoughtcrime.securesms.util.dualsim.SubscriptionInfoCompat;
|
||||
@ -164,6 +169,8 @@ public class ConversationItem extends LinearLayout
|
||||
|
||||
bodyText.setOnLongClickListener(passthroughClickListener);
|
||||
bodyText.setOnClickListener(passthroughClickListener);
|
||||
|
||||
bodyText.setMovementMethod(LongClickMovementMethod.getInstance(getContext()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -266,7 +273,6 @@ public class ConversationItem extends LinearLayout
|
||||
|
||||
private void setInteractionState(MessageRecord messageRecord) {
|
||||
setSelected(batchSelected.contains(messageRecord));
|
||||
bodyText.setAutoLinkMask(batchSelected.isEmpty() ? Linkify.ALL : 0);
|
||||
|
||||
if (mediaThumbnailStub.resolved()) {
|
||||
mediaThumbnailStub.get().setFocusable(!shouldInterceptClicks(messageRecord) && batchSelected.isEmpty());
|
||||
@ -310,7 +316,7 @@ public class ConversationItem extends LinearLayout
|
||||
if (isCaptionlessMms(messageRecord)) {
|
||||
bodyText.setVisibility(View.GONE);
|
||||
} else {
|
||||
bodyText.setText(messageRecord.getDisplayBody());
|
||||
bodyText.setText(linkifyMessageBody(messageRecord.getDisplayBody(), batchSelected.isEmpty()));
|
||||
bodyText.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
@ -370,6 +376,20 @@ public class ConversationItem extends LinearLayout
|
||||
}
|
||||
}
|
||||
|
||||
private SpannableString linkifyMessageBody(SpannableString messageBody, boolean shouldLinkifyAllLinks) {
|
||||
boolean hasLinks = Linkify.addLinks(messageBody, shouldLinkifyAllLinks ? Linkify.ALL : 0);
|
||||
|
||||
if (hasLinks) {
|
||||
URLSpan[] urlSpans = messageBody.getSpans(0, messageBody.length(), URLSpan.class);
|
||||
for (URLSpan urlSpan : urlSpans) {
|
||||
int start = messageBody.getSpanStart(urlSpan);
|
||||
int end = messageBody.getSpanEnd(urlSpan);
|
||||
messageBody.setSpan(new LongClickCopySpan(urlSpan.getURL()), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
}
|
||||
return messageBody;
|
||||
}
|
||||
|
||||
private void setStatusIcons(MessageRecord messageRecord) {
|
||||
indicatorText.setVisibility(View.GONE);
|
||||
|
||||
@ -578,6 +598,9 @@ public class ConversationItem extends LinearLayout
|
||||
|
||||
@Override
|
||||
public boolean onLongClick(View v) {
|
||||
if (bodyText.hasSelection()) {
|
||||
return false;
|
||||
}
|
||||
performLongClick();
|
||||
return true;
|
||||
}
|
||||
|
73
src/org/thoughtcrime/securesms/util/LongClickCopySpan.java
Normal file
73
src/org/thoughtcrime/securesms/util/LongClickCopySpan.java
Normal file
@ -0,0 +1,73 @@
|
||||
package org.thoughtcrime.securesms.util;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.ClipData;
|
||||
import android.content.Context;
|
||||
import android.support.annotation.ColorInt;
|
||||
import android.text.TextPaint;
|
||||
import android.text.style.URLSpan;
|
||||
import android.view.View;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
|
||||
public class LongClickCopySpan extends URLSpan {
|
||||
private static final String PREFIX_MAILTO = "mailto:";
|
||||
private static final String PREFIX_TEL = "tel:";
|
||||
|
||||
private boolean isHighlighted;
|
||||
@ColorInt
|
||||
private int highlightColor;
|
||||
|
||||
public LongClickCopySpan(String url) {
|
||||
super(url);
|
||||
}
|
||||
|
||||
void onLongClick(View widget) {
|
||||
Context context = widget.getContext();
|
||||
String preparedUrl = prepareUrl(getURL());
|
||||
copyUrl(context, preparedUrl);
|
||||
Toast.makeText(context,
|
||||
context.getString(R.string.ConversationItem_copied_text, preparedUrl), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDrawState(TextPaint ds) {
|
||||
super.updateDrawState(ds);
|
||||
ds.bgColor = highlightColor;
|
||||
ds.setUnderlineText(!isHighlighted);
|
||||
}
|
||||
|
||||
void setHighlighted(boolean highlighted, @ColorInt int highlightColor) {
|
||||
this.isHighlighted = highlighted;
|
||||
this.highlightColor = highlightColor;
|
||||
}
|
||||
|
||||
private void copyUrl(Context context, String url) {
|
||||
int sdk = android.os.Build.VERSION.SDK_INT;
|
||||
if (sdk < android.os.Build.VERSION_CODES.HONEYCOMB) {
|
||||
@SuppressWarnings("deprecation") android.text.ClipboardManager clipboard =
|
||||
(android.text.ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
clipboard.setText(url);
|
||||
} else {
|
||||
copyUriSdk11(context, url);
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(android.os.Build.VERSION_CODES.HONEYCOMB)
|
||||
private void copyUriSdk11(Context context, String url) {
|
||||
android.content.ClipboardManager clipboard =
|
||||
(android.content.ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
ClipData clip = ClipData.newPlainText(context.getString(R.string.app_name), url);
|
||||
clipboard.setPrimaryClip(clip);
|
||||
}
|
||||
|
||||
private String prepareUrl(String url) {
|
||||
if (url.startsWith(PREFIX_MAILTO)) {
|
||||
return url.substring(PREFIX_MAILTO.length());
|
||||
} else if (url.startsWith(PREFIX_TEL)) {
|
||||
return url.substring(PREFIX_TEL.length());
|
||||
}
|
||||
return url;
|
||||
}
|
||||
}
|
103
src/org/thoughtcrime/securesms/util/LongClickMovementMethod.java
Normal file
103
src/org/thoughtcrime/securesms/util/LongClickMovementMethod.java
Normal file
@ -0,0 +1,103 @@
|
||||
package org.thoughtcrime.securesms.util;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.text.Layout;
|
||||
import android.text.Selection;
|
||||
import android.text.Spannable;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
import android.view.GestureDetector;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
|
||||
public class LongClickMovementMethod extends LinkMovementMethod {
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
private static LongClickMovementMethod sInstance;
|
||||
|
||||
private final GestureDetector gestureDetector;
|
||||
private View widget;
|
||||
private LongClickCopySpan currentSpan;
|
||||
|
||||
private LongClickMovementMethod(final Context context) {
|
||||
gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
|
||||
@Override
|
||||
public void onLongPress(MotionEvent e) {
|
||||
if (currentSpan != null && widget != null) {
|
||||
currentSpan.onLongClick(widget);
|
||||
widget = null;
|
||||
currentSpan = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSingleTapUp(MotionEvent e) {
|
||||
if (currentSpan != null && widget != null) {
|
||||
currentSpan.onClick(widget);
|
||||
widget = null;
|
||||
currentSpan = null;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
|
||||
int action = event.getAction();
|
||||
|
||||
if (action == MotionEvent.ACTION_UP ||
|
||||
action == MotionEvent.ACTION_DOWN) {
|
||||
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);
|
||||
|
||||
LongClickCopySpan longClickCopySpan[] = buffer.getSpans(off, off, LongClickCopySpan.class);
|
||||
if (longClickCopySpan.length != 0) {
|
||||
LongClickCopySpan aSingleSpan = longClickCopySpan[0];
|
||||
if (action == MotionEvent.ACTION_DOWN) {
|
||||
Selection.setSelection(buffer, buffer.getSpanStart(aSingleSpan),
|
||||
buffer.getSpanEnd(aSingleSpan));
|
||||
aSingleSpan.setHighlighted(true,
|
||||
ContextCompat.getColor(widget.getContext(), R.color.touch_highlight));
|
||||
} else {
|
||||
Selection.removeSelection(buffer);
|
||||
aSingleSpan.setHighlighted(false, Color.TRANSPARENT);
|
||||
}
|
||||
|
||||
this.currentSpan = aSingleSpan;
|
||||
this.widget = widget;
|
||||
return gestureDetector.onTouchEvent(event);
|
||||
}
|
||||
} else if (action == MotionEvent.ACTION_CANCEL) {
|
||||
// Remove Selections.
|
||||
LongClickCopySpan[] spans = buffer.getSpans(Selection.getSelectionStart(buffer),
|
||||
Selection.getSelectionEnd(buffer), LongClickCopySpan.class);
|
||||
for (LongClickCopySpan aSpan : spans) {
|
||||
aSpan.setHighlighted(false, Color.TRANSPARENT);
|
||||
}
|
||||
Selection.removeSelection(buffer);
|
||||
}
|
||||
return super.onTouchEvent(widget, buffer, event);
|
||||
}
|
||||
|
||||
public static LongClickMovementMethod getInstance(Context context) {
|
||||
if (sInstance == null) {
|
||||
sInstance = new LongClickMovementMethod(context.getApplicationContext());
|
||||
}
|
||||
return sInstance;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user