diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index 183af8ea3..b7c9c84d9 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -98,6 +98,7 @@ import eu.siacs.conversations.ui.widget.EditMessage; import eu.siacs.conversations.utils.GeoHelper; import eu.siacs.conversations.utils.MessageUtils; import eu.siacs.conversations.utils.NickValidityChecker; +import eu.siacs.conversations.utils.Patterns; import eu.siacs.conversations.utils.QuickLoader; import eu.siacs.conversations.utils.StylingHelper; import eu.siacs.conversations.utils.TimeframeUtils; @@ -1052,6 +1053,7 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke activity.getMenuInflater().inflate(R.menu.message_context, menu); menu.setHeaderTitle(R.string.message_options); MenuItem copyMessage = menu.findItem(R.id.copy_message); + MenuItem copyLink = menu.findItem(R.id.copy_link); MenuItem quoteMessage = menu.findItem(R.id.quote_message); MenuItem retryDecryption = menu.findItem(R.id.retry_decryption); MenuItem correctMessage = menu.findItem(R.id.correct_message); @@ -1065,6 +1067,13 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke if (!m.isFileOrImage() && !encrypted && !m.isGeoUri() && !m.treatAsDownloadable()) { copyMessage.setVisible(true); quoteMessage.setVisible(MessageUtils.prepareQuote(m).length() > 0); + String body = m.getMergedBody().toString(); + if (ShareUtil.containsXmppUri(body)) { + copyLink.setTitle(R.string.copy_jabber_id); + copyLink.setVisible(true); + } else if (Patterns.AUTOLINK_WEB_URL.matcher(body).find()) { + copyLink.setVisible(true); + } } if (m.getEncryption() == Message.ENCRYPTION_DECRYPTION_FAILED) { retryDecryption.setVisible(true); @@ -1122,6 +1131,9 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke case R.id.copy_message: ShareUtil.copyToClipboard(activity, selectedMessage); return true; + case R.id.copy_link: + ShareUtil.copyLinkToClipboard(activity, selectedMessage); + return true; case R.id.quote_message: quoteMessage(selectedMessage); return true; 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 1da81dc0d..c8c1705cb 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java @@ -92,11 +92,6 @@ public class MessageAdapter extends ArrayAdapter implements CopyTextVie private static final int RECEIVED = 1; private static final int STATUS = 2; private static final int DATE_SEPARATOR = 3; - private static final Pattern XMPP_PATTERN = Pattern - .compile("xmpp\\:(?:(?:[" - + Patterns.GOOD_IRI_CHAR - + "\\;\\/\\?\\@\\&\\=\\#\\~\\-\\.\\+\\!\\*\\'\\(\\)\\,\\_])" - + "|(?:\\%[a-fA-F0-9]{2}))+"); private List highlightedTerm = null; @@ -553,7 +548,7 @@ public class MessageAdapter extends ArrayAdapter implements CopyTextVie StylingHelper.highlight(activity, body, highlightedTerm, StylingHelper.isDarkText(viewHolder.messageBody)); } - Linkify.addLinks(body, XMPP_PATTERN, "xmpp", XMPPURI_MATCH_FILTER, null); + Linkify.addLinks(body, Patterns.XMPP_PATTERN, "xmpp", XMPPURI_MATCH_FILTER, null); Linkify.addLinks(body, Patterns.AUTOLINK_WEB_URL, "http", WEBURL_MATCH_FILTER, WEBURL_TRANSFORM_FILTER); Linkify.addLinks(body, GeoHelper.GEO_URI, "geo"); FixedURLSpan.fix(body); diff --git a/src/main/java/eu/siacs/conversations/ui/util/ShareUtil.java b/src/main/java/eu/siacs/conversations/ui/util/ShareUtil.java index 1384aba62..a48e8d6a2 100644 --- a/src/main/java/eu/siacs/conversations/ui/util/ShareUtil.java +++ b/src/main/java/eu/siacs/conversations/ui/util/ShareUtil.java @@ -33,13 +33,22 @@ import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; import android.support.v4.content.ContextCompat; +import android.util.Log; import android.widget.Toast; +import java.net.URL; +import java.util.regex.Matcher; + +import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.entities.DownloadableFile; import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.persistance.FileBackend; +import eu.siacs.conversations.ui.ConversationsActivity; import eu.siacs.conversations.ui.XmppActivity; +import eu.siacs.conversations.utils.Patterns; +import eu.siacs.conversations.utils.XmppUri; +import rocks.xmpp.addr.Jid; public class ShareUtil { @@ -98,4 +107,40 @@ public class ShareUtil { Toast.makeText(activity, R.string.url_copied_to_clipboard, Toast.LENGTH_SHORT).show(); } } + + public static void copyLinkToClipboard(XmppActivity activity, Message message) { + String body = message.getMergedBody().toString(); + Matcher xmppPatternMatcher = Patterns.XMPP_PATTERN.matcher(body); + if (xmppPatternMatcher.find()) { + try { + Jid jid = new XmppUri(body.substring(xmppPatternMatcher.start(), xmppPatternMatcher.end())).getJid(); + if (activity.copyTextToClipboard(jid.asBareJid().toString(), R.string.account_settings_jabber_id)) { + Toast.makeText(activity,R.string.jabber_id_copied_to_clipboard, Toast.LENGTH_SHORT).show(); + } + return; + } catch (Exception e) { + e.printStackTrace(); + return; + } + } + Matcher webUrlPatternMatcher = Patterns.AUTOLINK_WEB_URL.matcher(body); + if (webUrlPatternMatcher.find()) { + String url = body.substring(webUrlPatternMatcher.start(),webUrlPatternMatcher.end()); + if (activity.copyTextToClipboard(url,R.string.web_address)) { + Toast.makeText(activity,R.string.url_copied_to_clipboard, Toast.LENGTH_SHORT).show(); + } + } + } + + public static boolean containsXmppUri(String body) { + Matcher xmppPatternMatcher = Patterns.XMPP_PATTERN.matcher(body); + if (xmppPatternMatcher.find()) { + try { + return new XmppUri(body.substring(xmppPatternMatcher.start(), xmppPatternMatcher.end())).isJidValid(); + } catch (Exception e) { + return false; + } + } + return false; + } } diff --git a/src/main/java/eu/siacs/conversations/utils/Patterns.java b/src/main/java/eu/siacs/conversations/utils/Patterns.java index a5a83bdea..6e9e85cd7 100644 --- a/src/main/java/eu/siacs/conversations/utils/Patterns.java +++ b/src/main/java/eu/siacs/conversations/utils/Patterns.java @@ -26,6 +26,13 @@ import java.util.regex.Pattern; * Commonly used regular expression patterns. */ public class Patterns { + + public static final Pattern XMPP_PATTERN = Pattern + .compile("xmpp\\:(?:(?:[" + + Patterns.GOOD_IRI_CHAR + + "\\;\\/\\?\\@\\&\\=\\#\\~\\-\\.\\+\\!\\*\\'\\(\\)\\,\\_])" + + "|(?:\\%[a-fA-F0-9]{2}))+"); + /** * Regular expression to match all IANA top-level domains. * List accurate as of 2011/07/18. List taken from: diff --git a/src/main/res/menu/message_context.xml b/src/main/res/menu/message_context.xml index fe65ea099..97f31f625 100644 --- a/src/main/res/menu/message_context.xml +++ b/src/main/res/menu/message_context.xml @@ -10,6 +10,11 @@ android:id="@+id/copy_message" android:title="@string/copy_to_clipboard" android:visible="false"/> + + Send again File URL Copied URL to clipboard + Copied Jabberd ID to clipboard + web address Scan 2D Barcode Show 2D Barcode Show block list @@ -708,4 +710,6 @@ View conversation Share Location Plugin Use the Share Location Plugin instead of the build in map + Copy web address + Copy Jabber ID