diff --git a/app/build.gradle b/app/build.gradle index 902c3fa82..a27deae66 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -27,7 +27,7 @@ android { applicationId "io.github.nekoinverter.ehviewer" minSdkVersion 23 targetSdkVersion 30 - versionCode 150 + versionCode 151 versionName "1.7.24" resConfigs "zh", "zh-rCN", "zh-rHK", "zh-rTW", "es", "ja", "ko", "fr", "de", "th" diff --git a/app/src/main/java/com/hippo/ehviewer/EhApplication.java b/app/src/main/java/com/hippo/ehviewer/EhApplication.java index c825af9d7..d0800ac9d 100644 --- a/app/src/main/java/com/hippo/ehviewer/EhApplication.java +++ b/app/src/main/java/com/hippo/ehviewer/EhApplication.java @@ -36,7 +36,6 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AlertDialog; import androidx.collection.LruCache; -import androidx.core.text.HtmlCompat; import com.hippo.a7zip.A7Zip; import com.hippo.beerbelly.SimpleDiskCache; @@ -434,13 +433,15 @@ public class EhApplication extends SceneApplication { if (activity != null) { activity.runOnUiThread(() -> { AlertDialog dialog = new AlertDialog.Builder(activity) - .setMessage(HtmlCompat.fromHtml(html, HtmlCompat.FROM_HTML_MODE_LEGACY)) + .setMessage(Html.fromHtml(html)) .setPositiveButton(android.R.string.ok, null) .create(); - final View messageView = dialog.findViewById(android.R.id.message); - if (messageView instanceof TextView) { - ((TextView) messageView).setMovementMethod(LinkMovementMethod.getInstance()); - } + dialog.setOnShowListener(d -> { + final View messageView = dialog.findViewById(android.R.id.message); + if (messageView instanceof TextView) { + ((TextView) messageView).setMovementMethod(LinkMovementMethod.getInstance()); + } + }); try { dialog.show(); } catch (Throwable t) { diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryCommentsScene.java b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryCommentsScene.java index c71e063fe..35dcce52f 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryCommentsScene.java +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryCommentsScene.java @@ -77,6 +77,7 @@ import com.hippo.text.URLImageGetter; import com.hippo.util.ClipboardUtil; import com.hippo.util.ExceptionUtils; import com.hippo.util.ReadableTime; +import com.hippo.util.TextUrl; import com.hippo.view.ViewTransition; import com.hippo.widget.FabLayout; import com.hippo.widget.LinkifyTextView; @@ -965,9 +966,7 @@ public final class GalleryCommentsScene extends ToolbarScene ssb.append("\n\n").append(ss); } - LinkifyCompat.addLinks(ssb, Linkify.WEB_URLS); - - return ssb; + return TextUrl.handleTextUrl(ssb); } public void bind(GalleryComment value) { diff --git a/app/src/main/java/com/hippo/util/TextUrl.java b/app/src/main/java/com/hippo/util/TextUrl.java new file mode 100644 index 000000000..1a6867154 --- /dev/null +++ b/app/src/main/java/com/hippo/util/TextUrl.java @@ -0,0 +1,59 @@ +/* + * Copyright 2016 Hippo Seven + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.hippo.util; + +import android.text.Spannable; +import android.text.SpannableString; +import android.text.style.URLSpan; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public final class TextUrl { + + private static final Pattern URL_PATTERN = Pattern.compile("(http|https)://[a-z0-9A-Z%-]+(\\.[a-z0-9A-Z%-]+)+(:\\d{1,5})?(/[a-zA-Z0-9-_~:#@!&',;=%/*.?+$\\[\\]()]+)?/?"); + + public static CharSequence handleTextUrl(CharSequence content) { + Matcher m = URL_PATTERN.matcher(content); + + Spannable spannable = null; + while (m.find()) { + // Ensure spannable + if (spannable == null) { + if (content instanceof Spannable) { + spannable = (Spannable) content; + } else { + spannable = new SpannableString(content); + } + } + + int start = m.start(); + int end = m.end(); + + URLSpan[] links = spannable.getSpans(start, end, URLSpan.class); + if (links.length > 0) { + // There has been URLSpan already, leave it alone + continue; + } + + URLSpan urlSpan = new URLSpan(m.group(0)); + spannable.setSpan(urlSpan, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + } + + return spannable == null ? content : spannable; + } +}