Improve link click handling

pull/996/head
Alex Baker 4 years ago
parent d06867c2a7
commit bf98d474bf

@ -160,7 +160,6 @@ dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib:${Versions.kotlin}") implementation("org.jetbrains.kotlin:kotlin-stdlib:${Versions.kotlin}")
implementation("io.github.luizgrp.sectionedrecyclerviewadapter:sectionedrecyclerviewadapter:2.0.0") implementation("io.github.luizgrp.sectionedrecyclerviewadapter:sectionedrecyclerviewadapter:2.0.0")
implementation("androidx.multidex:multidex:2.0.1") implementation("androidx.multidex:multidex:2.0.1")
implementation("me.saket:better-link-movement-method:2.2.0")
implementation("com.squareup.okhttp3:okhttp:${Versions.okhttp}") implementation("com.squareup.okhttp3:okhttp:${Versions.okhttp}")
implementation("com.google.code.gson:gson:2.8.6") implementation("com.google.code.gson:gson:2.8.6")
implementation("com.google.android.material:material:1.1.0") implementation("com.google.android.material:material:1.1.0")

@ -477,12 +477,6 @@
license: The Apache Software License, Version 2.0 license: The Apache Software License, Version 2.0
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt
url: https://developer.android.com/topic/libraries/architecture/index.html url: https://developer.android.com/topic/libraries/architecture/index.html
- artifact: me.saket:better-link-movement-method:+
name: BetterLinkMovementMethod
copyrightHolder: Saket Narayan
license: The Apache Software License, Version 2.0
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt
url: https://github.com/Saketme/BetterLinkMovementMethod
- artifact: androidx.drawerlayout:drawerlayout:+ - artifact: androidx.drawerlayout:drawerlayout:+
name: Android Support Library Drawer Layout name: Android Support Library Drawer Layout
copyrightHolder: Android Open Source Project copyrightHolder: Android Open Source Project

@ -1280,22 +1280,6 @@
"version": "2.2.5" "version": "2.2.5"
} }
}, },
{
"notice": null,
"copyrightHolder": "Saket Narayan",
"copyrightStatement": "Copyright © Saket Narayan. All rights reserved.",
"license": "The Apache Software License, Version 2.0",
"licenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt",
"normalizedLicense": "apache2",
"year": null,
"url": "https://github.com/Saketme/BetterLinkMovementMethod",
"libraryName": "BetterLinkMovementMethod",
"artifactId": {
"name": "better-link-movement-method",
"group": "me.saket",
"version": "2.2.0"
}
},
{ {
"notice": null, "notice": null,
"copyrightHolder": "Android Open Source Project", "copyrightHolder": "Android Open Source Project",

@ -5,12 +5,16 @@ import static java.util.Arrays.asList;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.style.URLSpan;
import android.view.View;
import android.widget.TextView; import android.widget.TextView;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.net.URLDecoder; import java.net.URLDecoder;
import javax.inject.Inject; import javax.inject.Inject;
import me.saket.bettermovementmethod.BetterLinkMovementMethod;
import org.tasks.R; import org.tasks.R;
import org.tasks.injection.ForActivity; import org.tasks.injection.ForActivity;
@ -26,68 +30,97 @@ public class Linkify {
} }
public void linkify(TextView textView) { public void linkify(TextView textView) {
linkify(textView, () -> {}, () -> {}); linkify(textView, () -> {});
} }
public void linkify(TextView textView, Runnable onClick, Runnable onLongClick) { public void linkify(TextView textView, Runnable onClick) {
if (textView.length() == 0) { if (textView.length() == 0) {
return; return;
} }
BetterLinkMovementMethod.linkify(android.text.util.Linkify.ALL, textView) android.text.util.Linkify.addLinks(textView, android.text.util.Linkify.ALL);
.setOnLinkClickListener((tv, url) -> handleLink(url, onClick))
.setOnLinkLongClickListener( textView.setOnClickListener(
(tv, url) -> { v -> {
onLongClick.run(); if (textView.getSelectionStart() == -1 && textView.getSelectionEnd() == -1) {
return true; onClick.run();
}); }
});
URLSpan[] spans;
Spannable spannable;
CharSequence text = textView.getText();
if (text instanceof SpannableStringBuilder || text instanceof SpannableString) {
spannable = (Spannable) text;
} else {
return;
}
spans = spannable.getSpans(0, text.length(), URLSpan.class);
for (URLSpan span : spans) {
int start = spannable.getSpanStart(span);
int end = spannable.getSpanEnd(span);
spannable.removeSpan(span);
spannable.setSpan(new ClickHandlingURLSpan(span.getURL(), onClick), start, end, 0);
}
} }
private boolean handleLink(String url, Runnable onEdit) { private class ClickHandlingURLSpan extends URLSpan {
String title;
String edit = context.getString(R.string.TAd_actionEditTask); private final Runnable onEdit;
String action;
Uri uri = Uri.parse(url); ClickHandlingURLSpan(String url, Runnable onEdit) {
String scheme = uri.getScheme(); super(url);
if (Strings.isNullOrEmpty(scheme)) { this.onEdit = onEdit;
scheme = "";
} }
switch (scheme) {
case "tel": @Override
title = uri.getEncodedSchemeSpecificPart(); public void onClick(View widget) {
action = context.getString(R.string.action_call); String title;
break; String edit = context.getString(R.string.TAd_actionEditTask);
case "mailto": String action;
title = uri.getEncodedSchemeSpecificPart(); String url = getURL();
action = context.getString(R.string.action_open); Uri uri = Uri.parse(url);
break; String scheme = uri.getScheme();
case "geo": if (Strings.isNullOrEmpty(scheme)) {
title = uri.getEncodedQuery().replaceFirst("q=", ""); scheme = "";
try { }
title = URLDecoder.decode(title, "utf-8"); switch (scheme) {
} catch (UnsupportedEncodingException ignored) { case "tel":
} title = uri.getEncodedSchemeSpecificPart();
action = context.getString(R.string.action_open); action = context.getString(R.string.action_call);
break; break;
default: case "mailto":
title = url; title = uri.getEncodedSchemeSpecificPart();
action = context.getString(R.string.action_open); action = context.getString(R.string.action_open);
break; break;
case "geo":
title = uri.getEncodedQuery().replaceFirst("q=", "");
try {
title = URLDecoder.decode(title, "utf-8");
} catch (UnsupportedEncodingException ignored) {
}
action = context.getString(R.string.action_open);
break;
default:
title = url;
action = context.getString(R.string.action_open);
break;
}
dialogBuilder
.newDialog(title)
.setItems(
asList(action, edit),
(dialogInterface, selected) -> {
if (selected == 0) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(uri);
context.startActivity(intent);
} else {
onEdit.run();
}
})
.show();
} }
dialogBuilder
.newDialog(title)
.setItems(
asList(action, edit),
(dialogInterface, selected) -> {
if (selected == 0) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(uri);
context.startActivity(intent);
} else {
onEdit.run();
}
})
.show();
return true;
} }
} }

