From 70477c9fc9c6c6df45d2b921d920ec4070535bb4 Mon Sep 17 00:00:00 2001 From: Christian Schneppe Date: Fri, 29 Jun 2018 22:34:45 +0200 Subject: linkify subject + open xmpp directly w/o going through start conv activity --- .../messenger/ui/ConferenceDetailsActivity.java | 7 +- .../pixart/messenger/ui/ConversationsActivity.java | 13 +++ .../messenger/ui/adapter/MessageAdapter.java | 80 ++-------------- .../de/pixart/messenger/ui/text/FixedURLSpan.java | 8 ++ .../de/pixart/messenger/ui/util/MyLinkify.java | 106 +++++++++++++++++++++ 5 files changed, 142 insertions(+), 72 deletions(-) create mode 100644 src/main/java/de/pixart/messenger/ui/util/MyLinkify.java (limited to 'src/main/java/de/pixart/messenger/ui') diff --git a/src/main/java/de/pixart/messenger/ui/ConferenceDetailsActivity.java b/src/main/java/de/pixart/messenger/ui/ConferenceDetailsActivity.java index 2ff6facf9..5ba1aad49 100644 --- a/src/main/java/de/pixart/messenger/ui/ConferenceDetailsActivity.java +++ b/src/main/java/de/pixart/messenger/ui/ConferenceDetailsActivity.java @@ -15,6 +15,7 @@ import android.os.Bundle; import android.support.v7.app.ActionBar; import android.support.v7.app.AlertDialog; import android.support.v7.widget.Toolbar; +import android.text.SpannableStringBuilder; import android.util.Log; import android.view.ContextMenu; import android.view.LayoutInflater; @@ -48,6 +49,7 @@ import de.pixart.messenger.entities.MucOptions.User; import de.pixart.messenger.services.XmppConnectionService; import de.pixart.messenger.services.XmppConnectionService.OnConversationUpdate; import de.pixart.messenger.services.XmppConnectionService.OnMucRosterUpdate; +import de.pixart.messenger.ui.util.MyLinkify; import de.pixart.messenger.utils.MenuDoubleTabUtil; import de.pixart.messenger.utils.TimeframeUtils; import de.pixart.messenger.utils.UIHelper; @@ -612,7 +614,10 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers this.binding.mucTitle.setVisibility(View.GONE); } if (printableValue(subject)) { - this.binding.mucSubject.setText(mucOptions.getSubject()); + SpannableStringBuilder spannable = new SpannableStringBuilder(subject); + MyLinkify.addLinks(spannable, false); + this.binding.mucSubject.setText(spannable); + this.binding.mucSubject.setAutoLinkMask(0); this.binding.mucSubject.setVisibility(View.VISIBLE); } else { this.binding.mucSubject.setVisibility(View.GONE); diff --git a/src/main/java/de/pixart/messenger/ui/ConversationsActivity.java b/src/main/java/de/pixart/messenger/ui/ConversationsActivity.java index 590b93d6c..3882fd732 100644 --- a/src/main/java/de/pixart/messenger/ui/ConversationsActivity.java +++ b/src/main/java/de/pixart/messenger/ui/ConversationsActivity.java @@ -88,6 +88,7 @@ import de.pixart.messenger.ui.util.PendingItem; import de.pixart.messenger.utils.ExceptionHelper; import de.pixart.messenger.utils.MenuDoubleTabUtil; import de.pixart.messenger.utils.UIHelper; +import de.pixart.messenger.utils.XmppUri; import de.pixart.messenger.xmpp.OnUpdateBlocklist; import de.pixart.messenger.xmpp.chatstate.ChatState; @@ -523,6 +524,18 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio } } + public boolean onXmppUriClicked(Uri uri) { + XmppUri xmppUri = new XmppUri(uri); + if (xmppUri.isJidValid() && !xmppUri.hasFingerprints()) { + final Conversation conversation = xmppConnectionService.findUniqueConversationByJid(xmppUri); + if (conversation != null) { + openConversation(conversation, null); + return true; + } + } + return false; + } + @Override public boolean onOptionsItemSelected(MenuItem item) { if (MenuDoubleTabUtil.shouldIgnoreTap()) { diff --git a/src/main/java/de/pixart/messenger/ui/adapter/MessageAdapter.java b/src/main/java/de/pixart/messenger/ui/adapter/MessageAdapter.java index 5d38094bf..519b01c1a 100644 --- a/src/main/java/de/pixart/messenger/ui/adapter/MessageAdapter.java +++ b/src/main/java/de/pixart/messenger/ui/adapter/MessageAdapter.java @@ -15,7 +15,6 @@ import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.AsyncTask; -import android.os.Build; import android.preference.PreferenceManager; import android.support.annotation.ColorInt; import android.support.v4.app.ActivityCompat; @@ -28,7 +27,6 @@ import android.text.format.DateUtils; import android.text.style.ForegroundColorSpan; import android.text.style.RelativeSizeSpan; import android.text.style.StyleSpan; -import android.text.util.Linkify; import android.util.Base64; import android.util.DisplayMetrics; import android.util.Log; @@ -53,7 +51,6 @@ import java.io.UnsupportedEncodingException; import java.lang.ref.WeakReference; import java.net.URL; import java.util.List; -import java.util.Locale; import java.util.concurrent.RejectedExecutionException; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -78,8 +75,8 @@ import de.pixart.messenger.ui.ConversationsActivity; import de.pixart.messenger.ui.ShowFullscreenMessageActivity; import de.pixart.messenger.ui.XmppActivity; import de.pixart.messenger.ui.text.DividerSpan; -import de.pixart.messenger.ui.text.FixedURLSpan; import de.pixart.messenger.ui.text.QuoteSpan; +import de.pixart.messenger.ui.util.MyLinkify; import de.pixart.messenger.ui.widget.ClickableMovementMethod; import de.pixart.messenger.ui.widget.CopyTextView; import de.pixart.messenger.ui.widget.ListSelectionManager; @@ -87,10 +84,8 @@ import de.pixart.messenger.utils.CryptoHelper; import de.pixart.messenger.utils.EmojiWrapper; import de.pixart.messenger.utils.Emoticons; import de.pixart.messenger.utils.GeoHelper; -import de.pixart.messenger.utils.Patterns; import de.pixart.messenger.utils.StylingHelper; import de.pixart.messenger.utils.UIHelper; -import de.pixart.messenger.utils.XmppUri; import de.pixart.messenger.xmpp.mam.MamReference; public class MessageAdapter extends ArrayAdapter implements CopyTextView.CopyHandler { @@ -105,60 +100,6 @@ public class MessageAdapter extends ArrayAdapter implements CopyTextVie boolean isResendable = false; - private static final Linkify.TransformFilter WEBURL_TRANSFORM_FILTER = (matcher, url) -> { - if (url == null) { - return null; - } - final String lcUrl = url.toLowerCase(Locale.US); - if (lcUrl.startsWith("http://") || lcUrl.startsWith("https://")) { - return removeTrailingBracket(url); - } else { - return "http://" + removeTrailingBracket(url); - } - }; - - private static String removeTrailingBracket(final String url) { - int numOpenBrackets = 0; - for (char c : url.toCharArray()) { - if (c == '(') { - ++numOpenBrackets; - } else if (c == ')') { - --numOpenBrackets; - } - } - if (numOpenBrackets != 0 && url.charAt(url.length() - 1) == ')') { - return url.substring(0, url.length() - 1); - } else { - return url; - } - } - - private static final Linkify.MatchFilter WEBURL_MATCH_FILTER = (cs, start, end) -> { - if (start > 0) { - if (cs.charAt(start - 1) == '@' || cs.charAt(start - 1) == '.' - || cs.subSequence(Math.max(0, start - 3), start).equals("://")) { - return false; - } - } - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - if (end < cs.length()) { - // Reject strings that were probably matched only because they contain a dot followed by - // by some known TLD (see also comment for WORD_BOUNDARY in Patterns.java) - if (Character.isAlphabetic(cs.charAt(end - 1)) && Character.isAlphabetic(cs.charAt(end))) { - return false; - } - } - } - - return true; - }; - - private static final Linkify.MatchFilter XMPPURI_MATCH_FILTER = (s, start, end) -> { - XmppUri uri = new XmppUri(s.subSequence(start, end).toString()); - return uri.isJidValid(); - }; - private final XmppActivity activity; private final ListSelectionManager listSelectionManager = new ListSelectionManager(); private final AudioPlayer audioPlayer; @@ -622,10 +563,7 @@ public class MessageAdapter extends ArrayAdapter implements CopyTextVie if (highlightedTerm != null) { StylingHelper.highlight(activity, body, highlightedTerm, StylingHelper.isDarkText(viewHolder.messageBody)); } - 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); + MyLinkify.addLinks(body,true); viewHolder.messageBody.setAutoLinkMask(0); viewHolder.messageBody.setText(EmojiWrapper.transform(body)); viewHolder.messageBody.setTextIsSelectable(true); @@ -862,14 +800,14 @@ public class MessageAdapter extends ArrayAdapter implements CopyTextVie break; default: throw new AssertionError("Unknown view type"); - } + } if (viewHolder.messageBody != null) { listSelectionManager.onCreate(viewHolder.messageBody, new MessageBodyActionModeCallback(viewHolder.messageBody)); viewHolder.messageBody.setCopyHandler(this); } view.setTag(viewHolder); } else { - viewHolder = (ViewHolder) view.getTag(); + viewHolder = (ViewHolder) view.getTag(); if (viewHolder == null) { return view; } @@ -922,12 +860,12 @@ public class MessageAdapter extends ArrayAdapter implements CopyTextVie resetClickListener(viewHolder.message_box, viewHolder.messageBody); viewHolder.contact_picture.setOnClickListener(v -> { - if (MessageAdapter.this.mOnContactPictureClickedListener != null) { - MessageAdapter.this.mOnContactPictureClickedListener - .onContactPictureClicked(message); - } + if (MessageAdapter.this.mOnContactPictureClickedListener != null) { + MessageAdapter.this.mOnContactPictureClickedListener + .onContactPictureClicked(message); + } - }); + }); viewHolder.contact_picture .setOnLongClickListener(v -> { if (MessageAdapter.this.mOnContactPictureLongClickedListener != null) { diff --git a/src/main/java/de/pixart/messenger/ui/text/FixedURLSpan.java b/src/main/java/de/pixart/messenger/ui/text/FixedURLSpan.java index 87299b8e1..353887054 100644 --- a/src/main/java/de/pixart/messenger/ui/text/FixedURLSpan.java +++ b/src/main/java/de/pixart/messenger/ui/text/FixedURLSpan.java @@ -42,6 +42,7 @@ import android.view.View; import android.widget.Toast; import de.pixart.messenger.R; +import de.pixart.messenger.ui.ConversationsActivity; @SuppressLint("ParcelCreator") public class FixedURLSpan extends URLSpan { @@ -63,6 +64,12 @@ public class FixedURLSpan extends URLSpan { public void onClick(View widget) { final Uri uri = Uri.parse(getURL()); final Context context = widget.getContext(); + if (uri.getScheme().equals("xmpp") && context instanceof ConversationsActivity) { + if (((ConversationsActivity) context).onXmppUriClicked(uri)) { + widget.playSoundEffect(0); + return; + } + } final Intent intent = new Intent(Intent.ACTION_VIEW, uri); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { intent.setFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT); @@ -70,6 +77,7 @@ public class FixedURLSpan extends URLSpan { //intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName()); try { context.startActivity(intent); + widget.playSoundEffect(0); } catch (ActivityNotFoundException e) { Toast.makeText(context, R.string.no_application_found_to_open_link, Toast.LENGTH_SHORT).show(); } diff --git a/src/main/java/de/pixart/messenger/ui/util/MyLinkify.java b/src/main/java/de/pixart/messenger/ui/util/MyLinkify.java new file mode 100644 index 000000000..2817c55c7 --- /dev/null +++ b/src/main/java/de/pixart/messenger/ui/util/MyLinkify.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2018, Daniel Gultsch All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package de.pixart.messenger.ui.util; + +import android.os.Build; +import android.text.Editable; +import android.text.util.Linkify; + +import java.util.Locale; + +import de.pixart.messenger.ui.text.FixedURLSpan; +import de.pixart.messenger.utils.GeoHelper; +import de.pixart.messenger.utils.Patterns; +import de.pixart.messenger.utils.XmppUri; + +public class MyLinkify { + + private static final Linkify.TransformFilter WEBURL_TRANSFORM_FILTER = (matcher, url) -> { + if (url == null) { + return null; + } + final String lcUrl = url.toLowerCase(Locale.US); + if (lcUrl.startsWith("http://") || lcUrl.startsWith("https://")) { + return removeTrailingBracket(url); + } else { + return "http://" + removeTrailingBracket(url); + } + }; + + private static String removeTrailingBracket(final String url) { + int numOpenBrackets = 0; + for (char c : url.toCharArray()) { + if (c == '(') { + ++numOpenBrackets; + } else if (c == ')') { + --numOpenBrackets; + } + } + if (numOpenBrackets != 0 && url.charAt(url.length() - 1) == ')') { + return url.substring(0, url.length() - 1); + } else { + return url; + } + } + + private static final Linkify.MatchFilter WEBURL_MATCH_FILTER = (cs, start, end) -> { + if (start > 0) { + if (cs.charAt(start - 1) == '@' || cs.charAt(start - 1) == '.' + || cs.subSequence(Math.max(0, start - 3), start).equals("://")) { + return false; + } + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + if (end < cs.length()) { + // Reject strings that were probably matched only because they contain a dot followed by + // by some known TLD (see also comment for WORD_BOUNDARY in Patterns.java) + if (Character.isAlphabetic(cs.charAt(end - 1)) && Character.isAlphabetic(cs.charAt(end))) { + return false; + } + } + } + + return true; + }; + + private static final Linkify.MatchFilter XMPPURI_MATCH_FILTER = (s, start, end) -> { + XmppUri uri = new XmppUri(s.subSequence(start, end).toString()); + return uri.isJidValid(); + }; + + public static void addLinks(Editable body, boolean includeGeo) { + 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); + if (includeGeo) { + Linkify.addLinks(body, GeoHelper.GEO_URI, "geo"); + } + FixedURLSpan.fix(body); + } +} \ No newline at end of file -- cgit v1.2.3