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("io.github.luizgrp.sectionedrecyclerviewadapter:sectionedrecyclerviewadapter:2.0.0")
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.google.code.gson:gson:2.8.6")
implementation("com.google.android.material:material:1.1.0")

@ -477,12 +477,6 @@
license: The Apache Software License, Version 2.0
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt
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:+
name: Android Support Library Drawer Layout
copyrightHolder: Android Open Source Project

@ -1280,22 +1280,6 @@
"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,
"copyrightHolder": "Android Open Source Project",

@ -5,12 +5,16 @@ import static java.util.Arrays.asList;
import android.content.Context;
import android.content.Intent;
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 com.google.common.base.Strings;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import javax.inject.Inject;
import me.saket.bettermovementmethod.BetterLinkMovementMethod;
import org.tasks.R;
import org.tasks.injection.ForActivity;
@ -26,68 +30,97 @@ public class Linkify {
}
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) {
return;
}
BetterLinkMovementMethod.linkify(android.text.util.Linkify.ALL, textView)
.setOnLinkClickListener((tv, url) -> handleLink(url, onClick))
.setOnLinkLongClickListener(
(tv, url) -> {
onLongClick.run();
return true;
});
android.text.util.Linkify.addLinks(textView, android.text.util.Linkify.ALL);
textView.setOnClickListener(
v -> {
if (textView.getSelectionStart() == -1 && textView.getSelectionEnd() == -1) {
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) {
String title;
String edit = context.getString(R.string.TAd_actionEditTask);
String action;
Uri uri = Uri.parse(url);
String scheme = uri.getScheme();
if (Strings.isNullOrEmpty(scheme)) {
scheme = "";
private class ClickHandlingURLSpan extends URLSpan {
private final Runnable onEdit;
ClickHandlingURLSpan(String url, Runnable onEdit) {
super(url);
this.onEdit = onEdit;
}
switch (scheme) {
case "tel":
title = uri.getEncodedSchemeSpecificPart();
action = context.getString(R.string.action_call);
break;
case "mailto":
title = uri.getEncodedSchemeSpecificPart();
action = context.getString(R.string.action_open);
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;
@Override
public void onClick(View widget) {
String title;
String edit = context.getString(R.string.TAd_actionEditTask);
String action;
String url = getURL();
Uri uri = Uri.parse(url);
String scheme = uri.getScheme();
if (Strings.isNullOrEmpty(scheme)) {
scheme = "";
}
switch (scheme) {
case "tel":
title = uri.getEncodedSchemeSpecificPart();
action = context.getString(R.string.action_call);
break;
case "mailto":
title = uri.getEncodedSchemeSpecificPart();
action = context.getString(R.string.action_open);
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 org.tasks.R;
import org.tasks.data.TaskContainer;
import org.tasks.dialogs.DateTimePicker;
import org.tasks.dialogs.Linkify;
import org.tasks.locale.Locale;
import org.tasks.preferences.Preferences;
@ -209,11 +208,9 @@ public class ViewHolder extends RecyclerView.ViewHolder {
description.setVisibility(task.hasNotes() ? View.VISIBLE : View.GONE);
}
if (preferences.getBoolean(R.string.p_linkify_task_list, false)) {
linkify.linkify(nameView, this::onRowBodyClick, this::onRowBodyLongClick);
linkify.linkify(description, this::onRowBodyClick, this::onRowBodyLongClick);
nameView.setOnClickListener(view -> onRowBodyClick());
linkify.linkify(nameView, this::onRowBodyClick);
linkify.linkify(description, this::onRowBodyClick);
nameView.setOnLongClickListener(view -> onRowBodyLongClick());
description.setOnClickListener(view -> onRowBodyClick());
description.setOnLongClickListener(view -> onRowBodyLongClick());
}
if (chipGroup.getVisibility() == View.VISIBLE) {

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

Loading…
Cancel
Save