@ -25,7 +25,6 @@ import com.todoroo.astrid.ui.CheckableImageView;
import java.util.List; import java.util.List;
import org.tasks.R; import org.tasks.R;
import org.tasks.data.TaskContainer; import org.tasks.data.TaskContainer;
import org.tasks.dialogs.DateTimePicker;
import org.tasks.dialogs.Linkify; import org.tasks.dialogs.Linkify;
import org.tasks.locale.Locale; import org.tasks.locale.Locale;
import org.tasks.preferences.Preferences; import org.tasks.preferences.Preferences;
@ -209,11 +208,9 @@ public class ViewHolder extends RecyclerView.ViewHolder {
description.setVisibility(task.hasNotes() ? View.VISIBLE : View.GONE); description.setVisibility(task.hasNotes() ? View.VISIBLE : View.GONE);
} }
if (preferences.getBoolean(R.string.p_linkify_task_list, false)) { if (preferences.getBoolean(R.string.p_linkify_task_list, false)) {
linkify.linkify(nameView, this::onRowBodyClick, this::onRowBodyLongClick); linkify.linkify(nameView, this::onRowBodyClick);
linkify.linkify(description, this::onRowBodyClick, this::onRowBodyLongClick); linkify.linkify(description, this::onRowBodyClick);
nameView.setOnClickListener(view -> onRowBodyClick());
nameView.setOnLongClickListener(view -> onRowBodyLongClick()); nameView.setOnLongClickListener(view -> onRowBodyLongClick());
description.setOnClickListener(view -> onRowBodyClick());
description.setOnLongClickListener(view -> onRowBodyLongClick()); description.setOnLongClickListener(view -> onRowBodyLongClick());
} }
if (chipGroup.getVisibility() == View.VISIBLE) { if (chipGroup.getVisibility() == View.VISIBLE) {

@ -34,7 +34,7 @@
<TextView <TextView
android:id="@+id/title" android:id="@+id/title"
android:layout_width="fill_parent" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_toEndOf="@id/completeBox" android:layout_toEndOf="@id/completeBox"
android:layout_toStartOf="@id/due_date" android:layout_toStartOf="@id/due_date"
@ -52,7 +52,7 @@
<TextView <TextView
android:id="@+id/description" android:id="@+id/description"
android:layout_width="match_parent" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_below="@id/title" android:layout_below="@id/title"
android:layout_marginTop="@dimen/task_list_item_spacing" android:layout_marginTop="@dimen/task_list_item_spacing"

Loading…
Cancel
Save