aboutsummaryrefslogtreecommitdiff
path: root/app/src/main/java/ml
diff options
context:
space:
mode:
authorDocile-Alligator <25734209+Docile-Alligator@users.noreply.github.com>2023-12-09 05:03:29 +0000
committerDocile-Alligator <25734209+Docile-Alligator@users.noreply.github.com>2023-12-09 05:03:29 +0000
commit6065dc84548e2111cabb23565e8789cf091fd75b (patch)
tree96a651c85492d4c9989f7ac8e9bc51ca3a9eba2b /app/src/main/java/ml
parentfd2ee38e8d98eef92e1ea7c1fe2b68506b696569 (diff)
downloadinfinity-for-reddit-6065dc84548e2111cabb23565e8789cf091fd75b.tar
infinity-for-reddit-6065dc84548e2111cabb23565e8789cf091fd75b.tar.gz
infinity-for-reddit-6065dc84548e2111cabb23565e8789cf091fd75b.tar.bz2
infinity-for-reddit-6065dc84548e2111cabb23565e8789cf091fd75b.tar.lz
infinity-for-reddit-6065dc84548e2111cabb23565e8789cf091fd75b.tar.xz
infinity-for-reddit-6065dc84548e2111cabb23565e8789cf091fd75b.tar.zst
infinity-for-reddit-6065dc84548e2111cabb23565e8789cf091fd75b.zip
Fix OnClickListener's onlick being called even if it's null. Fix the double haptic feedback issue in markdown text.
Diffstat (limited to 'app/src/main/java/ml')
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/activities/ViewSubredditDetailActivity.java7
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/activities/ViewUserDetailActivity.java7
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/activities/WikiActivity.java4
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/adapters/CommentsListingRecyclerViewAdapter.java4
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/adapters/CommentsRecyclerViewAdapter.java6
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/adapters/MessageRecyclerViewAdapter.java1
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/adapters/PostDetailRecyclerViewAdapter.java11
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/adapters/PrivateMessagesDetailRecyclerViewAdapter.java1
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/adapters/RulesRecyclerViewAdapter.java6
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/customviews/SpoilerOnClickTextView.java2
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/fragments/SidebarFragment.java6
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/markdown/CustomMarkwonAdapter.java25
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/markdown/EvenBetterLinkMovementMethod.java450
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/markdown/MarkdownUtils.java9
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SpoilerAwareMovementMethod.java12
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SpoilerSpan.java2
16 files changed, 505 insertions, 48 deletions
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/ViewSubredditDetailActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/ViewSubredditDetailActivity.java
index 9101cfbc..80c0b8b5 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/ViewSubredditDetailActivity.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/ViewSubredditDetailActivity.java
@@ -71,7 +71,6 @@ import io.noties.markwon.MarkwonConfiguration;
import io.noties.markwon.MarkwonPlugin;
import io.noties.markwon.core.MarkwonTheme;
import jp.wasabeef.glide.transformations.RoundedCornersTransformation;
-import me.saket.bettermovementmethod.BetterLinkMovementMethod;
import ml.docilealligator.infinityforreddit.ActivityToolbarInterface;
import ml.docilealligator.infinityforreddit.AppBarStateChangeListener;
import ml.docilealligator.infinityforreddit.Infinity;
@@ -103,6 +102,7 @@ import ml.docilealligator.infinityforreddit.events.GoBackToMainPageEvent;
import ml.docilealligator.infinityforreddit.events.SwitchAccountEvent;
import ml.docilealligator.infinityforreddit.fragments.PostFragment;
import ml.docilealligator.infinityforreddit.fragments.SidebarFragment;
+import ml.docilealligator.infinityforreddit.markdown.EvenBetterLinkMovementMethod;
import ml.docilealligator.infinityforreddit.markdown.MarkdownUtils;
import ml.docilealligator.infinityforreddit.message.ReadMessage;
import ml.docilealligator.infinityforreddit.multireddit.MultiReddit;
@@ -389,7 +389,7 @@ public class ViewSubredditDetailActivity extends BaseActivity implements SortTyp
builder.linkColor(mCustomThemeWrapper.getLinkColor());
}
};
- BetterLinkMovementMethod.OnLinkLongClickListener onLinkLongClickListener = (textView, url) -> {
+ EvenBetterLinkMovementMethod.OnLinkLongClickListener onLinkLongClickListener = (textView, url) -> {
UrlMenuBottomSheetFragment urlMenuBottomSheetFragment = UrlMenuBottomSheetFragment.newInstance(url);
urlMenuBottomSheetFragment.show(getSupportFragmentManager(), null);
return true;
@@ -400,8 +400,9 @@ public class ViewSubredditDetailActivity extends BaseActivity implements SortTyp
descriptionTextView.setOnLongClickListener(view -> {
if (description != null && !description.equals("") && descriptionTextView.getSelectionStart() == -1 && descriptionTextView.getSelectionEnd() == -1) {
CopyTextBottomSheetFragment.show(getSupportFragmentManager(), description, null);
+ return true;
}
- return true;
+ return false;
});
mSubredditViewModel = new ViewModelProvider(this,
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/ViewUserDetailActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/ViewUserDetailActivity.java
index 52fedcb7..659d0a4b 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/ViewUserDetailActivity.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/ViewUserDetailActivity.java
@@ -67,7 +67,6 @@ import io.noties.markwon.MarkwonConfiguration;
import io.noties.markwon.MarkwonPlugin;
import io.noties.markwon.core.MarkwonTheme;
import jp.wasabeef.glide.transformations.RoundedCornersTransformation;
-import me.saket.bettermovementmethod.BetterLinkMovementMethod;
import ml.docilealligator.infinityforreddit.ActivityToolbarInterface;
import ml.docilealligator.infinityforreddit.AppBarStateChangeListener;
import ml.docilealligator.infinityforreddit.DeleteThing;
@@ -100,6 +99,7 @@ import ml.docilealligator.infinityforreddit.events.GoBackToMainPageEvent;
import ml.docilealligator.infinityforreddit.events.SwitchAccountEvent;
import ml.docilealligator.infinityforreddit.fragments.CommentsListingFragment;
import ml.docilealligator.infinityforreddit.fragments.PostFragment;
+import ml.docilealligator.infinityforreddit.markdown.EvenBetterLinkMovementMethod;
import ml.docilealligator.infinityforreddit.markdown.MarkdownUtils;
import ml.docilealligator.infinityforreddit.message.ReadMessage;
import ml.docilealligator.infinityforreddit.multireddit.MultiReddit;
@@ -381,7 +381,7 @@ public class ViewUserDetailActivity extends BaseActivity implements SortTypeSele
builder.linkColor(mCustomThemeWrapper.getLinkColor());
}
};
- BetterLinkMovementMethod.OnLinkLongClickListener onLinkLongClickListener = (textView, url) -> {
+ EvenBetterLinkMovementMethod.OnLinkLongClickListener onLinkLongClickListener = (textView, url) -> {
UrlMenuBottomSheetFragment urlMenuBottomSheetFragment = UrlMenuBottomSheetFragment.newInstance(url);
urlMenuBottomSheetFragment.show(getSupportFragmentManager(), null);
return true;
@@ -391,8 +391,9 @@ public class ViewUserDetailActivity extends BaseActivity implements SortTypeSele
descriptionTextView.setOnLongClickListener(view -> {
if (description != null && !description.equals("") && descriptionTextView.getSelectionStart() == -1 && descriptionTextView.getSelectionEnd() == -1) {
CopyTextBottomSheetFragment.show(getSupportFragmentManager(), description, null);
+ return true;
}
- return true;
+ return false;
});
userViewModel = new ViewModelProvider(this, new UserViewModel.Factory(getApplication(), mRedditDataRoomDatabase, username))
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/WikiActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/WikiActivity.java
index 57ec0ff1..6372191f 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/WikiActivity.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/WikiActivity.java
@@ -41,7 +41,6 @@ import io.noties.markwon.MarkwonConfiguration;
import io.noties.markwon.MarkwonPlugin;
import io.noties.markwon.core.MarkwonTheme;
import io.noties.markwon.recycler.MarkwonAdapter;
-import me.saket.bettermovementmethod.BetterLinkMovementMethod;
import ml.docilealligator.infinityforreddit.Infinity;
import ml.docilealligator.infinityforreddit.R;
import ml.docilealligator.infinityforreddit.apis.RedditAPI;
@@ -53,6 +52,7 @@ import ml.docilealligator.infinityforreddit.customviews.SwipeLockLinearLayoutMan
import ml.docilealligator.infinityforreddit.customviews.slidr.Slidr;
import ml.docilealligator.infinityforreddit.events.ChangeNetworkStatusEvent;
import ml.docilealligator.infinityforreddit.events.SwitchAccountEvent;
+import ml.docilealligator.infinityforreddit.markdown.EvenBetterLinkMovementMethod;
import ml.docilealligator.infinityforreddit.markdown.EmoteCloseBracketInlineProcessor;
import ml.docilealligator.infinityforreddit.markdown.EmotePlugin;
import ml.docilealligator.infinityforreddit.markdown.ImageAndGifEntry;
@@ -182,7 +182,7 @@ public class WikiActivity extends BaseActivity {
builder.linkColor(linkColor);
}
};
- BetterLinkMovementMethod.OnLinkLongClickListener onLinkLongClickListener = (textView, url) -> {
+ EvenBetterLinkMovementMethod.OnLinkLongClickListener onLinkLongClickListener = (textView, url) -> {
UrlMenuBottomSheetFragment urlMenuBottomSheetFragment = UrlMenuBottomSheetFragment.newInstance(url);
urlMenuBottomSheetFragment.show(getSupportFragmentManager(), null);
return true;
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/CommentsListingRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/CommentsListingRecyclerViewAdapter.java
index 1964f7f7..9fb2b239 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/CommentsListingRecyclerViewAdapter.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/CommentsListingRecyclerViewAdapter.java
@@ -36,7 +36,6 @@ import io.noties.markwon.Markwon;
import io.noties.markwon.MarkwonConfiguration;
import io.noties.markwon.MarkwonPlugin;
import io.noties.markwon.core.MarkwonTheme;
-import me.saket.bettermovementmethod.BetterLinkMovementMethod;
import ml.docilealligator.infinityforreddit.NetworkState;
import ml.docilealligator.infinityforreddit.R;
import ml.docilealligator.infinityforreddit.SaveThing;
@@ -56,6 +55,7 @@ import ml.docilealligator.infinityforreddit.customviews.SpoilerOnClickTextView;
import ml.docilealligator.infinityforreddit.customviews.SwipeLockInterface;
import ml.docilealligator.infinityforreddit.customviews.SwipeLockLinearLayoutManager;
import ml.docilealligator.infinityforreddit.databinding.ItemCommentBinding;
+import ml.docilealligator.infinityforreddit.markdown.EvenBetterLinkMovementMethod;
import ml.docilealligator.infinityforreddit.markdown.CustomMarkwonAdapter;
import ml.docilealligator.infinityforreddit.markdown.EmoteCloseBracketInlineProcessor;
import ml.docilealligator.infinityforreddit.markdown.EmotePlugin;
@@ -173,7 +173,7 @@ public class CommentsListingRecyclerViewAdapter extends PagedListAdapter<Comment
builder.linkColor(linkColor);
}
};
- BetterLinkMovementMethod.OnLinkLongClickListener onLinkLongClickListener = (textView, url) -> {
+ EvenBetterLinkMovementMethod.OnLinkLongClickListener onLinkLongClickListener = (textView, url) -> {
if (!activity.isDestroyed() && !activity.isFinishing()) {
UrlMenuBottomSheetFragment urlMenuBottomSheetFragment = UrlMenuBottomSheetFragment.newInstance(url);
urlMenuBottomSheetFragment.show(activity.getSupportFragmentManager(), urlMenuBottomSheetFragment.getTag());
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/CommentsRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/CommentsRecyclerViewAdapter.java
index 8aa76ba7..ba0e45c0 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/CommentsRecyclerViewAdapter.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/CommentsRecyclerViewAdapter.java
@@ -44,7 +44,6 @@ import io.noties.markwon.MarkwonConfiguration;
import io.noties.markwon.MarkwonPlugin;
import io.noties.markwon.core.MarkwonTheme;
import jp.wasabeef.glide.transformations.RoundedCornersTransformation;
-import me.saket.bettermovementmethod.BetterLinkMovementMethod;
import ml.docilealligator.infinityforreddit.R;
import ml.docilealligator.infinityforreddit.SaveThing;
import ml.docilealligator.infinityforreddit.SortType;
@@ -61,13 +60,14 @@ import ml.docilealligator.infinityforreddit.comment.Comment;
import ml.docilealligator.infinityforreddit.comment.FetchComment;
import ml.docilealligator.infinityforreddit.customtheme.CustomThemeWrapper;
import ml.docilealligator.infinityforreddit.customviews.CommentIndentationView;
-import ml.docilealligator.infinityforreddit.markdown.CustomMarkwonAdapter;
import ml.docilealligator.infinityforreddit.customviews.LinearLayoutManagerBugFixed;
import ml.docilealligator.infinityforreddit.customviews.SpoilerOnClickTextView;
import ml.docilealligator.infinityforreddit.customviews.SwipeLockInterface;
import ml.docilealligator.infinityforreddit.customviews.SwipeLockLinearLayoutManager;
import ml.docilealligator.infinityforreddit.databinding.ItemCommentBinding;
import ml.docilealligator.infinityforreddit.fragments.ViewPostDetailFragment;
+import ml.docilealligator.infinityforreddit.markdown.EvenBetterLinkMovementMethod;
+import ml.docilealligator.infinityforreddit.markdown.CustomMarkwonAdapter;
import ml.docilealligator.infinityforreddit.markdown.EmoteCloseBracketInlineProcessor;
import ml.docilealligator.infinityforreddit.markdown.EmotePlugin;
import ml.docilealligator.infinityforreddit.markdown.ImageAndGifEntry;
@@ -207,7 +207,7 @@ public class CommentsRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerVi
builder.linkColor(linkColor);
}
};
- BetterLinkMovementMethod.OnLinkLongClickListener onLinkLongClickListener = (textView, url) -> {
+ EvenBetterLinkMovementMethod.OnLinkLongClickListener onLinkLongClickListener = (textView, url) -> {
if (!activity.isDestroyed() && !activity.isFinishing()) {
UrlMenuBottomSheetFragment urlMenuBottomSheetFragment = UrlMenuBottomSheetFragment.newInstance(url);
urlMenuBottomSheetFragment.show(activity.getSupportFragmentManager(), null);
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/MessageRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/MessageRecyclerViewAdapter.java
index 1eea5041..f2967d8e 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/MessageRecyclerViewAdapter.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/MessageRecyclerViewAdapter.java
@@ -28,7 +28,6 @@ import io.noties.markwon.Markwon;
import io.noties.markwon.MarkwonConfiguration;
import io.noties.markwon.core.MarkwonTheme;
import io.noties.markwon.ext.strikethrough.StrikethroughPlugin;
-import io.noties.markwon.inlineparser.AutolinkInlineProcessor;
import io.noties.markwon.inlineparser.BangInlineProcessor;
import io.noties.markwon.inlineparser.HtmlInlineProcessor;
import io.noties.markwon.inlineparser.MarkwonInlineParserPlugin;
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/PostDetailRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/PostDetailRecyclerViewAdapter.java
index a7c36f73..2afce6a5 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/PostDetailRecyclerViewAdapter.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/PostDetailRecyclerViewAdapter.java
@@ -61,7 +61,6 @@ import io.noties.markwon.MarkwonPlugin;
import io.noties.markwon.core.MarkwonTheme;
import jp.wasabeef.glide.transformations.BlurTransformation;
import jp.wasabeef.glide.transformations.RoundedCornersTransformation;
-import me.saket.bettermovementmethod.BetterLinkMovementMethod;
import ml.docilealligator.infinityforreddit.FetchGfycatOrRedgifsVideoLinks;
import ml.docilealligator.infinityforreddit.FetchStreamableVideo;
import ml.docilealligator.infinityforreddit.R;
@@ -102,6 +101,7 @@ import ml.docilealligator.infinityforreddit.databinding.ItemPostDetailVideoAndGi
import ml.docilealligator.infinityforreddit.databinding.ItemPostDetailVideoAutoplayBinding;
import ml.docilealligator.infinityforreddit.databinding.ItemPostDetailVideoAutoplayLegacyControllerBinding;
import ml.docilealligator.infinityforreddit.fragments.ViewPostDetailFragment;
+import ml.docilealligator.infinityforreddit.markdown.EvenBetterLinkMovementMethod;
import ml.docilealligator.infinityforreddit.markdown.CustomMarkwonAdapter;
import ml.docilealligator.infinityforreddit.markdown.EmoteCloseBracketInlineProcessor;
import ml.docilealligator.infinityforreddit.markdown.EmotePlugin;
@@ -221,7 +221,7 @@ public class PostDetailRecyclerViewAdapter extends RecyclerView.Adapter<Recycler
private boolean canStartActivity = true;
private boolean canPlayVideo = true;
- public PostDetailRecyclerViewAdapter(BaseActivity activity, ViewPostDetailFragment fragment,
+ public PostDetailRecyclerViewAdapter(@NonNull BaseActivity activity, ViewPostDetailFragment fragment,
Executor executor, CustomThemeWrapper customThemeWrapper,
Retrofit retrofit, Retrofit oauthRetrofit, Retrofit gfycatRetrofit,
Retrofit redgifsRetrofit, Provider<StreamableAPI> streamableApiProvider,
@@ -356,8 +356,9 @@ public class PostDetailRecyclerViewAdapter extends RecyclerView.Adapter<Recycler
mActivity.getSupportFragmentManager(),
mPost.getSelfTextPlain(), mPost.getSelfText()
);
+ return true;
}
- return true;
+ return false;
});
}
@@ -377,8 +378,8 @@ public class PostDetailRecyclerViewAdapter extends RecyclerView.Adapter<Recycler
builder.linkColor(linkColor);
}
};
- BetterLinkMovementMethod.OnLinkLongClickListener onLinkLongClickListener = (textView, url) -> {
- if (activity != null && !activity.isDestroyed() && !activity.isFinishing()) {
+ EvenBetterLinkMovementMethod.OnLinkLongClickListener onLinkLongClickListener = (textView, url) -> {
+ if (!activity.isDestroyed() && !activity.isFinishing()) {
UrlMenuBottomSheetFragment urlMenuBottomSheetFragment = new UrlMenuBottomSheetFragment();
Bundle bundle = new Bundle();
bundle.putString(UrlMenuBottomSheetFragment.EXTRA_URL, url);
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/PrivateMessagesDetailRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/PrivateMessagesDetailRecyclerViewAdapter.java
index e617340f..c4f859d4 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/PrivateMessagesDetailRecyclerViewAdapter.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/PrivateMessagesDetailRecyclerViewAdapter.java
@@ -32,7 +32,6 @@ import io.noties.markwon.Markwon;
import io.noties.markwon.MarkwonConfiguration;
import io.noties.markwon.core.MarkwonTheme;
import io.noties.markwon.ext.strikethrough.StrikethroughPlugin;
-import io.noties.markwon.inlineparser.AutolinkInlineProcessor;
import io.noties.markwon.inlineparser.BangInlineProcessor;
import io.noties.markwon.inlineparser.HtmlInlineProcessor;
import io.noties.markwon.inlineparser.MarkwonInlineParserPlugin;
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/RulesRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/RulesRecyclerViewAdapter.java
index 554e3b06..5dc4a82e 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/RulesRecyclerViewAdapter.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/RulesRecyclerViewAdapter.java
@@ -24,7 +24,6 @@ import io.noties.markwon.MarkwonConfiguration;
import io.noties.markwon.MarkwonPlugin;
import io.noties.markwon.core.MarkwonTheme;
import io.noties.markwon.recycler.MarkwonAdapter;
-import me.saket.bettermovementmethod.BetterLinkMovementMethod;
import ml.docilealligator.infinityforreddit.R;
import ml.docilealligator.infinityforreddit.Rule;
import ml.docilealligator.infinityforreddit.activities.BaseActivity;
@@ -35,6 +34,7 @@ import ml.docilealligator.infinityforreddit.customtheme.CustomThemeWrapper;
import ml.docilealligator.infinityforreddit.customviews.SwipeLockInterface;
import ml.docilealligator.infinityforreddit.customviews.SwipeLockLinearLayoutManager;
import ml.docilealligator.infinityforreddit.customviews.slidr.widget.SliderPanel;
+import ml.docilealligator.infinityforreddit.markdown.EvenBetterLinkMovementMethod;
import ml.docilealligator.infinityforreddit.markdown.EmoteCloseBracketInlineProcessor;
import ml.docilealligator.infinityforreddit.markdown.EmotePlugin;
import ml.docilealligator.infinityforreddit.markdown.ImageAndGifEntry;
@@ -87,8 +87,8 @@ public class RulesRecyclerViewAdapter extends RecyclerView.Adapter<RulesRecycler
builder.linkColor(customThemeWrapper.getLinkColor());
}
};
- BetterLinkMovementMethod.OnLinkLongClickListener onLinkLongClickListener = (textView, url) -> {
- if (activity != null && !activity.isDestroyed() && !activity.isFinishing()) {
+ EvenBetterLinkMovementMethod.OnLinkLongClickListener onLinkLongClickListener = (textView, url) -> {
+ if (!activity.isDestroyed() && !activity.isFinishing()) {
UrlMenuBottomSheetFragment urlMenuBottomSheetFragment = UrlMenuBottomSheetFragment.newInstance(url);
urlMenuBottomSheetFragment.show(activity.getSupportFragmentManager(), null);
}
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/customviews/SpoilerOnClickTextView.java b/app/src/main/java/ml/docilealligator/infinityforreddit/customviews/SpoilerOnClickTextView.java
index a34f644a..43709bbb 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/customviews/SpoilerOnClickTextView.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/customviews/SpoilerOnClickTextView.java
@@ -24,7 +24,7 @@ public class SpoilerOnClickTextView extends androidx.appcompat.widget.AppCompatT
return isSpoilerOnClick;
}
- public void setSpoilerOnClick(boolean spoilerOnClick) {
+ public void setSpoilerOnClick(boolean spoilerOnClick) {
isSpoilerOnClick = spoilerOnClick;
}
}
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/fragments/SidebarFragment.java b/app/src/main/java/ml/docilealligator/infinityforreddit/fragments/SidebarFragment.java
index a30fe3c1..a8298a92 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/fragments/SidebarFragment.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/fragments/SidebarFragment.java
@@ -35,7 +35,6 @@ import io.noties.markwon.Markwon;
import io.noties.markwon.MarkwonConfiguration;
import io.noties.markwon.MarkwonPlugin;
import io.noties.markwon.core.MarkwonTheme;
-import me.saket.bettermovementmethod.BetterLinkMovementMethod;
import ml.docilealligator.infinityforreddit.Infinity;
import ml.docilealligator.infinityforreddit.R;
import ml.docilealligator.infinityforreddit.RedditDataRoomDatabase;
@@ -46,9 +45,10 @@ import ml.docilealligator.infinityforreddit.asynctasks.InsertSubredditData;
import ml.docilealligator.infinityforreddit.bottomsheetfragments.CopyTextBottomSheetFragment;
import ml.docilealligator.infinityforreddit.bottomsheetfragments.UrlMenuBottomSheetFragment;
import ml.docilealligator.infinityforreddit.customtheme.CustomThemeWrapper;
+import ml.docilealligator.infinityforreddit.customviews.LinearLayoutManagerBugFixed;
import ml.docilealligator.infinityforreddit.events.ChangeNetworkStatusEvent;
+import ml.docilealligator.infinityforreddit.markdown.EvenBetterLinkMovementMethod;
import ml.docilealligator.infinityforreddit.markdown.CustomMarkwonAdapter;
-import ml.docilealligator.infinityforreddit.customviews.LinearLayoutManagerBugFixed;
import ml.docilealligator.infinityforreddit.markdown.EmoteCloseBracketInlineProcessor;
import ml.docilealligator.infinityforreddit.markdown.EmotePlugin;
import ml.docilealligator.infinityforreddit.markdown.ImageAndGifEntry;
@@ -153,7 +153,7 @@ public class SidebarFragment extends Fragment {
});
}
};
- BetterLinkMovementMethod.OnLinkLongClickListener onLinkLongClickListener = (textView, url) -> {
+ EvenBetterLinkMovementMethod.OnLinkLongClickListener onLinkLongClickListener = (textView, url) -> {
UrlMenuBottomSheetFragment urlMenuBottomSheetFragment = UrlMenuBottomSheetFragment.newInstance(url);
urlMenuBottomSheetFragment.show(getChildFragmentManager(), null);
return true;
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/CustomMarkwonAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/CustomMarkwonAdapter.java
index 25e63d2c..c3c84ee3 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/CustomMarkwonAdapter.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/CustomMarkwonAdapter.java
@@ -120,8 +120,18 @@ public class CustomMarkwonAdapter extends MarkwonAdapter {
entry.bindHolder(markwon, holder, node);
if (holder.itemView instanceof SpoilerOnClickTextView) {
- holder.itemView.setOnClickListener(onClickListener);
- holder.itemView.setOnLongClickListener(onLongClickListener);
+ SpoilerOnClickTextView textView = (SpoilerOnClickTextView) holder.itemView;
+ holder.itemView.setOnClickListener(view -> {
+ if (onClickListener != null && textView.getSelectionStart() == -1 && textView.getSelectionEnd() == -1) {
+ onClickListener.onClick(view);
+ }
+ });
+ holder.itemView.setOnLongClickListener(view -> {
+ if (onLongClickListener != null && textView.getSelectionStart() == -1 && textView.getSelectionEnd() == -1) {
+ return onLongClickListener.onLongClick(view);
+ }
+ return false;
+ });
} else if (holder.itemView instanceof HorizontalScrollView) {
TableLayout tableLayout = holder.itemView.findViewById(R.id.table_layout);
if (tableLayout != null) {
@@ -132,15 +142,16 @@ public class CustomMarkwonAdapter extends MarkwonAdapter {
if (tableRow.getChildAt(j) instanceof TextView) {
TextView textView = (TextView) tableRow.getChildAt(j);
tableRow.getChildAt(j).setOnClickListener(view -> {
- if (textView.getSelectionStart() == -1 && textView.getSelectionEnd() == -1) {
+ if (onClickListener != null && textView.getSelectionStart() == -1 && textView.getSelectionEnd() == -1) {
onClickListener.onClick(view);
}
});
tableRow.getChildAt(j).setOnLongClickListener(view -> {
- if (textView.getSelectionStart() == -1 && textView.getSelectionEnd() == -1) {
+ if (onLongClickListener != null && textView.getSelectionStart() == -1 && textView.getSelectionEnd() == -1) {
onLongClickListener.onLongClick(view);
+ return true;
}
- return true;
+ return false;
});
}
}
@@ -158,12 +169,12 @@ public class CustomMarkwonAdapter extends MarkwonAdapter {
if (holder instanceof ImageAndGifEntry.Holder) {
if (!((ImageAndGifEntry.Holder) holder).binding.captionTextViewMarkdownImageAndGifBlock.hasOnClickListeners()) {
((ImageAndGifEntry.Holder) holder).binding.captionTextViewMarkdownImageAndGifBlock.setOnClickListener(view -> {
- if (((ImageAndGifEntry.Holder) holder).binding.captionTextViewMarkdownImageAndGifBlock.getSelectionStart() == -1 && ((ImageAndGifEntry.Holder) holder).binding.captionTextViewMarkdownImageAndGifBlock.getSelectionEnd() == -1) {
+ if (onClickListener != null && ((ImageAndGifEntry.Holder) holder).binding.captionTextViewMarkdownImageAndGifBlock.getSelectionStart() == -1 && ((ImageAndGifEntry.Holder) holder).binding.captionTextViewMarkdownImageAndGifBlock.getSelectionEnd() == -1) {
onClickListener.onClick(view);
}
});
((ImageAndGifEntry.Holder) holder).binding.captionTextViewMarkdownImageAndGifBlock.setOnLongClickListener(view -> {
- if (((ImageAndGifEntry.Holder) holder).binding.captionTextViewMarkdownImageAndGifBlock.getSelectionStart() == -1 && ((ImageAndGifEntry.Holder) holder).binding.captionTextViewMarkdownImageAndGifBlock.getSelectionEnd() == -1) {
+ if (onLongClickListener != null && ((ImageAndGifEntry.Holder) holder).binding.captionTextViewMarkdownImageAndGifBlock.getSelectionStart() == -1 && ((ImageAndGifEntry.Holder) holder).binding.captionTextViewMarkdownImageAndGifBlock.getSelectionEnd() == -1) {
return onLongClickListener.onLongClick(view);
}
return false;
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/EvenBetterLinkMovementMethod.java b/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/EvenBetterLinkMovementMethod.java
new file mode 100644
index 00000000..d3c4909d
--- /dev/null
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/EvenBetterLinkMovementMethod.java
@@ -0,0 +1,450 @@
+package ml.docilealligator.infinityforreddit.markdown;
+
+import android.app.Activity;
+import android.graphics.RectF;
+import android.text.Layout;
+import android.text.Selection;
+import android.text.Spannable;
+import android.text.Spanned;
+import android.text.method.LinkMovementMethod;
+import android.text.style.BackgroundColorSpan;
+import android.text.style.ClickableSpan;
+import android.text.style.URLSpan;
+import android.text.util.Linkify;
+import android.view.HapticFeedbackConstants;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.widget.TextView;
+
+import ml.docilealligator.infinityforreddit.R;
+
+public class EvenBetterLinkMovementMethod extends LinkMovementMethod {
+ private static EvenBetterLinkMovementMethod singleInstance;
+ private static final int LINKIFY_NONE = -2;
+
+ private OnLinkClickListener onLinkClickListener;
+ private OnLinkLongClickListener onLinkLongClickListener;
+ private final RectF touchedLineBounds = new RectF();
+ private boolean isUrlHighlighted;
+ private ClickableSpan clickableSpanUnderTouchOnActionDown;
+ private int activeTextViewHashcode;
+ private LongPressTimer ongoingLongPressTimer;
+ private boolean wasLongPressRegistered;
+
+ public interface OnLinkClickListener {
+ /**
+ * @param textView The TextView on which a click was registered.
+ * @param url The clicked URL.
+ * @return True if this click was handled. False to let Android handle the URL.
+ */
+ boolean onClick(TextView textView, String url);
+ }
+
+ public interface OnLinkLongClickListener {
+ /**
+ * @param textView The TextView on which a long-click was registered.
+ * @param url The long-clicked URL.
+ * @return True if this long-click was handled. False to let Android handle the URL (as a short-click).
+ */
+ boolean onLongClick(TextView textView, String url);
+ }
+
+ /**
+ * Return a new instance of BetterLinkMovementMethod.
+ */
+ public static EvenBetterLinkMovementMethod newInstance() {
+ return new EvenBetterLinkMovementMethod();
+ }
+
+ /**
+ * @param linkifyMask One of {@link Linkify#ALL}, {@link Linkify#PHONE_NUMBERS}, {@link Linkify#MAP_ADDRESSES},
+ * {@link Linkify#WEB_URLS} and {@link Linkify#EMAIL_ADDRESSES}.
+ * @param textViews The TextViews on which a {@link EvenBetterLinkMovementMethod} should be registered.
+ * @return The registered {@link EvenBetterLinkMovementMethod} on the TextViews.
+ */
+ public static EvenBetterLinkMovementMethod linkify(int linkifyMask, TextView... textViews) {
+ EvenBetterLinkMovementMethod movementMethod = newInstance();
+ for (TextView textView : textViews) {
+ addLinks(linkifyMask, movementMethod, textView);
+ }
+ return movementMethod;
+ }
+
+ /**
+ * Like {@link #linkify(int, TextView...)}, but can be used for TextViews with HTML links.
+ *
+ * @param textViews The TextViews on which a {@link EvenBetterLinkMovementMethod} should be registered.
+ * @return The registered {@link EvenBetterLinkMovementMethod} on the TextViews.
+ */
+ public static EvenBetterLinkMovementMethod linkifyHtml(TextView... textViews) {
+ return linkify(LINKIFY_NONE, textViews);
+ }
+
+ /**
+ * Recursively register a {@link EvenBetterLinkMovementMethod} on every TextView inside a layout.
+ *
+ * @param linkifyMask One of {@link Linkify#ALL}, {@link Linkify#PHONE_NUMBERS}, {@link Linkify#MAP_ADDRESSES},
+ * {@link Linkify#WEB_URLS} and {@link Linkify#EMAIL_ADDRESSES}.
+ * @return The registered {@link EvenBetterLinkMovementMethod} on the TextViews.
+ */
+ public static EvenBetterLinkMovementMethod linkify(int linkifyMask, ViewGroup viewGroup) {
+ EvenBetterLinkMovementMethod movementMethod = newInstance();
+ rAddLinks(linkifyMask, viewGroup, movementMethod);
+ return movementMethod;
+ }
+
+ /**
+ * Like {@link #linkify(int, TextView...)}, but can be used for TextViews with HTML links.
+ *
+ * @return The registered {@link EvenBetterLinkMovementMethod} on the TextViews.
+ */
+ @SuppressWarnings("unused")
+ public static EvenBetterLinkMovementMethod linkifyHtml(ViewGroup viewGroup) {
+ return linkify(LINKIFY_NONE, viewGroup);
+ }
+
+ /**
+ * Recursively register a {@link EvenBetterLinkMovementMethod} on every TextView inside a layout.
+ *
+ * @param linkifyMask One of {@link Linkify#ALL}, {@link Linkify#PHONE_NUMBERS}, {@link Linkify#MAP_ADDRESSES},
+ * {@link Linkify#WEB_URLS} and {@link Linkify#EMAIL_ADDRESSES}.
+ * @return The registered {@link EvenBetterLinkMovementMethod} on the TextViews.
+ */
+ public static EvenBetterLinkMovementMethod linkify(int linkifyMask, Activity activity) {
+ // Find the layout passed to setContentView().
+ ViewGroup activityLayout = ((ViewGroup) ((ViewGroup) activity.findViewById(Window.ID_ANDROID_CONTENT)).getChildAt(0));
+
+ EvenBetterLinkMovementMethod movementMethod = newInstance();
+ rAddLinks(linkifyMask, activityLayout, movementMethod);
+ return movementMethod;
+ }
+
+ /**
+ * Like {@link #linkify(int, TextView...)}, but can be used for TextViews with HTML links.
+ *
+ * @return The registered {@link EvenBetterLinkMovementMethod} on the TextViews.
+ */
+ @SuppressWarnings("unused")
+ public static EvenBetterLinkMovementMethod linkifyHtml(Activity activity) {
+ return linkify(LINKIFY_NONE, activity);
+ }
+
+ /**
+ * Get a static instance of BetterLinkMovementMethod. Do note that registering a click listener on the returned
+ * instance is not supported because it will potentially be shared on multiple TextViews.
+ */
+ @SuppressWarnings("unused")
+ public static EvenBetterLinkMovementMethod getInstance() {
+ if (singleInstance == null) {
+ singleInstance = new EvenBetterLinkMovementMethod();
+ }
+ return singleInstance;
+ }
+
+ protected EvenBetterLinkMovementMethod() {
+ }
+
+ /**
+ * Set a listener that will get called whenever any link is clicked on the TextView.
+ */
+ public EvenBetterLinkMovementMethod setOnLinkClickListener(OnLinkClickListener clickListener) {
+ if (this == singleInstance) {
+ throw new UnsupportedOperationException("Setting a click listener on the instance returned by getInstance() is not supported to avoid memory " +
+ "leaks. Please use newInstance() or any of the linkify() methods instead.");
+ }
+
+ this.onLinkClickListener = clickListener;
+ return this;
+ }
+
+ /**
+ * Set a listener that will get called whenever any link is clicked on the TextView.
+ */
+ public EvenBetterLinkMovementMethod setOnLinkLongClickListener(OnLinkLongClickListener longClickListener) {
+ if (this == singleInstance) {
+ throw new UnsupportedOperationException("Setting a long-click listener on the instance returned by getInstance() is not supported to avoid " +
+ "memory leaks. Please use newInstance() or any of the linkify() methods instead.");
+ }
+
+ this.onLinkLongClickListener = longClickListener;
+ return this;
+ }
+
+// ======== PUBLIC APIs END ======== //
+
+ private static void rAddLinks(int linkifyMask, ViewGroup viewGroup, EvenBetterLinkMovementMethod movementMethod) {
+ for (int i = 0; i < viewGroup.getChildCount(); i++) {
+ View child = viewGroup.getChildAt(i);
+
+ if (child instanceof ViewGroup) {
+ // Recursively find child TextViews.
+ rAddLinks(linkifyMask, ((ViewGroup) child), movementMethod);
+
+ } else if (child instanceof TextView) {
+ TextView textView = (TextView) child;
+ addLinks(linkifyMask, movementMethod, textView);
+ }
+ }
+ }
+
+ private static void addLinks(int linkifyMask, EvenBetterLinkMovementMethod movementMethod, TextView textView) {
+ textView.setMovementMethod(movementMethod);
+ if (linkifyMask != LINKIFY_NONE) {
+ Linkify.addLinks(textView, linkifyMask);
+ }
+ }
+
+ @Override
+ public boolean onTouchEvent(final TextView textView, Spannable text, MotionEvent event) {
+ if (activeTextViewHashcode != textView.hashCode()) {
+ // Bug workaround: TextView stops calling onTouchEvent() once any URL is highlighted.
+ // A hacky solution is to reset any "autoLink" property set in XML. But we also want
+ // to do this once per TextView.
+ activeTextViewHashcode = textView.hashCode();
+ textView.setAutoLinkMask(0);
+ }
+
+ final ClickableSpan clickableSpanUnderTouch = findClickableSpanUnderTouch(textView, text, event);
+ if (event.getAction() == MotionEvent.ACTION_DOWN) {
+ clickableSpanUnderTouchOnActionDown = clickableSpanUnderTouch;
+ }
+ final boolean touchStartedOverAClickableSpan = clickableSpanUnderTouchOnActionDown != null;
+
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ if (clickableSpanUnderTouch != null) {
+ highlightUrl(textView, clickableSpanUnderTouch, text);
+ }
+
+ if (touchStartedOverAClickableSpan && onLinkLongClickListener != null) {
+ LongPressTimer.OnTimerReachedListener longClickListener = new LongPressTimer.OnTimerReachedListener() {
+ @Override
+ public void onTimerReached() {
+ wasLongPressRegistered = true;
+ removeUrlHighlightColor(textView);
+ if (dispatchUrlLongClick(textView, clickableSpanUnderTouch)) {
+ textView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+ }
+ }
+ };
+ startTimerForRegisteringLongClick(textView, longClickListener);
+ }
+ return touchStartedOverAClickableSpan;
+
+ case MotionEvent.ACTION_UP:
+ // Register a click only if the touch started and ended on the same URL.
+ if (!wasLongPressRegistered && touchStartedOverAClickableSpan && clickableSpanUnderTouch == clickableSpanUnderTouchOnActionDown) {
+ dispatchUrlClick(textView, clickableSpanUnderTouch);
+ }
+ cleanupOnTouchUp(textView);
+
+ // Consume this event even if we could not find any spans to avoid letting Android handle this event.
+ // Android's TextView implementation has a bug where links get clicked even when there is no more text
+ // next to the link and the touch lies outside its bounds in the same direction.
+ return touchStartedOverAClickableSpan;
+
+ case MotionEvent.ACTION_CANCEL:
+ cleanupOnTouchUp(textView);
+ return false;
+
+ case MotionEvent.ACTION_MOVE:
+ // Stop listening for a long-press as soon as the user wanders off to unknown lands.
+ if (clickableSpanUnderTouch != clickableSpanUnderTouchOnActionDown) {
+ removeLongPressCallback(textView);
+ }
+
+ if (!wasLongPressRegistered) {
+ // Toggle highlight.
+ if (clickableSpanUnderTouch != null) {
+ highlightUrl(textView, clickableSpanUnderTouch, text);
+ } else {
+ removeUrlHighlightColor(textView);
+ }
+ }
+
+ return touchStartedOverAClickableSpan;
+
+ default:
+ return false;
+ }
+ }
+
+ private void cleanupOnTouchUp(TextView textView) {
+ wasLongPressRegistered = false;
+ clickableSpanUnderTouchOnActionDown = null;
+ removeUrlHighlightColor(textView);
+ removeLongPressCallback(textView);
+ }
+
+ /**
+ * Determines the touched location inside the TextView's text and returns the ClickableSpan found under it (if any).
+ *
+ * @return The touched ClickableSpan or null.
+ */
+ protected ClickableSpan findClickableSpanUnderTouch(TextView textView, Spannable text, MotionEvent event) {
+ // So we need to find the location in text where touch was made, regardless of whether the TextView
+ // has scrollable text. That is, not the entire text is currently visible.
+ int touchX = (int) event.getX();
+ int touchY = (int) event.getY();
+
+ // Ignore padding.
+ touchX -= textView.getTotalPaddingLeft();
+ touchY -= textView.getTotalPaddingTop();
+
+ // Account for scrollable text.
+ touchX += textView.getScrollX();
+ touchY += textView.getScrollY();
+
+ final Layout layout = textView.getLayout();
+ final int touchedLine = layout.getLineForVertical(touchY);
+ final int touchOffset = layout.getOffsetForHorizontal(touchedLine, touchX);
+
+ touchedLineBounds.left = layout.getLineLeft(touchedLine);
+ touchedLineBounds.top = layout.getLineTop(touchedLine);
+ touchedLineBounds.right = layout.getLineWidth(touchedLine) + touchedLineBounds.left;
+ touchedLineBounds.bottom = layout.getLineBottom(touchedLine);
+
+ if (touchedLineBounds.contains(touchX, touchY)) {
+ // Find a ClickableSpan that lies under the touched area.
+ final Object[] spans = text.getSpans(touchOffset, touchOffset, ClickableSpan.class);
+ for (final Object span : spans) {
+ if (span instanceof ClickableSpan) {
+ return (ClickableSpan) span;
+ }
+ }
+ // No ClickableSpan found under the touched location.
+ return null;
+
+ } else {
+ // Touch lies outside the line's horizontal bounds where no spans should exist.
+ return null;
+ }
+ }
+
+ /**
+ * Adds a background color span at <var>clickableSpan</var>'s location.
+ */
+ protected void highlightUrl(TextView textView, ClickableSpan clickableSpan, Spannable text) {
+ if (isUrlHighlighted) {
+ return;
+ }
+ isUrlHighlighted = true;
+
+ int spanStart = text.getSpanStart(clickableSpan);
+ int spanEnd = text.getSpanEnd(clickableSpan);
+ BackgroundColorSpan highlightSpan = new BackgroundColorSpan(textView.getHighlightColor());
+ text.setSpan(highlightSpan, spanStart, spanEnd, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
+
+ textView.setTag(R.id.bettermovementmethod_highlight_background_span, highlightSpan);
+
+ Selection.setSelection(text, spanStart, spanEnd);
+ }
+
+ /**
+ * Removes the highlight color under the Url.
+ */
+ protected void removeUrlHighlightColor(TextView textView) {
+ if (!isUrlHighlighted) {
+ return;
+ }
+ isUrlHighlighted = false;
+
+ Spannable text = (Spannable) textView.getText();
+ BackgroundColorSpan highlightSpan = (BackgroundColorSpan) textView.getTag(R.id.bettermovementmethod_highlight_background_span);
+ text.removeSpan(highlightSpan);
+
+ Selection.removeSelection(text);
+ }
+
+ protected void startTimerForRegisteringLongClick(TextView textView, LongPressTimer.OnTimerReachedListener longClickListener) {
+ ongoingLongPressTimer = new LongPressTimer();
+ ongoingLongPressTimer.setOnTimerReachedListener(longClickListener);
+ textView.postDelayed(ongoingLongPressTimer, ViewConfiguration.getLongPressTimeout());
+ }
+
+ /**
+ * Remove the long-press detection timer.
+ */
+ protected void removeLongPressCallback(TextView textView) {
+ if (ongoingLongPressTimer != null) {
+ textView.removeCallbacks(ongoingLongPressTimer);
+ ongoingLongPressTimer = null;
+ }
+ }
+
+ protected void dispatchUrlClick(TextView textView, ClickableSpan clickableSpan) {
+ ClickableSpanWithText clickableSpanWithText = ClickableSpanWithText.ofSpan(textView, clickableSpan);
+ boolean handled = onLinkClickListener != null && onLinkClickListener.onClick(textView, clickableSpanWithText.text());
+
+ if (!handled) {
+ // Let Android handle this click.
+ clickableSpanWithText.span().onClick(textView);
+ }
+ }
+
+ protected boolean dispatchUrlLongClick(TextView textView, ClickableSpan clickableSpan) {
+ ClickableSpanWithText clickableSpanWithText = ClickableSpanWithText.ofSpan(textView, clickableSpan);
+ boolean handled = onLinkLongClickListener != null && onLinkLongClickListener.onLongClick(textView, clickableSpanWithText.text());
+
+ if (!handled) {
+ // Let Android handle this long click as a short-click.
+ clickableSpanWithText.span().onClick(textView);
+ }
+
+ return true;
+ }
+
+ protected static final class LongPressTimer implements Runnable {
+ private LongPressTimer.OnTimerReachedListener onTimerReachedListener;
+
+ protected interface OnTimerReachedListener {
+ void onTimerReached();
+ }
+
+ @Override
+ public void run() {
+ onTimerReachedListener.onTimerReached();
+ }
+
+ public void setOnTimerReachedListener(LongPressTimer.OnTimerReachedListener listener) {
+ onTimerReachedListener = listener;
+ }
+ }
+
+ /**
+ * A wrapper to support all {@link ClickableSpan}s that may or may not provide URLs.
+ */
+ protected static class ClickableSpanWithText {
+ private ClickableSpan span;
+ private String text;
+
+ protected static ClickableSpanWithText ofSpan(TextView textView, ClickableSpan span) {
+ Spanned s = (Spanned) textView.getText();
+ String text;
+ if (span instanceof URLSpan) {
+ text = ((URLSpan) span).getURL();
+ } else {
+ int start = s.getSpanStart(span);
+ int end = s.getSpanEnd(span);
+ text = s.subSequence(start, end).toString();
+ }
+ return new ClickableSpanWithText(span, text);
+ }
+
+ protected ClickableSpanWithText(ClickableSpan span, String text) {
+ this.span = span;
+ this.text = text;
+ }
+
+ protected ClickableSpan span() {
+ return span;
+ }
+
+ protected String text() {
+ return text;
+ }
+ }
+}
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/MarkdownUtils.java b/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/MarkdownUtils.java
index 45e6f384..b9b906fd 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/MarkdownUtils.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/MarkdownUtils.java
@@ -19,7 +19,6 @@ import io.noties.markwon.linkify.LinkifyPlugin;
import io.noties.markwon.movement.MovementMethodPlugin;
import io.noties.markwon.recycler.table.TableEntry;
import io.noties.markwon.recycler.table.TableEntryPlugin;
-import me.saket.bettermovementmethod.BetterLinkMovementMethod;
import ml.docilealligator.infinityforreddit.R;
public class MarkdownUtils {
@@ -35,7 +34,7 @@ public class MarkdownUtils {
@NonNull ImageAndGifPlugin imageAndGifPlugin,
int markdownColor,
int spoilerBackgroundColor,
- @Nullable BetterLinkMovementMethod.OnLinkLongClickListener onLinkLongClickListener) {
+ @Nullable EvenBetterLinkMovementMethod.OnLinkLongClickListener onLinkLongClickListener) {
return Markwon.builder(context)
.usePlugin(MarkwonInlineParserPlugin.create(plugin -> {
plugin.excludeInlineProcessor(HtmlInlineProcessor.class);
@@ -60,7 +59,7 @@ public class MarkdownUtils {
@NonNull
public static Markwon createDescriptionMarkwon(Context context, MarkwonPlugin miscPlugin,
- BetterLinkMovementMethod.OnLinkLongClickListener onLinkLongClickListener) {
+ EvenBetterLinkMovementMethod.OnLinkLongClickListener onLinkLongClickListener) {
return Markwon.builder(context)
.usePlugin(MarkwonInlineParserPlugin.create(plugin -> {
plugin.excludeInlineProcessor(HtmlInlineProcessor.class);
@@ -84,14 +83,14 @@ public class MarkdownUtils {
@NonNull
public static Markwon createLinksOnlyMarkwon(@NonNull Context context,
@NonNull MarkwonPlugin miscPlugin,
- @Nullable BetterLinkMovementMethod.OnLinkLongClickListener onLinkLongClickListener) {
+ @Nullable EvenBetterLinkMovementMethod.OnLinkLongClickListener onLinkLongClickListener) {
return Markwon.builder(context)
.usePlugin(MarkwonInlineParserPlugin.create(plugin -> {
plugin.excludeInlineProcessor(HtmlInlineProcessor.class);
plugin.excludeInlineProcessor(BangInlineProcessor.class);
}))
.usePlugin(miscPlugin)
- .usePlugin(MovementMethodPlugin.create(BetterLinkMovementMethod.newInstance().setOnLinkLongClickListener(onLinkLongClickListener)))
+ .usePlugin(MovementMethodPlugin.create(EvenBetterLinkMovementMethod.newInstance().setOnLinkLongClickListener(onLinkLongClickListener)))
.usePlugin(LinkifyPlugin.create(Linkify.WEB_URLS))
.build();
}
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SpoilerAwareMovementMethod.java b/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SpoilerAwareMovementMethod.java
index 1b343e6a..4ff7dcf9 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SpoilerAwareMovementMethod.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SpoilerAwareMovementMethod.java
@@ -10,12 +10,10 @@ import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import me.saket.bettermovementmethod.BetterLinkMovementMethod;
-
/**
- * Extension of {@link BetterLinkMovementMethod} that handles {@link SpoilerSpan}s
+ * Extension of {@link EvenBetterLinkMovementMethod} that handles {@link SpoilerSpan}s
*/
-public class SpoilerAwareMovementMethod extends BetterLinkMovementMethod {
+public class SpoilerAwareMovementMethod extends EvenBetterLinkMovementMethod {
private final RectF touchedLineBounds = new RectF();
@Override
@@ -85,12 +83,12 @@ public class SpoilerAwareMovementMethod extends BetterLinkMovementMethod {
}
@Override
- protected void dispatchUrlLongClick(TextView textView, ClickableSpan clickableSpan) {
+ protected boolean dispatchUrlLongClick(TextView textView, ClickableSpan clickableSpan) {
if (clickableSpan instanceof SpoilerSpan) {
((SpoilerSpan) clickableSpan).onLongClick(textView);
- return;
+ return false;
}
- super.dispatchUrlLongClick(textView, clickableSpan);
+ return super.dispatchUrlLongClick(textView, clickableSpan);
}
@Override
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SpoilerSpan.java b/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SpoilerSpan.java
index 6651867b..9a63ae24 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SpoilerSpan.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SpoilerSpan.java
@@ -8,8 +8,6 @@ import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
-import androidx.transition.AutoTransition;
-import androidx.transition.TransitionManager;
import ml.docilealligator.infinityforreddit.customviews.SpoilerOnClickTextView;