diff options
Diffstat (limited to 'app/src/main/java/app/fedilab/android/helper/SpannableHelper.java')
-rw-r--r-- | app/src/main/java/app/fedilab/android/helper/SpannableHelper.java | 1060 |
1 files changed, 328 insertions, 732 deletions
diff --git a/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java b/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java index 26cb125d9..f53c1172a 100644 --- a/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java +++ b/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java @@ -41,6 +41,7 @@ import android.text.style.URLSpan; import android.util.Patterns; import android.view.LayoutInflater; import android.view.View; +import android.webkit.URLUtil; import android.widget.Toast; import androidx.annotation.NonNull; @@ -52,12 +53,6 @@ import androidx.lifecycle.ViewModelStoreOwner; import androidx.preference.PreferenceManager; import com.bumptech.glide.Glide; -import com.google.android.material.dialog.MaterialAlertDialogBuilder; - -import org.jsoup.Jsoup; -import org.jsoup.nodes.Document; -import org.jsoup.nodes.Element; -import org.jsoup.select.Elements; import java.io.IOException; import java.lang.ref.WeakReference; @@ -94,20 +89,15 @@ import es.dmoral.toasty.Toasty; public class SpannableHelper { public static final String CLICKABLE_SPAN = "CLICKABLE_SPAN"; + private static int linkColor; public static Spannable convert(Context context, String text, - Status status, Account account, Announcement announcement, - boolean convertHtml, boolean forceMentions, WeakReference<View> viewWeakReference) { - return convert(context, text, status, account, announcement, convertHtml, forceMentions, viewWeakReference, null); + Status status, Account account, Announcement announcement, WeakReference<View> viewWeakReference) { + return convert(context, text, status, account, announcement, viewWeakReference, null); } - - private static int linkColor; - public static Spannable convert(Context context, String text, Status status, Account account, Announcement announcement, - boolean convertHtml, - boolean forceMentions, WeakReference<View> viewWeakReference, Status.Callback callback) { SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(context); @@ -131,24 +121,126 @@ public class SpannableHelper { if (linkColor == 0) { linkColor = -1; } - SpannableString initialContent; - if (text == null) { - return null; + List<Mention> mentions = new ArrayList<>(); + if (status != null && status.mentions != null) { + mentions.addAll(status.mentions); } - Document htmlContent = Jsoup.parse(text); - Elements mentionElements = htmlContent.select("a.mention"); - //We keep a reference to mentions - HashMap<String, String> mentionsMap = new HashMap<>(); - if (mentionElements.size() > 0) { - for (int i = 0; i < mentionElements.size(); i++) { - Element mentionElement = mentionElements.get(i); - String href = mentionElement.attr("href"); - String mention = mentionElement.text(); - mentionsMap.put(mention, href); + text = text.replaceAll("((<\\s?p\\s?>|<\\s?br\\s?/?>)>(((?!(<\\s?br\\s?/?>|<\\s?/s?p\\s?>)).)*))", "$2<blockquote>$3</blockquote>"); + text = text.trim().replaceAll("\\s{3}", " "); + text = text.trim().replaceAll("\\s{2}", " "); + SpannableString initialContent; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) + initialContent = new SpannableString(Html.fromHtml(text, Html.FROM_HTML_MODE_LEGACY)); + else + initialContent = new SpannableString(Html.fromHtml(text)); + + //Get all links + SpannableStringBuilder content = new SpannableStringBuilder(initialContent); + URLSpan[] urls = content.getSpans(0, (content.length() - 1), URLSpan.class); + //Loop through links + for (URLSpan span : urls) { + String url = span.getURL(); + int start = content.getSpanStart(span); + int end = content.getSpanEnd(span); + if (start < 0 || end > content.length()) { + continue; } + content.removeSpan(span); + //Get the matching word associated to the URL + String word = content.subSequence(start, end).toString(); + if (word.startsWith("@") || word.startsWith("#")) { + content.setSpan(new LongClickableSpan() { + @Override + public void onLongClick(View textView) { + textView.setTag(CLICKABLE_SPAN); + if (word.startsWith("#") && BaseMainActivity.filterFetched && MainActivity.mainFilters != null) { + String tag = word.trim(); + if (!tag.startsWith("#")) { + tag = "#" + tag; + } + Filter fedilabFilter = null; + for (Filter filter : MainActivity.mainFilters) { + if (filter.title.equals(Helper.FEDILAB_MUTED_HASHTAGS)) { + fedilabFilter = filter; + break; + } + } + //Filter for Fedilab doesn't exist we have to create it + if (fedilabFilter == null) { + Filter.FilterParams filterParams = new Filter.FilterParams(); + filterParams.title = Helper.FEDILAB_MUTED_HASHTAGS; + filterParams.filter_action = "hide"; + filterParams.context = new ArrayList<>(); + filterParams.context.add("home"); + filterParams.context.add("public"); + filterParams.context.add("thread"); + filterParams.context.add("account"); + String finalTag = tag; + FiltersVM filtersVM = new ViewModelProvider((ViewModelStoreOwner) context).get(FiltersVM.class); + filtersVM.addFilter(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, filterParams) + .observe((LifecycleOwner) context, filter -> { + if (filter != null) { + MainActivity.mainFilters.add(filter); + addTagToFilter(context, finalTag, status, filter); + } + }); + } else { + addTagToFilter(context, tag, status, fedilabFilter); + } + } + } + + @Override + public void onClick(@NonNull View textView) { + textView.setTag(CLICKABLE_SPAN); + Intent intent; + Bundle b; + if (word.startsWith("#")) { + intent = new Intent(context, HashTagActivity.class); + b = new Bundle(); + b.putString(Helper.ARG_SEARCH_KEYWORD, word.trim()); + intent.putExtras(b); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(intent); + } else if (word.startsWith("@")) { + intent = new Intent(context, ProfileActivity.class); + b = new Bundle(); + Mention targetedMention = null; + + for (Mention mention : mentions) { + if (word.compareToIgnoreCase("@" + mention.username) == 0) { + targetedMention = mention; + break; + } + } + if (targetedMention != null) { + b.putString(Helper.ARG_USER_ID, targetedMention.id); + } else { + b.putString(Helper.ARG_MENTION, word); + } + intent.putExtras(b); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(intent); + } + } + + @Override + public void updateDrawState(@NonNull TextPaint ds) { + super.updateDrawState(ds); + ds.setUnderlineText(false); + if (linkColor != -1) { + ds.setColor(linkColor); + } + } + + }, start, end, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + } else { + makeLinks(context, content, url, start, end); + } + replaceQuoteSpans(context, content); + emails(context, content); } - text = text.replaceAll("((<\\s?p\\s?>|<\\s?br\\s?\\/?>)>(((?!([<])).)*))", "$2<blockquote>$3</blockquote>"); Pattern imgPattern = Pattern.compile("<img [^>]*src=\"([^\"]+)\"[^>]*>"); Matcher matcherImg = imgPattern.matcher(text); HashMap<String, String> imagesToReplace = new LinkedHashMap<>(); @@ -160,57 +252,15 @@ public class SpannableHelper { text = text.replaceAll(Pattern.quote(matcherImg.group()), replacement); } - SpannableStringBuilder content; View view = viewWeakReference.get(); - List<Mention> mentionList = null; List<Emoji> emojiList = null; if (status != null) { - mentionList = status.mentions; emojiList = status.emojis; } else if (account != null) { emojiList = account.emojis; } else if (announcement != null) { emojiList = announcement.emojis; } - //UrlDetails will contain links having a text different from the url - HashMap<String, String> urlDetails = new HashMap<>(); - if (convertHtml) { - Matcher matcherALink = Helper.aLink.matcher(text); - - //We stock details - while (matcherALink.find()) { - String urlText = matcherALink.group(3); - String url = matcherALink.group(2); - if (urlText != null && urlText.startsWith(">")) { - urlText = urlText.substring(1); - } - if (url != null && urlText != null && !url.equalsIgnoreCase(urlText) && !urlText.contains("<span")) { - urlDetails.put(url, urlText); - } - } - text = text.trim().replaceAll("\\s{3}", " "); - text = text.trim().replaceAll("\\s{2}", " "); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) - initialContent = new SpannableString(Html.fromHtml(text, Html.FROM_HTML_MODE_LEGACY)); - else - initialContent = new SpannableString(Html.fromHtml(text)); - - content = new SpannableStringBuilder(initialContent); - URLSpan[] urls = content.getSpans(0, (content.length() - 1), URLSpan.class); - for (URLSpan span : urls) { - content.removeSpan(span); - } - //Make tags, mentions, groups - interaction(context, content, status, mentionList, forceMentions, mentionsMap); - //Make all links - linkify(context, content, urlDetails); - linkifyURL(context, content, urlDetails); - emails(context, content); - gemini(context, content); - replaceQuoteSpans(context, content); - } else { - content = new SpannableStringBuilder(text); - } boolean animate = !sharedpreferences.getBoolean(context.getString(R.string.SET_DISABLE_ANIMATED_EMOJI), false); CustomEmoji customEmoji = new CustomEmoji(new WeakReference<>(view)); content = customEmoji.makeEmoji(content, emojiList, animate, callback); @@ -234,542 +284,251 @@ public class SpannableHelper { return trimSpannable(new SpannableStringBuilder(content)); } - private static void linkify(Context context, SpannableStringBuilder content, HashMap<String, String> urlDetails) { - //--- URLs ---- - Matcher matcherLink = Patterns.WEB_URL.matcher(content); - - int offSetTruncate = 0; - - - while (matcherLink.find()) { - int matchStart = matcherLink.start() - offSetTruncate; - int matchEnd = matchStart + matcherLink.group().length(); - if (matchEnd > content.toString().length()) { - matchEnd = content.toString().length(); - } - - if (content.toString().length() < matchEnd || matchStart < 0 || matchStart > matchEnd) { - continue; - } - - - final String url = content.toString().substring(matchStart, matchEnd); - if (urlDetails.containsKey(url)) { - continue; - } - - ClickableSpan[] clickableSpans = content.getSpans(matchStart, matchEnd, ClickableSpan.class); - if (clickableSpans != null) { - for (ClickableSpan clickableSpan : clickableSpans) { - content.removeSpan(clickableSpan); - } - } - content.removeSpan(clickableSpans); - String newURL = Helper.transformURL(context, url); - //If URL has been transformed - if (newURL.compareTo(url) != 0) { - content.replace(matchStart, matchEnd, newURL); - offSetTruncate -= (newURL.length() - url.length()); - matchEnd = matchStart + newURL.length(); - } - //Truncate URL if needed - //TODO: add an option to disable truncated URLs - String urlText = newURL; - if (newURL.length() > 30 && !urlDetails.containsKey(urlText) && !urlText.startsWith("gemini")) { - urlText = urlText.substring(0, 30); - urlText += "…"; - content.replace(matchStart, matchEnd, urlText); - matchEnd = matchStart + 31; - offSetTruncate += (newURL.length() - urlText.length()); - } + private static void makeLinks(Context context, SpannableStringBuilder content, String url, int start, int end) { + String newUrl = url; + boolean validUrl = URLUtil.isValidUrl(url) && url.length() == (end - start); + if (validUrl) { + newUrl = Helper.transformURL(context, url); + } - if (matchEnd <= content.length() && matchEnd >= matchStart) { - content.setSpan(new LongClickableSpan() { - @Override - public void onLongClick(View view) { - Context mContext = view.getContext(); - MaterialAlertDialogBuilder materialAlertDialogBuilder = new MaterialAlertDialogBuilder(mContext); - PopupLinksBinding popupLinksBinding = PopupLinksBinding.inflate(LayoutInflater.from(context)); - materialAlertDialogBuilder.setView(popupLinksBinding.getRoot()); - AlertDialog alertDialog = materialAlertDialogBuilder.create(); - alertDialog.show(); - String finalURl = newURL; - String uniqueUrl = newURL.endsWith("…") ? newURL : newURL + "…"; - if (urlDetails.containsValue(uniqueUrl)) { - finalURl = Helper.getKeyByValue(urlDetails, uniqueUrl); - } - if (finalURl == null) { - return; - } - if (finalURl.startsWith("http://")) { - finalURl = finalURl.replace("http://", "https://"); - } - String finalURl1 = finalURl; - popupLinksBinding.displayFullLink.setOnClickListener(v -> { - AlertDialog.Builder builder = new AlertDialog.Builder(mContext); - builder.setMessage(finalURl1); - builder.setTitle(context.getString(R.string.display_full_link)); - builder.setPositiveButton(R.string.close, (dialog, which) -> dialog.dismiss()) - .show(); - alertDialog.dismiss(); - }); - popupLinksBinding.shareLink.setOnClickListener(v -> { - Intent sendIntent = new Intent(Intent.ACTION_SEND); - sendIntent.putExtra(Intent.EXTRA_SUBJECT, context.getString(R.string.shared_via)); - sendIntent.putExtra(Intent.EXTRA_TEXT, finalURl1); - sendIntent.setType("text/plain"); - sendIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - Intent intentChooser = Intent.createChooser(sendIntent, context.getString(R.string.share_with)); - intentChooser.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - context.startActivity(intentChooser); - alertDialog.dismiss(); - }); + //If URL has been transformed + if (validUrl && newUrl.compareTo(url) != 0) { + content.replace(start, end, newUrl); + end = start + newUrl.length(); + url = newUrl; + } + if (url.length() > 30 && (validUrl || url.startsWith("gimini://"))) { + newUrl = url.substring(0, 30); + newUrl += "…"; + content.replace(start, end, newUrl); + } + int matchEnd = validUrl ? start + newUrl.length() : end; - popupLinksBinding.openOtherApp.setOnClickListener(v -> { - Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setData(Uri.parse(finalURl1)); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - try { - context.startActivity(intent); - } catch (Exception e) { - Toasty.error(context, context.getString(R.string.toast_error), Toast.LENGTH_LONG).show(); - } - alertDialog.dismiss(); - }); + String finalUrl = url; + if (content.length() < matchEnd) { + matchEnd = content.length(); + } + content.setSpan(new LongClickableSpan() { + @Override + public void onLongClick(View view) { + Context mContext = view.getContext(); + AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(mContext); + PopupLinksBinding popupLinksBinding = PopupLinksBinding.inflate(LayoutInflater.from(context)); + dialogBuilder.setView(popupLinksBinding.getRoot()); + AlertDialog alertDialog = dialogBuilder.create(); + alertDialog.show(); + popupLinksBinding.displayFullLink.setOnClickListener(v -> { + AlertDialog.Builder builder = new AlertDialog.Builder(mContext); + builder.setMessage(finalUrl); + builder.setTitle(context.getString(R.string.display_full_link)); + builder.setPositiveButton(R.string.close, (dialog, which) -> dialog.dismiss()) + .show(); + alertDialog.dismiss(); + }); + popupLinksBinding.shareLink.setOnClickListener(v -> { + Intent sendIntent = new Intent(Intent.ACTION_SEND); + sendIntent.putExtra(Intent.EXTRA_SUBJECT, context.getString(R.string.shared_via)); + sendIntent.putExtra(Intent.EXTRA_TEXT, finalUrl); + sendIntent.setType("text/plain"); + sendIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + Intent intentChooser = Intent.createChooser(sendIntent, context.getString(R.string.share_with)); + intentChooser.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(intentChooser); + alertDialog.dismiss(); + }); + + popupLinksBinding.openOtherApp.setOnClickListener(v -> { + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setData(Uri.parse(finalUrl)); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + try { + context.startActivity(intent); + } catch (Exception e) { + Toasty.error(context, context.getString(R.string.toast_error), Toast.LENGTH_LONG).show(); + } + alertDialog.dismiss(); + }); + + popupLinksBinding.copyLink.setOnClickListener(v -> { + ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); + ClipData clip = ClipData.newPlainText(Helper.CLIP_BOARD, finalUrl); + if (clipboard != null) { + clipboard.setPrimaryClip(clip); + Toasty.info(context, context.getString(R.string.clipboard_url), Toast.LENGTH_LONG).show(); + } + alertDialog.dismiss(); + }); - popupLinksBinding.copyLink.setOnClickListener(v -> { - ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); - ClipData clip = ClipData.newPlainText(Helper.CLIP_BOARD, finalURl1); - if (clipboard != null) { - clipboard.setPrimaryClip(clip); - Toasty.info(context, context.getString(R.string.clipboard_url), Toast.LENGTH_LONG).show(); - } - alertDialog.dismiss(); - }); + popupLinksBinding.checkRedirect.setOnClickListener(v -> { + try { - popupLinksBinding.checkRedirect.setOnClickListener(v -> { + URL finalUrlCheck = new URL(finalUrl); + new Thread(() -> { try { - - URL finalUrlCheck = new URL(finalURl1); - new Thread(() -> { - try { - String redirect = null; - HttpsURLConnection httpsURLConnection = (HttpsURLConnection) finalUrlCheck.openConnection(); - httpsURLConnection.setConnectTimeout(10 * 1000); - httpsURLConnection.setRequestProperty("http.keepAlive", "false"); - // httpsURLConnection.setRequestProperty("User-Agent", USER_AGENT); - httpsURLConnection.setRequestMethod("HEAD"); - httpsURLConnection.setInstanceFollowRedirects(false); - if (httpsURLConnection.getResponseCode() == 301 || httpsURLConnection.getResponseCode() == 302) { - Map<String, List<String>> map = httpsURLConnection.getHeaderFields(); - for (Map.Entry<String, List<String>> entry : map.entrySet()) { - if (entry.toString().toLowerCase().startsWith("location")) { - Matcher matcher = Patterns.WEB_URL.matcher(entry.toString()); - if (matcher.find()) { - redirect = matcher.group(1); - } - } + String redirect = null; + HttpsURLConnection httpsURLConnection = (HttpsURLConnection) finalUrlCheck.openConnection(); + httpsURLConnection.setConnectTimeout(10 * 1000); + httpsURLConnection.setRequestProperty("http.keepAlive", "false"); + //httpsURLConnection.setRequestProperty("User-Agent", USER_AGENT); + httpsURLConnection.setRequestMethod("HEAD"); + httpsURLConnection.setInstanceFollowRedirects(false); + if (httpsURLConnection.getResponseCode() == 301 || httpsURLConnection.getResponseCode() == 302) { + Map<String, List<String>> map = httpsURLConnection.getHeaderFields(); + for (Map.Entry<String, List<String>> entry : map.entrySet()) { + if (entry.toString().toLowerCase().startsWith("location")) { + Matcher matcher = Patterns.WEB_URL.matcher(entry.toString()); + if (matcher.find()) { + redirect = matcher.group(1); } } - httpsURLConnection.getInputStream().close(); - if (redirect != null && redirect.compareTo(finalURl1) != 0) { - URL redirectURL = new URL(redirect); - String host = redirectURL.getHost(); - String protocol = redirectURL.getProtocol(); - if (protocol == null || host == null) { - redirect = null; - } - } - Handler mainHandler = new Handler(context.getMainLooper()); - String finalRedirect = redirect; - Runnable myRunnable = () -> { - AlertDialog.Builder builder1 = new AlertDialog.Builder(view.getContext()); - if (finalRedirect != null) { - builder1.setMessage(context.getString(R.string.redirect_detected, finalURl1, finalRedirect)); - builder1.setNegativeButton(R.string.copy_link, (dialog, which) -> { - ClipboardManager clipboard1 = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); - ClipData clip1 = ClipData.newPlainText(Helper.CLIP_BOARD, finalRedirect); - if (clipboard1 != null) { - clipboard1.setPrimaryClip(clip1); - Toasty.info(context, context.getString(R.string.clipboard_url), Toast.LENGTH_LONG).show(); - } - dialog.dismiss(); - }); - builder1.setNeutralButton(R.string.share_link, (dialog, which) -> { - Intent sendIntent1 = new Intent(Intent.ACTION_SEND); - sendIntent1.putExtra(Intent.EXTRA_SUBJECT, context.getString(R.string.shared_via)); - sendIntent1.putExtra(Intent.EXTRA_TEXT, finalURl1); - sendIntent1.setType("text/plain"); - context.startActivity(Intent.createChooser(sendIntent1, context.getString(R.string.share_with))); - dialog.dismiss(); - }); - } else { - builder1.setMessage(R.string.no_redirect); - } - builder1.setTitle(context.getString(R.string.check_redirect)); - builder1.setPositiveButton(R.string.close, (dialog, which) -> dialog.dismiss()) - .show(); - - }; - mainHandler.post(myRunnable); - } catch (IOException e) { - e.printStackTrace(); - } - - }).start(); - } catch (MalformedURLException e) { - e.printStackTrace(); - } - - alertDialog.dismiss(); - }); - - } - - @Override - public void onClick(@NonNull View textView) { - String finalURl = newURL; - String finalURl2 = url; - String uniqueNewURL = newURL.endsWith("…") ? newURL : newURL + "…"; - if (urlDetails.containsValue(uniqueNewURL)) { - finalURl = Helper.getKeyByValue(urlDetails, uniqueNewURL); - } - String uniqueUrl = url.endsWith("…") ? url : url + "…"; - if (urlDetails.containsValue(uniqueUrl)) { - finalURl2 = Helper.getKeyByValue(urlDetails, uniqueUrl); - } - textView.setTag(CLICKABLE_SPAN); - Pattern link = Pattern.compile("https?://([\\da-z.-]+\\.[a-z.]{2,10})/(@[\\w._-]*[0-9]*)(/[0-9]+)?$"); - Matcher matcherLink = null; - if (finalURl2 != null) { - matcherLink = link.matcher(finalURl2); - } - if (finalURl2 != null && matcherLink.find() && !finalURl2.contains("medium.com")) { - if (matcherLink.group(3) != null && Objects.requireNonNull(matcherLink.group(3)).length() > 0) { //It's a toot - CrossActionHelper.fetchRemoteStatus(context, currentAccount, finalURl2, new CrossActionHelper.Callback() { - @Override - public void federatedStatus(Status status) { - Intent intent = new Intent(context, ContextActivity.class); - intent.putExtra(Helper.ARG_STATUS, status); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - context.startActivity(intent); } - - @Override - public void federatedAccount(Account account) { + } + httpsURLConnection.getInputStream().close(); + if (redirect != null && redirect.compareTo(finalUrl) != 0) { + URL redirectURL = new URL(redirect); + String host = redirectURL.getHost(); + String protocol = redirectURL.getProtocol(); + if (protocol == null || host == null) { + redirect = null; } - }); - } else {//It's an account - CrossActionHelper.fetchRemoteAccount(context, currentAccount, matcherLink.group(2) + "@" + matcherLink.group(1), new CrossActionHelper.Callback() { - @Override - public void federatedStatus(Status status) { + } + Handler mainHandler = new Handler(context.getMainLooper()); + String finalRedirect = redirect; + Runnable myRunnable = () -> { + AlertDialog.Builder builder1 = new AlertDialog.Builder(view.getContext()); + if (finalRedirect != null) { + builder1.setMessage(context.getString(R.string.redirect_detected, finalUrl, finalRedirect)); + builder1.setNegativeButton(R.string.copy_link, (dialog, which) -> { + ClipboardManager clipboard1 = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); + ClipData clip1 = ClipData.newPlainText(Helper.CLIP_BOARD, finalRedirect); + if (clipboard1 != null) { + clipboard1.setPrimaryClip(clip1); + Toasty.info(context, context.getString(R.string.clipboard_url), Toast.LENGTH_LONG).show(); + } + dialog.dismiss(); + }); + builder1.setNeutralButton(R.string.share_link, (dialog, which) -> { + Intent sendIntent1 = new Intent(Intent.ACTION_SEND); + sendIntent1.putExtra(Intent.EXTRA_SUBJECT, context.getString(R.string.shared_via)); + sendIntent1.putExtra(Intent.EXTRA_TEXT, finalUrl); + sendIntent1.setType("text/plain"); + context.startActivity(Intent.createChooser(sendIntent1, context.getString(R.string.share_with))); + dialog.dismiss(); + }); + } else { + builder1.setMessage(R.string.no_redirect); } + builder1.setTitle(context.getString(R.string.check_redirect)); + builder1.setPositiveButton(R.string.close, (dialog, which) -> dialog.dismiss()) + .show(); - @Override - public void federatedAccount(Account account) { - Intent intent = new Intent(context, ProfileActivity.class); - Bundle b = new Bundle(); - b.putSerializable(Helper.ARG_ACCOUNT, account); - intent.putExtras(b); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - context.startActivity(intent); - } - }); + }; + mainHandler.post(myRunnable); + } catch (IOException e) { + e.printStackTrace(); } - } else { - Helper.openBrowser(context, finalURl); - } + }).start(); + } catch (MalformedURLException e) { + e.printStackTrace(); } - @Override - public void updateDrawState(@NonNull TextPaint ds) { - super.updateDrawState(ds); - if (linkColor != -1) { - ds.setColor(linkColor); - } - } - - }, matchStart, matchEnd, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); - } - } - } - - private static void linkifyURL(Context context, SpannableStringBuilder content, HashMap<String, String> urlDetails) { + alertDialog.dismiss(); + }); - for (Map.Entry<String, String> entry : urlDetails.entrySet()) { - String value = entry.getValue(); - if (value.startsWith("@") || value.startsWith("#")) { - continue; - } - SpannableString contentUrl; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) - contentUrl = new SpannableString(Html.fromHtml(value, Html.FROM_HTML_MODE_LEGACY)); - else - contentUrl = new SpannableString(Html.fromHtml(value)); - if (contentUrl.toString().trim().isEmpty()) { - continue; } - Pattern word = Pattern.compile(Pattern.quote(contentUrl.toString())); - Matcher matcherLink = word.matcher(content); - while (matcherLink.find()) { - String url = entry.getKey(); - int matchStart = matcherLink.start(); - int matchEnd = matchStart + matcherLink.group().length(); - if (matchEnd > content.toString().length()) { - matchEnd = content.toString().length(); - } - if (content.toString().length() < matchEnd || matchStart < 0 || matchStart > matchEnd) { - continue; - } - - ClickableSpan[] clickableSpans = content.getSpans(matchStart, matchEnd, ClickableSpan.class); - if (clickableSpans != null) { - for (ClickableSpan clickableSpan : clickableSpans) { - content.removeSpan(clickableSpan); - } - } - content.removeSpan(clickableSpans); + @Override + public void onClick(@NonNull View textView) { + + textView.setTag(CLICKABLE_SPAN); + Pattern link = Pattern.compile("https?://([\\da-z.-]+\\.[a-z.]{2,10})/(@[\\w._-]*[0-9]*)(/[0-9]+)?$"); + Matcher matcherLink = link.matcher(finalUrl); + Pattern linkLong = Pattern.compile("https?://([\\da-z.-]+\\.[a-z.]{2,10})/(@[\\w_.-]+@[a-zA-Z0-9][a-zA-Z0-9.-]{1,61}[a-zA-Z0-9](?:\\.[a-zA-Z]{2,})+)(/[0-9]+)?$"); + Matcher matcherLinkLong = linkLong.matcher(finalUrl); + if (matcherLink.find() && !finalUrl.contains("medium.com")) { + if (matcherLink.group(3) != null && Objects.requireNonNull(matcherLink.group(3)).length() > 0) { //It's a toot + CrossActionHelper.fetchRemoteStatus(context, currentAccount, finalUrl, new CrossActionHelper.Callback() { + @Override + public void federatedStatus(Status status) { + Intent intent = new Intent(context, ContextActivity.class); + intent.putExtra(Helper.ARG_STATUS, status); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(intent); + } - |