mirror of
https://codeberg.org/tom79/Fedilab.git
synced 2024-12-23 01:00:04 +02:00
Comment issue #366 - Make text clickable
This commit is contained in:
parent
60a1b2bfa4
commit
4d3c94c7fd
1 changed files with 227 additions and 0 deletions
|
@ -115,6 +115,7 @@ public class SpannableHelper {
|
|||
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);
|
||||
|
@ -140,6 +141,7 @@ public class SpannableHelper {
|
|||
interaction(context, content, mentionList);
|
||||
//Make all links
|
||||
linkify(context, content, urlDetails);
|
||||
linkifyURL(context, content, urlDetails);
|
||||
} else {
|
||||
content = new SpannableStringBuilder(text);
|
||||
}
|
||||
|
@ -185,6 +187,8 @@ public class SpannableHelper {
|
|||
Matcher matcherLink = urlPattern.matcher(content);
|
||||
|
||||
int offSetTruncate = 0;
|
||||
|
||||
|
||||
while (matcherLink.find()) {
|
||||
int matchStart = matcherLink.start() - offSetTruncate;
|
||||
int matchEnd = matchStart + matcherLink.group().length();
|
||||
|
@ -433,6 +437,229 @@ public class SpannableHelper {
|
|||
}
|
||||
}
|
||||
|
||||
private static void linkifyURL(Context context, SpannableStringBuilder content, HashMap<String, String> urlDetails) {
|
||||
|
||||
for (Map.Entry<String, String> entry : urlDetails.entrySet()) {
|
||||
String value = entry.getValue();
|
||||
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));
|
||||
|
||||
Pattern word = Pattern.compile(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;
|
||||
}
|
||||
if (matchEnd <= content.length()) {
|
||||
content.setSpan(new LongClickableSpan() {
|
||||
@Override
|
||||
public void onLongClick(View view) {
|
||||
Context mContext = view.getContext();
|
||||
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(mContext, Helper.dialogStyle());
|
||||
PopupLinksBinding popupLinksBinding = PopupLinksBinding.inflate(LayoutInflater.from(context));
|
||||
dialogBuilder.setView(popupLinksBinding.getRoot());
|
||||
AlertDialog alertDialog = dialogBuilder.create();
|
||||
alertDialog.show();
|
||||
String finalURl = url;
|
||||
if (urlDetails.containsValue(url)) {
|
||||
finalURl = Helper.getKeyByValue(urlDetails, url);
|
||||
}
|
||||
String finalURl1 = finalURl;
|
||||
popupLinksBinding.displayFullLink.setOnClickListener(v -> {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(mContext, Helper.dialogStyle());
|
||||
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();
|
||||
});
|
||||
|
||||
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();
|
||||
});
|
||||
|
||||
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 {
|
||||
|
||||
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 = urlPattern.matcher(entry.toString());
|
||||
if (matcher.find()) {
|
||||
redirect = matcher.group(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
httpsURLConnection.getInputStream().close();
|
||||
if (redirect != null && finalURl1 != 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(), Helper.dialogStyle());
|
||||
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 = url;
|
||||
if (urlDetails.containsValue(url)) {
|
||||
finalURl = Helper.getKeyByValue(urlDetails, url);
|
||||
}
|
||||
|
||||
textView.setTag(CLICKABLE_SPAN);
|
||||
Pattern link = Pattern.compile("https?://([\\da-z.-]+\\.[a-z.]{2,10})/(@[\\w._-]*[0-9]*)(/[0-9]+)?$");
|
||||
Matcher matcherLink = null;
|
||||
if (finalURl != null) {
|
||||
matcherLink = link.matcher(finalURl);
|
||||
}
|
||||
if (finalURl != null && 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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void federatedAccount(Account account) {
|
||||
}
|
||||
});
|
||||
} else {//It's an account
|
||||
CrossActionHelper.fetchRemoteAccount(context, currentAccount, matcherLink.group(2) + "@" + matcherLink.group(1), new CrossActionHelper.Callback() {
|
||||
@Override
|
||||
public void federatedStatus(Status status) {
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
Helper.openBrowser(context, finalURl);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDrawState(@NonNull TextPaint ds) {
|
||||
super.updateDrawState(ds);
|
||||
ds.setUnderlineText(false);
|
||||
ds.setColor(linkColor);
|
||||
}
|
||||
}, matchStart, matchEnd, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static void interaction(Context context, Spannable content, List<Mention> mentions) {
|
||||
// --- For all patterns defined in Helper class ---
|
||||
for (Map.Entry<Helper.PatternType, Pattern> entry : Helper.patternHashMap.entrySet()) {
|
||||
|
|
Loading…
Reference in a new issue