From 1ac8ec0d97e1ad9f28439db2c68e6be3f78c9d10 Mon Sep 17 00:00:00 2001 From: Alex Baker Date: Mon, 19 Apr 2021 12:40:03 -0500 Subject: [PATCH] Use built-in link movement method --- app/build.gradle.kts | 1 - app/licenses.yml | 6 - app/src/main/assets/licenses.json | 14 -- .../main/java/org/tasks/dialogs/Linkify.kt | 122 ++++++++++-------- deps_fdroid.txt | 1 - deps_googleplay.txt | 1 - 6 files changed, 67 insertions(+), 78 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 271f5bc12..928d18daf 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -190,7 +190,6 @@ dependencies { implementation("io.noties.markwon:ext-strikethrough:${Versions.markwon}") implementation("io.noties.markwon:ext-tables:${Versions.markwon}") implementation("io.noties.markwon:linkify:${Versions.markwon}") - implementation("me.saket:better-link-movement-method:2.2.0") debugImplementation("com.facebook.flipper:flipper:${Versions.flipper}") debugImplementation("com.facebook.flipper:flipper-network-plugin:${Versions.flipper}") diff --git a/app/licenses.yml b/app/licenses.yml index 6613ab5d4..126dce5e7 100644 --- a/app/licenses.yml +++ b/app/licenses.yml @@ -938,12 +938,6 @@ name: commonmark-ext-gfm-strikethrough copyrightHolder: Atlassian and others license: BSD 2-Clause -- artifact: me.saket:better-link-movement-method:+ - name: better-link-movement-method - copyrightHolder: Saket Narayan - license: The Apache Software License, Version 2.0 - licenseUrl: http://www.apache.org/licenses/LICENSE-2.0 - url: https://github.com/Saketme/BetterLinkMovementMethod - artifact: io.noties.markwon:linkify:+ name: linkify copyrightHolder: Dimitry Ivanov diff --git a/app/src/main/assets/licenses.json b/app/src/main/assets/licenses.json index 50cea1af1..ef68a945c 100644 --- a/app/src/main/assets/licenses.json +++ b/app/src/main/assets/licenses.json @@ -2230,20 +2230,6 @@ "normalizedLicense": "bsd_2_clauses", "libraryName": "commonmark-ext-gfm-strikethrough" }, - { - "artifactId": { - "name": "better-link-movement-method", - "group": "me.saket", - "version": "+" - }, - "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", - "normalizedLicense": "apache2", - "url": "https://github.com/Saketme/BetterLinkMovementMethod", - "libraryName": "better-link-movement-method" - }, { "artifactId": { "name": "linkify", diff --git a/app/src/main/java/org/tasks/dialogs/Linkify.kt b/app/src/main/java/org/tasks/dialogs/Linkify.kt index f1d9bd310..d1681cd12 100644 --- a/app/src/main/java/org/tasks/dialogs/Linkify.kt +++ b/app/src/main/java/org/tasks/dialogs/Linkify.kt @@ -4,12 +4,14 @@ 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.text.util.Linkify -import android.view.MotionEvent +import android.view.View import android.widget.TextView import androidx.core.text.util.LinkifyCompat import dagger.hilt.android.qualifiers.ActivityContext -import me.saket.bettermovementmethod.BetterLinkMovementMethod import org.tasks.R import timber.log.Timber import java.io.UnsupportedEncodingException @@ -29,68 +31,78 @@ class Linkify @Inject constructor( } fun setMovementMethod(tv: TextView, handle: (() -> Unit)? = null) { - val blmm = BetterLinkMovementMethod.newInstance().apply { - setOnLinkClickListener { _, url -> onClick(url, handle ?: {}) } - setOnLinkLongClickListener { _, _ -> tv.performLongClick() } - } - tv.movementMethod = blmm - tv.setOnTouchListener { _, event -> - val text = tv.text - when { - text is Spannable && blmm.onTouchEvent(tv, text, event) -> true - event.action == MotionEvent.ACTION_UP -> { - handle?.invoke() - false - } - else -> false + tv.setOnClickListener { + if (!tv.hasSelection()) { + handle?.invoke() } } - } + val text = tv.text + if (text is SpannableStringBuilder || text is SpannableString) { + val spannable = text as Spannable + val spans = spannable.getSpans(0, text.length, URLSpan::class.java) + for (span in spans) { + val start = spannable.getSpanStart(span) + val end = spannable.getSpanEnd(span) + spannable.removeSpan(span) + spannable.setSpan( + ClickHandlingURLSpan(span.url, handle), + start, + end, + 0 + ) - fun onClick(url: String, onEdit: () -> Unit): Boolean { - var title: String? - val edit = context.getString(R.string.TAd_actionEditTask) - val action: String - val uri = Uri.parse(url).let { - if (it.scheme.isNullOrBlank()) { - Uri.parse("https://$url") - } else { - it } } - when (uri.scheme) { - "tel" -> { - title = uri.encodedSchemeSpecificPart - action = context.getString(R.string.action_call) - } - "mailto" -> { - title = uri.encodedSchemeSpecificPart - action = context.getString(R.string.action_open) - } - "geo" -> { - title = uri.encodedQuery!!.replaceFirst("q=".toRegex(), "") - try { - title = URLDecoder.decode(title, "utf-8") - } catch (ignored: UnsupportedEncodingException) { + } + + private inner class ClickHandlingURLSpan constructor( + url: String?, + private val onEdit: (() -> Unit)? = null + ) : URLSpan(url) { + override fun onClick(widget: View) { + var title: String? + val edit = context.getString(R.string.TAd_actionEditTask) + val action: String + val uri = Uri.parse(url).let { + if (it.scheme.isNullOrBlank()) { + Uri.parse("https://$url") + } else { + it } - action = context.getString(R.string.action_open) } - else -> { - title = url - action = context.getString(R.string.action_open) - } - } - dialogBuilder - .newDialog(title) - .setItems(listOf(action, edit)) { _, selected -> - if (selected == 0) { - context.startActivity(Intent(Intent.ACTION_VIEW, uri)) - } else { - onEdit() + when (uri.scheme) { + "tel" -> { + title = uri.encodedSchemeSpecificPart + action = context.getString(R.string.action_call) + } + "mailto" -> { + title = uri.encodedSchemeSpecificPart + action = context.getString(R.string.action_open) + } + "geo" -> { + title = uri.encodedQuery!!.replaceFirst("q=".toRegex(), "") + try { + title = URLDecoder.decode(title, "utf-8") + } catch (ignored: UnsupportedEncodingException) { + } + action = context.getString(R.string.action_open) + } + else -> { + title = url + action = context.getString(R.string.action_open) } } - .show() - return true + dialogBuilder + .newDialog(title) + .setItems(listOf(action, edit)) { _, selected -> + if (selected == 0) { + context.startActivity(Intent(Intent.ACTION_VIEW, uri)) + } else { + onEdit?.invoke() + } + } + .show() + } } companion object { diff --git a/deps_fdroid.txt b/deps_fdroid.txt index 4f6a13c82..de68fa996 100644 --- a/deps_fdroid.txt +++ b/deps_fdroid.txt @@ -306,7 +306,6 @@ +| \--- com.atlassian.commonmark:commonmark:0.13.0 ++--- io.noties.markwon:linkify:4.6.2 +| \--- io.noties.markwon:core:4.6.2 (*) -++--- me.saket:better-link-movement-method:2.2.0 ++--- org.jetbrains.kotlin:kotlin-stdlib:1.4.32 (*) ++--- org.jetbrains.kotlinx:kotlinx-collections-immutable-jvm:0.3.4 +| +--- org.jetbrains.kotlin:kotlin-stdlib:1.4.30 -> 1.4.32 (*) diff --git a/deps_googleplay.txt b/deps_googleplay.txt index 64c457b67..98ad90039 100644 --- a/deps_googleplay.txt +++ b/deps_googleplay.txt @@ -423,7 +423,6 @@ +| \--- com.atlassian.commonmark:commonmark:0.13.0 ++--- io.noties.markwon:linkify:4.6.2 +| \--- io.noties.markwon:core:4.6.2 (*) -++--- me.saket:better-link-movement-method:2.2.0 ++--- org.jetbrains.kotlin:kotlin-stdlib:1.4.32 (*) ++--- org.jetbrains.kotlinx:kotlinx-collections-immutable-jvm:0.3.4 +| +--- org.jetbrains.kotlin:kotlin-stdlib:1.4.30 -> 1.4.32 (*)