From 9960e9a0a9f25497ab796ad80020f293f46a8477 Mon Sep 17 00:00:00 2001 From: Alex Baker Date: Fri, 9 Apr 2021 09:40:07 -0500 Subject: [PATCH] Convert Linkify to Kotlin --- .../astrid/notes/CommentsController.kt | 7 +- .../BaseCaldavAccountSettingsActivity.kt | 3 +- .../main/java/org/tasks/dialogs/Linkify.java | 136 ------------------ .../main/java/org/tasks/dialogs/Linkify.kt | 106 ++++++++++++++ 4 files changed, 110 insertions(+), 142 deletions(-) delete mode 100644 app/src/main/java/org/tasks/dialogs/Linkify.java create mode 100644 app/src/main/java/org/tasks/dialogs/Linkify.kt diff --git a/app/src/main/java/com/todoroo/astrid/notes/CommentsController.kt b/app/src/main/java/com/todoroo/astrid/notes/CommentsController.kt index 73932051a..9f1c9fd92 100644 --- a/app/src/main/java/com/todoroo/astrid/notes/CommentsController.kt +++ b/app/src/main/java/com/todoroo/astrid/notes/CommentsController.kt @@ -38,9 +38,8 @@ class CommentsController @Inject constructor( private val userActivityDao: UserActivityDao, private val activity: Activity, private val preferences: Preferences, - private val locale: Locale, - private val linkify: Linkify) { - + private val locale: Locale +) { private val items = ArrayList() private var commentItems = 10 private var task: Task? = null @@ -88,7 +87,7 @@ class CommentsController @Inject constructor( // name val nameView = view.findViewById(R.id.title) nameView.text = Html.fromHtml(item.message) - linkify.safeLinkify(nameView, android.text.util.Linkify.ALL) + Linkify.safeLinkify(nameView, android.text.util.Linkify.ALL) // date val date = view.findViewById(R.id.date) diff --git a/app/src/main/java/org/tasks/caldav/BaseCaldavAccountSettingsActivity.kt b/app/src/main/java/org/tasks/caldav/BaseCaldavAccountSettingsActivity.kt index 30081147b..30d4c6296 100644 --- a/app/src/main/java/org/tasks/caldav/BaseCaldavAccountSettingsActivity.kt +++ b/app/src/main/java/org/tasks/caldav/BaseCaldavAccountSettingsActivity.kt @@ -48,7 +48,6 @@ abstract class BaseCaldavAccountSettingsActivity : ThemedInjectingAppCompatActiv @Inject lateinit var taskDeleter: TaskDeleter @Inject lateinit var inventory: Inventory @Inject lateinit var firebase: Firebase - @Inject lateinit var linkify: Linkify protected var caldavAccount: CaldavAccount? = null protected lateinit var binding: ActivityCaldavAccountSettingsBinding @@ -62,7 +61,7 @@ abstract class BaseCaldavAccountSettingsActivity : ThemedInjectingAppCompatActiv binding.nameLayout.visibility = View.GONE binding.description.visibility = View.VISIBLE binding.description.setText(description) - linkify.safeLinkify(binding.description, android.text.util.Linkify.WEB_URLS) + Linkify.safeLinkify(binding.description, android.text.util.Linkify.WEB_URLS) } else { binding.nameLayout.visibility = View.VISIBLE binding.description.visibility = View.GONE diff --git a/app/src/main/java/org/tasks/dialogs/Linkify.java b/app/src/main/java/org/tasks/dialogs/Linkify.java deleted file mode 100644 index e7564c0e0..000000000 --- a/app/src/main/java/org/tasks/dialogs/Linkify.java +++ /dev/null @@ -1,136 +0,0 @@ -package org.tasks.dialogs; - -import static java.util.Arrays.asList; -import static org.tasks.Strings.isNullOrEmpty; - -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 androidx.core.text.util.LinkifyCompat; -import dagger.hilt.android.qualifiers.ActivityContext; -import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; -import javax.inject.Inject; -import org.tasks.R; -import timber.log.Timber; - -public class Linkify { - - private final Context context; - private final DialogBuilder dialogBuilder; - - @Inject - public Linkify(@ActivityContext Context context, DialogBuilder dialogBuilder) { - this.context = context; - this.dialogBuilder = dialogBuilder; - } - - public void safeLinkify(TextView textView, int mask) { - try { - LinkifyCompat.addLinks(textView, mask); - } catch (UnsatisfiedLinkError e) { - Timber.e(e); - } - } - - public void linkify(TextView textView) { - linkify(textView, () -> {}); - } - - public void linkify(TextView textView, Runnable onClick) { - if (textView.length() == 0) { - return; - } - - safeLinkify(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 class ClickHandlingURLSpan extends URLSpan { - - private final Runnable onEdit; - - ClickHandlingURLSpan(String url, Runnable onEdit) { - super(url); - this.onEdit = onEdit; - } - - @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 (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(); - } - } -} diff --git a/app/src/main/java/org/tasks/dialogs/Linkify.kt b/app/src/main/java/org/tasks/dialogs/Linkify.kt new file mode 100644 index 000000000..6ff212f86 --- /dev/null +++ b/app/src/main/java/org/tasks/dialogs/Linkify.kt @@ -0,0 +1,106 @@ +package org.tasks.dialogs + +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.View +import android.widget.TextView +import androidx.core.text.util.LinkifyCompat +import dagger.hilt.android.qualifiers.ActivityContext +import org.tasks.R +import org.tasks.Strings.isNullOrEmpty +import timber.log.Timber +import java.io.UnsupportedEncodingException +import java.net.URLDecoder +import javax.inject.Inject + +class Linkify @Inject constructor( + @ActivityContext private val context: Context, + private val dialogBuilder: DialogBuilder +) { + fun linkify(textView: TextView, onClick: Runnable = Runnable {}) { + if (textView.length() == 0) { + return + } + safeLinkify(textView, Linkify.ALL) + textView.setOnClickListener { + if (textView.selectionStart == -1 && textView.selectionEnd == -1) { + onClick.run() + } + } + val text = textView.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, onClick), start, end, 0) + } + } + } + + private inner class ClickHandlingURLSpan constructor( + url: String?, + private val onEdit: Runnable + ) : 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) + var scheme = uri.scheme + if (isNullOrEmpty(scheme)) { + scheme = "" + } + when (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) + } + } + dialogBuilder + .newDialog(title) + .setItems(listOf(action, edit)) { _, selected -> + if (selected == 0) { + context.startActivity(Intent(Intent.ACTION_VIEW, uri)) + } else { + onEdit.run() + } + } + .show() + } + } + + companion object { + fun safeLinkify(textView: TextView?, mask: Int) { + try { + LinkifyCompat.addLinks(textView!!, mask) + } catch (e: UnsatisfiedLinkError) { + Timber.e(e) + } + } + } +} \ No newline at end of file