From 966bac159702a1fc648d8448f58f5a2138ebb346 Mon Sep 17 00:00:00 2001 From: Docile-Alligator <25734209+Docile-Alligator@users.noreply.github.com> Date: Mon, 27 Nov 2023 12:56:44 -0500 Subject: Hide images and gifs in ImageAndGifEntry and EmotePlugin if corresponding data saving settings are enabled. --- .../activities/CommentActivity.java | 6 +- .../activities/FullMarkdownActivity.java | 6 +- .../infinityforreddit/activities/WikiActivity.java | 5 +- .../CommentsListingRecyclerViewAdapter.java | 9 +- .../adapters/CommentsRecyclerViewAdapter.java | 7 +- .../adapters/PostDetailRecyclerViewAdapter.java | 9 +- .../adapters/RulesRecyclerViewAdapter.java | 5 +- .../customviews/CustomMarkwonAdapter.java | 253 ------------------- .../fragments/SidebarFragment.java | 7 +- .../markdown/CustomMarkwonAdapter.java | 269 +++++++++++++++++++++ .../infinityforreddit/markdown/EmotePlugin.java | 20 +- .../markdown/ImageAndGifEntry.java | 48 +++- .../infinityforreddit/markdown/MarkdownUtils.java | 4 +- 13 files changed, 370 insertions(+), 278 deletions(-) delete mode 100644 app/src/main/java/ml/docilealligator/infinityforreddit/customviews/CustomMarkwonAdapter.java create mode 100644 app/src/main/java/ml/docilealligator/infinityforreddit/markdown/CustomMarkwonAdapter.java (limited to 'app/src/main/java/ml') diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/CommentActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/CommentActivity.java index 9ff5cf9c..a6af969e 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/CommentActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/CommentActivity.java @@ -60,11 +60,12 @@ import ml.docilealligator.infinityforreddit.bottomsheetfragments.UploadedImagesB import ml.docilealligator.infinityforreddit.comment.Comment; import ml.docilealligator.infinityforreddit.comment.SendComment; import ml.docilealligator.infinityforreddit.customtheme.CustomThemeWrapper; -import ml.docilealligator.infinityforreddit.customviews.CustomMarkwonAdapter; +import ml.docilealligator.infinityforreddit.markdown.CustomMarkwonAdapter; import ml.docilealligator.infinityforreddit.customviews.LinearLayoutManagerBugFixed; import ml.docilealligator.infinityforreddit.databinding.ActivityCommentBinding; import ml.docilealligator.infinityforreddit.events.SwitchAccountEvent; import ml.docilealligator.infinityforreddit.markdown.EmoteCloseBracketInlineProcessor; +import ml.docilealligator.infinityforreddit.markdown.EmotePlugin; import ml.docilealligator.infinityforreddit.markdown.ImageAndGifEntry; import ml.docilealligator.infinityforreddit.markdown.ImageAndGifPlugin; import ml.docilealligator.infinityforreddit.markdown.MarkdownUtils; @@ -214,9 +215,10 @@ public class CommentActivity extends BaseActivity implements UploadImageEnabledA } }; EmoteCloseBracketInlineProcessor emoteCloseBracketInlineProcessor = new EmoteCloseBracketInlineProcessor(); + EmotePlugin emotePlugin = EmotePlugin.create(this); ImageAndGifPlugin imageAndGifPlugin = new ImageAndGifPlugin(); Markwon postBodyMarkwon = MarkdownUtils.createFullRedditMarkwon(this, - miscPlugin, emoteCloseBracketInlineProcessor, imageAndGifPlugin, parentTextColor, + miscPlugin, emoteCloseBracketInlineProcessor, emotePlugin, imageAndGifPlugin, parentTextColor, parentSpoilerBackgroundColor, null); CustomMarkwonAdapter markwonAdapter = MarkdownUtils.createCustomTablesAdapter(new ImageAndGifEntry(this, mGlide, mediaMetadata -> { Intent imageIntent = new Intent(this, ViewImageOrGifActivity.class); diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/FullMarkdownActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/FullMarkdownActivity.java index 3897323b..33363ec3 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/FullMarkdownActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/FullMarkdownActivity.java @@ -38,13 +38,14 @@ import io.noties.markwon.core.MarkwonTheme; import ml.docilealligator.infinityforreddit.Infinity; import ml.docilealligator.infinityforreddit.R; import ml.docilealligator.infinityforreddit.customtheme.CustomThemeWrapper; -import ml.docilealligator.infinityforreddit.customviews.CustomMarkwonAdapter; +import ml.docilealligator.infinityforreddit.markdown.CustomMarkwonAdapter; import ml.docilealligator.infinityforreddit.customviews.LinearLayoutManagerBugFixed; import ml.docilealligator.infinityforreddit.customviews.SwipeLockInterface; import ml.docilealligator.infinityforreddit.customviews.SwipeLockLinearLayoutManager; import ml.docilealligator.infinityforreddit.customviews.slidr.Slidr; import ml.docilealligator.infinityforreddit.events.SwitchAccountEvent; import ml.docilealligator.infinityforreddit.markdown.EmoteCloseBracketInlineProcessor; +import ml.docilealligator.infinityforreddit.markdown.EmotePlugin; import ml.docilealligator.infinityforreddit.markdown.ImageAndGifEntry; import ml.docilealligator.infinityforreddit.markdown.ImageAndGifPlugin; import ml.docilealligator.infinityforreddit.markdown.MarkdownUtils; @@ -143,9 +144,10 @@ public class FullMarkdownActivity extends BaseActivity { } }; EmoteCloseBracketInlineProcessor emoteCloseBracketInlineProcessor = new EmoteCloseBracketInlineProcessor(); + EmotePlugin emotePlugin = EmotePlugin.create(this); ImageAndGifPlugin imageAndGifPlugin = new ImageAndGifPlugin(); Markwon markwon = MarkdownUtils.createFullRedditMarkwon(this, - miscPlugin, emoteCloseBracketInlineProcessor, imageAndGifPlugin, markdownColor, + miscPlugin, emoteCloseBracketInlineProcessor, emotePlugin, imageAndGifPlugin, markdownColor, spoilerBackgroundColor, null); CustomMarkwonAdapter markwonAdapter = MarkdownUtils.createCustomTablesAdapter(new ImageAndGifEntry(this, 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 5d31f2f0..cd2f9526 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/WikiActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/WikiActivity.java @@ -53,6 +53,7 @@ import ml.docilealligator.infinityforreddit.customviews.SwipeLockLinearLayoutMan import ml.docilealligator.infinityforreddit.customviews.slidr.Slidr; import ml.docilealligator.infinityforreddit.events.SwitchAccountEvent; import ml.docilealligator.infinityforreddit.markdown.EmoteCloseBracketInlineProcessor; +import ml.docilealligator.infinityforreddit.markdown.EmotePlugin; import ml.docilealligator.infinityforreddit.markdown.ImageAndGifEntry; import ml.docilealligator.infinityforreddit.markdown.ImageAndGifPlugin; import ml.docilealligator.infinityforreddit.markdown.MarkdownUtils; @@ -100,6 +101,7 @@ public class WikiActivity extends BaseActivity { private String wikiMarkdown; private String mSubredditName; private EmoteCloseBracketInlineProcessor emoteCloseBracketInlineProcessor; + private EmotePlugin emotePlugin; private ImageAndGifPlugin imageAndGifPlugin; private Markwon markwon; private MarkwonAdapter markwonAdapter; @@ -184,9 +186,10 @@ public class WikiActivity extends BaseActivity { return true; }; emoteCloseBracketInlineProcessor = new EmoteCloseBracketInlineProcessor(); + emotePlugin = EmotePlugin.create(this); imageAndGifPlugin = new ImageAndGifPlugin(); markwon = MarkdownUtils.createFullRedditMarkwon(this, - miscPlugin, emoteCloseBracketInlineProcessor, imageAndGifPlugin, markdownColor, spoilerBackgroundColor, onLinkLongClickListener); + miscPlugin, emoteCloseBracketInlineProcessor, emotePlugin, imageAndGifPlugin, markdownColor, spoilerBackgroundColor, onLinkLongClickListener); markwonAdapter = MarkdownUtils.createCustomTablesAdapter(new ImageAndGifEntry(this, mGlide, mediaMetadata -> { 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 f9a445dd..ce979f78 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/CommentsListingRecyclerViewAdapter.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/CommentsListingRecyclerViewAdapter.java @@ -52,13 +52,14 @@ import ml.docilealligator.infinityforreddit.bottomsheetfragments.UrlMenuBottomSh import ml.docilealligator.infinityforreddit.comment.Comment; import ml.docilealligator.infinityforreddit.customtheme.CustomThemeWrapper; import ml.docilealligator.infinityforreddit.customviews.CommentIndentationView; -import ml.docilealligator.infinityforreddit.customviews.CustomMarkwonAdapter; +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.markdown.EmoteCloseBracketInlineProcessor; +import ml.docilealligator.infinityforreddit.markdown.EmotePlugin; import ml.docilealligator.infinityforreddit.markdown.ImageAndGifEntry; import ml.docilealligator.infinityforreddit.markdown.ImageAndGifPlugin; import ml.docilealligator.infinityforreddit.markdown.MarkdownUtils; @@ -86,6 +87,7 @@ public class CommentsListingRecyclerViewAdapter extends PagedListAdapter { if (!activity.isDestroyed() && !activity.isFinishing()) { UrlMenuBottomSheetFragment urlMenuBottomSheetFragment = UrlMenuBottomSheetFragment.newInstance(url); - urlMenuBottomSheetFragment.show(activity.getSupportFragmentManager(), null); + urlMenuBottomSheetFragment.show(activity.getSupportFragmentManager(), urlMenuBottomSheetFragment.getTag()); } return true; }; mEmoteCloseBracketInlineProcessor = new EmoteCloseBracketInlineProcessor(); + mEmotePlugin = EmotePlugin.create(activity); mImageAndGifPlugin = new ImageAndGifPlugin(); mMarkwon = MarkdownUtils.createFullRedditMarkwon(mActivity, - miscPlugin, mEmoteCloseBracketInlineProcessor, mImageAndGifPlugin, mCommentColor, + miscPlugin, mEmoteCloseBracketInlineProcessor, mEmotePlugin, mImageAndGifPlugin, mCommentColor, commentSpoilerBackgroundColor, onLinkLongClickListener); mImageAndGifEntry = new ImageAndGifEntry(activity, Glide.with(activity), new ImageAndGifEntry.OnItemClickListener() { @Override 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 85e03845..454d5398 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/CommentsRecyclerViewAdapter.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/CommentsRecyclerViewAdapter.java @@ -61,7 +61,7 @@ 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.customviews.CustomMarkwonAdapter; +import ml.docilealligator.infinityforreddit.markdown.CustomMarkwonAdapter; import ml.docilealligator.infinityforreddit.customviews.LinearLayoutManagerBugFixed; import ml.docilealligator.infinityforreddit.customviews.SpoilerOnClickTextView; import ml.docilealligator.infinityforreddit.customviews.SwipeLockInterface; @@ -69,6 +69,7 @@ import ml.docilealligator.infinityforreddit.customviews.SwipeLockLinearLayoutMan import ml.docilealligator.infinityforreddit.databinding.ItemCommentBinding; import ml.docilealligator.infinityforreddit.fragments.ViewPostDetailFragment; import ml.docilealligator.infinityforreddit.markdown.EmoteCloseBracketInlineProcessor; +import ml.docilealligator.infinityforreddit.markdown.EmotePlugin; import ml.docilealligator.infinityforreddit.markdown.ImageAndGifEntry; import ml.docilealligator.infinityforreddit.markdown.ImageAndGifPlugin; import ml.docilealligator.infinityforreddit.markdown.MarkdownUtils; @@ -98,6 +99,7 @@ public class CommentsRecyclerViewAdapter extends RecyclerView.Adapter { Intent intent = new Intent(activity, ViewImageOrGifActivity.class); 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 ed55fe62..9c6457ec 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/RulesRecyclerViewAdapter.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/RulesRecyclerViewAdapter.java @@ -36,6 +36,7 @@ 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.EmoteCloseBracketInlineProcessor; +import ml.docilealligator.infinityforreddit.markdown.EmotePlugin; import ml.docilealligator.infinityforreddit.markdown.ImageAndGifEntry; import ml.docilealligator.infinityforreddit.markdown.ImageAndGifPlugin; import ml.docilealligator.infinityforreddit.markdown.MarkdownUtils; @@ -43,6 +44,7 @@ import ml.docilealligator.infinityforreddit.markdown.MarkdownUtils; public class RulesRecyclerViewAdapter extends RecyclerView.Adapter { private BaseActivity activity; private EmoteCloseBracketInlineProcessor emoteCloseBracketInlineProcessor; + private EmotePlugin emotePlugin; private ImageAndGifPlugin imageAndGifPlugin; private Markwon markwon; @Nullable @@ -92,9 +94,10 @@ public class RulesRecyclerViewAdapter extends RecyclerView.Adapter> entries; - private final Entry defaultEntry; - private final MarkwonReducer reducer; - - private LayoutInflater layoutInflater; - - private Markwon markwon; - private List nodes; - - private View.OnClickListener onClickListener; - private View.OnLongClickListener onLongClickListener; - - @SuppressWarnings("WeakerAccess") - CustomMarkwonAdapter( - @NonNull SparseArray> entries, - @NonNull Entry defaultEntry, - @NonNull MarkwonReducer reducer) { - this.entries = entries; - this.defaultEntry = defaultEntry; - this.reducer = reducer; - - setHasStableIds(true); - } - - public void setOnClickListener(View.OnClickListener onClickListener) { - this.onClickListener = onClickListener; - } - - public void setOnLongClickListener(View.OnLongClickListener onLongClickListener) { - this.onLongClickListener = onLongClickListener; - } - - @NonNull - public static CustomBuilderImpl builder( - @LayoutRes int defaultEntryLayoutResId, - @IdRes int defaultEntryTextViewResId - ) { - return builder(SimpleEntry.create(defaultEntryLayoutResId, defaultEntryTextViewResId)); - } - - @NonNull - public static CustomBuilderImpl builder(@NonNull Entry defaultEntry) { - //noinspection unchecked - return new CustomBuilderImpl((Entry) defaultEntry); - } - - @Override - public void setMarkdown(@NonNull Markwon markwon, @NonNull String markdown) { - setParsedMarkdown(markwon, markwon.parse(markdown)); - } - - @Override - public void setParsedMarkdown(@NonNull Markwon markwon, @NonNull Node document) { - setParsedMarkdown(markwon, reducer.reduce(document)); - } - - @Override - public void setParsedMarkdown(@NonNull Markwon markwon, @NonNull List nodes) { - // clear all entries before applying - - defaultEntry.clear(); - - for (int i = 0, size = entries.size(); i < size; i++) { - entries.valueAt(i).clear(); - } - - this.markwon = markwon; - this.nodes = nodes; - } - - @NonNull - @Override - public Holder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - - if (layoutInflater == null) { - layoutInflater = LayoutInflater.from(parent.getContext()); - } - - final Entry entry = getEntry(viewType); - - return entry.createHolder(layoutInflater, parent); - } - - @Override - public void onBindViewHolder(@NonNull Holder holder, int position) { - - final Node node = nodes.get(position); - final int viewType = getNodeViewType(node.getClass()); - - final Entry entry = getEntry(viewType); - - entry.bindHolder(markwon, holder, node); - - if (holder.itemView instanceof SpoilerOnClickTextView) { - holder.itemView.setOnClickListener(onClickListener); - holder.itemView.setOnLongClickListener(onLongClickListener); - } else if (holder.itemView instanceof HorizontalScrollView) { - TableLayout tableLayout = holder.itemView.findViewById(R.id.table_layout); - if (tableLayout != null) { - for (int i = 0; i < tableLayout.getChildCount(); i++) { - if (tableLayout.getChildAt(i) instanceof TableRow) { - TableRow tableRow = ((TableRow) tableLayout.getChildAt(i)); - for (int j = 0; j < tableRow.getChildCount(); j++) { - if (tableRow.getChildAt(j) instanceof TextView) { - TextView textView = (TextView) tableRow.getChildAt(j); - tableRow.getChildAt(j).setOnClickListener(view -> { - if (textView.getSelectionStart() == -1 && textView.getSelectionEnd() == -1) { - onClickListener.onClick(view); - } - }); - tableRow.getChildAt(j).setOnLongClickListener(view -> { - if (textView.getSelectionStart() == -1 && textView.getSelectionEnd() == -1) { - onLongClickListener.onLongClick(view); - } - return true; - }); - } - } - } - } - } - } - - if (node instanceof ImageAndGifBlock) { - if (!holder.itemView.hasOnClickListeners()) { - holder.itemView.setOnClickListener(onClickListener); - } - holder.itemView.setOnLongClickListener(onLongClickListener); - } - } - - @Override - public int getItemCount() { - return nodes != null - ? nodes.size() - : 0; - } - - @Override - public void onViewRecycled(@NonNull Holder holder) { - super.onViewRecycled(holder); - - final Entry entry = getEntry(holder.getItemViewType()); - entry.onViewRecycled(holder); - } - - @SuppressWarnings("unused") - @NonNull - public List getItems() { - return nodes != null - ? Collections.unmodifiableList(nodes) - : Collections.emptyList(); - } - - @Override - public int getItemViewType(int position) { - return getNodeViewType(nodes.get(position).getClass()); - } - - @Override - public long getItemId(int position) { - final Node node = nodes.get(position); - final int type = getNodeViewType(node.getClass()); - final Entry entry = getEntry(type); - return entry.id(node); - } - - @Override - public int getNodeViewType(@NonNull Class node) { - // if has registered -> then return it, else 0 - final int hash = node.hashCode(); - if (entries.indexOfKey(hash) > -1) { - return hash; - } - return 0; - } - - @NonNull - private Entry getEntry(int viewType) { - return viewType == 0 - ? defaultEntry - : entries.get(viewType); - } - - public static class CustomBuilderImpl implements Builder { - - private final SparseArray> entries = new SparseArray<>(3); - - private final Entry defaultEntry; - - private MarkwonReducer reducer; - - CustomBuilderImpl(@NonNull Entry defaultEntry) { - this.defaultEntry = defaultEntry; - } - - @NonNull - @Override - public CustomBuilderImpl include( - @NonNull Class node, - @NonNull Entry entry) { - //noinspection unchecked - entries.append(node.hashCode(), (Entry) entry); - return this; - } - - @NonNull - @Override - public CustomBuilderImpl reducer(@NonNull MarkwonReducer reducer) { - this.reducer = reducer; - return this; - } - - @NonNull - @Override - public CustomMarkwonAdapter build() { - - if (reducer == null) { - reducer = MarkwonReducer.directChildren(); - } - - return new CustomMarkwonAdapter(entries, defaultEntry, reducer); - } - } -} 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 84d3bf5d..6d171a3a 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/fragments/SidebarFragment.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/fragments/SidebarFragment.java @@ -34,7 +34,6 @@ 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.MediaMetadata; import ml.docilealligator.infinityforreddit.R; import ml.docilealligator.infinityforreddit.RedditDataRoomDatabase; import ml.docilealligator.infinityforreddit.activities.LinkResolverActivity; @@ -44,9 +43,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.CustomMarkwonAdapter; +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; import ml.docilealligator.infinityforreddit.markdown.ImageAndGifPlugin; import ml.docilealligator.infinityforreddit.markdown.MarkdownUtils; @@ -149,9 +149,10 @@ public class SidebarFragment extends Fragment { return true; }; EmoteCloseBracketInlineProcessor emoteCloseBracketInlineProcessor = new EmoteCloseBracketInlineProcessor(); + EmotePlugin emotePlugin = EmotePlugin.create(activity); ImageAndGifPlugin imageAndGifPlugin = new ImageAndGifPlugin(); Markwon markwon = MarkdownUtils.createFullRedditMarkwon(activity, - miscPlugin, emoteCloseBracketInlineProcessor, imageAndGifPlugin, markdownColor, + miscPlugin, emoteCloseBracketInlineProcessor, emotePlugin, imageAndGifPlugin, markdownColor, spoilerBackgroundColor, onLinkLongClickListener); CustomMarkwonAdapter markwonAdapter = MarkdownUtils.createCustomTablesAdapter(new ImageAndGifEntry(activity, Glide.with(this), diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/CustomMarkwonAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/CustomMarkwonAdapter.java new file mode 100644 index 00000000..25e63d2c --- /dev/null +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/CustomMarkwonAdapter.java @@ -0,0 +1,269 @@ +package ml.docilealligator.infinityforreddit.markdown; + +import android.util.SparseArray; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.HorizontalScrollView; +import android.widget.TableLayout; +import android.widget.TableRow; +import android.widget.TextView; + +import androidx.annotation.IdRes; +import androidx.annotation.LayoutRes; +import androidx.annotation.NonNull; + +import org.commonmark.node.Node; + +import java.util.Collections; +import java.util.List; + +import io.noties.markwon.Markwon; +import io.noties.markwon.MarkwonReducer; +import io.noties.markwon.recycler.MarkwonAdapter; +import io.noties.markwon.recycler.SimpleEntry; +import ml.docilealligator.infinityforreddit.R; +import ml.docilealligator.infinityforreddit.customviews.SpoilerOnClickTextView; + +public class CustomMarkwonAdapter extends MarkwonAdapter { + private final SparseArray> entries; + private final Entry defaultEntry; + private final MarkwonReducer reducer; + + private LayoutInflater layoutInflater; + + private Markwon markwon; + private List nodes; + + private View.OnClickListener onClickListener; + private View.OnLongClickListener onLongClickListener; + + @SuppressWarnings("WeakerAccess") + CustomMarkwonAdapter( + @NonNull SparseArray> entries, + @NonNull Entry defaultEntry, + @NonNull MarkwonReducer reducer) { + this.entries = entries; + this.defaultEntry = defaultEntry; + this.reducer = reducer; + + setHasStableIds(true); + } + + public void setOnClickListener(View.OnClickListener onClickListener) { + this.onClickListener = onClickListener; + } + + public void setOnLongClickListener(View.OnLongClickListener onLongClickListener) { + this.onLongClickListener = onLongClickListener; + } + + @NonNull + public static CustomBuilderImpl builder( + @LayoutRes int defaultEntryLayoutResId, + @IdRes int defaultEntryTextViewResId + ) { + return builder(SimpleEntry.create(defaultEntryLayoutResId, defaultEntryTextViewResId)); + } + + @NonNull + public static CustomBuilderImpl builder(@NonNull Entry defaultEntry) { + //noinspection unchecked + return new CustomBuilderImpl((Entry) defaultEntry); + } + + @Override + public void setMarkdown(@NonNull Markwon markwon, @NonNull String markdown) { + setParsedMarkdown(markwon, markwon.parse(markdown)); + } + + @Override + public void setParsedMarkdown(@NonNull Markwon markwon, @NonNull Node document) { + setParsedMarkdown(markwon, reducer.reduce(document)); + } + + @Override + public void setParsedMarkdown(@NonNull Markwon markwon, @NonNull List nodes) { + // clear all entries before applying + + defaultEntry.clear(); + + for (int i = 0, size = entries.size(); i < size; i++) { + entries.valueAt(i).clear(); + } + + this.markwon = markwon; + this.nodes = nodes; + } + + @NonNull + @Override + public Holder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + + if (layoutInflater == null) { + layoutInflater = LayoutInflater.from(parent.getContext()); + } + + final Entry entry = getEntry(viewType); + + return entry.createHolder(layoutInflater, parent); + } + + @Override + public void onBindViewHolder(@NonNull Holder holder, int position) { + + final Node node = nodes.get(position); + final int viewType = getNodeViewType(node.getClass()); + + final Entry entry = getEntry(viewType); + + entry.bindHolder(markwon, holder, node); + + if (holder.itemView instanceof SpoilerOnClickTextView) { + holder.itemView.setOnClickListener(onClickListener); + holder.itemView.setOnLongClickListener(onLongClickListener); + } else if (holder.itemView instanceof HorizontalScrollView) { + TableLayout tableLayout = holder.itemView.findViewById(R.id.table_layout); + if (tableLayout != null) { + for (int i = 0; i < tableLayout.getChildCount(); i++) { + if (tableLayout.getChildAt(i) instanceof TableRow) { + TableRow tableRow = ((TableRow) tableLayout.getChildAt(i)); + for (int j = 0; j < tableRow.getChildCount(); j++) { + if (tableRow.getChildAt(j) instanceof TextView) { + TextView textView = (TextView) tableRow.getChildAt(j); + tableRow.getChildAt(j).setOnClickListener(view -> { + if (textView.getSelectionStart() == -1 && textView.getSelectionEnd() == -1) { + onClickListener.onClick(view); + } + }); + tableRow.getChildAt(j).setOnLongClickListener(view -> { + if (textView.getSelectionStart() == -1 && textView.getSelectionEnd() == -1) { + onLongClickListener.onLongClick(view); + } + return true; + }); + } + } + } + } + } + } + + if (node instanceof ImageAndGifBlock) { + if (!holder.itemView.hasOnClickListeners()) { + holder.itemView.setOnClickListener(onClickListener); + holder.itemView.setOnLongClickListener(onLongClickListener); + } + + 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) { + 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) { + return onLongClickListener.onLongClick(view); + } + return false; + }); + } + } + } + } + + @Override + public int getItemCount() { + return nodes != null + ? nodes.size() + : 0; + } + + @Override + public void onViewRecycled(@NonNull Holder holder) { + super.onViewRecycled(holder); + + final Entry entry = getEntry(holder.getItemViewType()); + entry.onViewRecycled(holder); + } + + @SuppressWarnings("unused") + @NonNull + public List getItems() { + return nodes != null + ? Collections.unmodifiableList(nodes) + : Collections.emptyList(); + } + + @Override + public int getItemViewType(int position) { + return getNodeViewType(nodes.get(position).getClass()); + } + + @Override + public long getItemId(int position) { + final Node node = nodes.get(position); + final int type = getNodeViewType(node.getClass()); + final Entry entry = getEntry(type); + return entry.id(node); + } + + @Override + public int getNodeViewType(@NonNull Class node) { + // if has registered -> then return it, else 0 + final int hash = node.hashCode(); + if (entries.indexOfKey(hash) > -1) { + return hash; + } + return 0; + } + + @NonNull + private Entry getEntry(int viewType) { + return viewType == 0 + ? defaultEntry + : entries.get(viewType); + } + + public static class CustomBuilderImpl implements Builder { + + private final SparseArray> entries = new SparseArray<>(3); + + private final Entry defaultEntry; + + private MarkwonReducer reducer; + + CustomBuilderImpl(@NonNull Entry defaultEntry) { + this.defaultEntry = defaultEntry; + } + + @NonNull + @Override + public CustomBuilderImpl include( + @NonNull Class node, + @NonNull Entry entry) { + //noinspection unchecked + entries.append(node.hashCode(), (Entry) entry); + return this; + } + + @NonNull + @Override + public CustomBuilderImpl reducer(@NonNull MarkwonReducer reducer) { + this.reducer = reducer; + return this; + } + + @NonNull + @Override + public CustomMarkwonAdapter build() { + + if (reducer == null) { + reducer = MarkwonReducer.directChildren(); + } + + return new CustomMarkwonAdapter(entries, defaultEntry, reducer); + } + } +} diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/EmotePlugin.java b/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/EmotePlugin.java index 2bb81bf9..05675498 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/EmotePlugin.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/EmotePlugin.java @@ -28,14 +28,16 @@ import io.noties.markwon.MarkwonSpansFactory; import io.noties.markwon.MarkwonVisitor; import io.noties.markwon.RenderProps; import io.noties.markwon.SpanFactory; +import io.noties.markwon.core.CoreProps; import io.noties.markwon.image.AsyncDrawable; import io.noties.markwon.image.AsyncDrawableLoader; import io.noties.markwon.image.AsyncDrawableScheduler; import io.noties.markwon.image.DrawableUtils; import io.noties.markwon.image.ImageProps; -import ml.docilealligator.infinityforreddit.MediaMetadata; public class EmotePlugin extends AbstractMarkwonPlugin { + private boolean disableImagePreview = true; + public interface GlideStore { @NonNull @@ -93,6 +95,18 @@ public class EmotePlugin extends AbstractMarkwonPlugin { @Override public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) { builder.on(Emote.class, (visitor, emote) -> { + if (disableImagePreview) { + Link link = new Link(emote.getMediaMetadata().original.url, emote.getTitle()); + + final int length = visitor.length(); + visitor.visitChildren(emote); + + final String destination = link.getDestination(); + CoreProps.LINK_DESTINATION.set(visitor.renderProps(), destination); + visitor.setSpansForNodeOptional(link, length); + return; + } + // if there is no image spanFactory, ignore final SpanFactory spanFactory = visitor.configuration().spansFactory().get(Emote.class); if (spanFactory == null) { @@ -141,8 +155,8 @@ public class EmotePlugin extends AbstractMarkwonPlugin { AsyncDrawableScheduler.schedule(textView); } - public void setMediaMetadataMap(Map mediaMetadataMap) { - + public void setDisableImagePreview(boolean disableImagePreview) { + this.disableImagePreview = disableImagePreview; } private static class GlideAsyncDrawableLoader extends AsyncDrawableLoader { diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/ImageAndGifEntry.java b/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/ImageAndGifEntry.java index 4f42acc1..12e62632 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/ImageAndGifEntry.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/ImageAndGifEntry.java @@ -1,8 +1,13 @@ package ml.docilealligator.infinityforreddit.markdown; +import android.content.Intent; import android.content.SharedPreferences; import android.content.res.ColorStateList; import android.graphics.drawable.Drawable; +import android.net.Uri; +import android.text.SpannableString; +import android.text.Spanned; +import android.text.style.URLSpan; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; @@ -26,9 +31,12 @@ import io.noties.markwon.Markwon; import io.noties.markwon.recycler.MarkwonAdapter; import jp.wasabeef.glide.transformations.BlurTransformation; import jp.wasabeef.glide.transformations.RoundedCornersTransformation; +import me.saket.bettermovementmethod.BetterLinkMovementMethod; import ml.docilealligator.infinityforreddit.MediaMetadata; import ml.docilealligator.infinityforreddit.SaveMemoryCenterInisdeDownsampleStrategy; import ml.docilealligator.infinityforreddit.activities.BaseActivity; +import ml.docilealligator.infinityforreddit.activities.LinkResolverActivity; +import ml.docilealligator.infinityforreddit.bottomsheetfragments.UrlMenuBottomSheetFragment; import ml.docilealligator.infinityforreddit.databinding.MarkdownImageAndGifBlockBinding; import ml.docilealligator.infinityforreddit.utils.SharedPreferencesUtils; import ml.docilealligator.infinityforreddit.utils.Utils; @@ -39,10 +47,12 @@ public class ImageAndGifEntry extends MarkwonAdapter.Entry imageRequestBuilder; if (dataSavingMode) { - imageRequestBuilder = glide.load(node.mediaMetadata.downscaled.url).listener(holder.requestListener); - holder.binding.imageViewMarkdownImageAndGifBlock.setRatio((float) node.mediaMetadata.downscaled.y / node.mediaMetadata.downscaled.x); + if (disableImagePreview) { + holder.binding.imageWrapperRelativeLayoutMarkdownImageAndGifBlock.setVisibility(View.GONE); + holder.binding.captionTextViewMarkdownImageAndGifBlock.setVisibility(View.VISIBLE); + holder.binding.captionTextViewMarkdownImageAndGifBlock.setGravity(Gravity.NO_GRAVITY); + SpannableString spannableString = new SpannableString(node.mediaMetadata.caption == null ? node.mediaMetadata.original.url : node.mediaMetadata.caption); + spannableString.setSpan(new URLSpan(node.mediaMetadata.original.url), 0, spannableString.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + holder.binding.captionTextViewMarkdownImageAndGifBlock.setText(spannableString); + return; + } else { + imageRequestBuilder = glide.load(node.mediaMetadata.downscaled.url).listener(holder.requestListener); + holder.binding.imageViewMarkdownImageAndGifBlock.setRatio((float) node.mediaMetadata.downscaled.y / node.mediaMetadata.downscaled.x); + } } else { imageRequestBuilder = glide.load(node.mediaMetadata.original.url).listener(holder.requestListener); holder.binding.imageViewMarkdownImageAndGifBlock.setRatio((float) node.mediaMetadata.original.y / node.mediaMetadata.original.x); @@ -143,6 +168,7 @@ public class ImageAndGifEntry extends MarkwonAdapter.Entry { + Intent intent = new Intent(baseActivity, LinkResolverActivity.class); + intent.setData(Uri.parse(url)); + baseActivity.startActivity(intent); + return true; + }) + .setOnLinkLongClickListener((textView, url) -> { + UrlMenuBottomSheetFragment urlMenuBottomSheetFragment = UrlMenuBottomSheetFragment.newInstance(url); + urlMenuBottomSheetFragment.show(baseActivity.getSupportFragmentManager(), urlMenuBottomSheetFragment.getTag()); + return true; + })); } } 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 da867443..45e6f384 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/MarkdownUtils.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/MarkdownUtils.java @@ -21,7 +21,6 @@ import io.noties.markwon.recycler.table.TableEntry; import io.noties.markwon.recycler.table.TableEntryPlugin; import me.saket.bettermovementmethod.BetterLinkMovementMethod; import ml.docilealligator.infinityforreddit.R; -import ml.docilealligator.infinityforreddit.customviews.CustomMarkwonAdapter; public class MarkdownUtils { /** @@ -32,6 +31,7 @@ public class MarkdownUtils { public static Markwon createFullRedditMarkwon(@NonNull Context context, @NonNull MarkwonPlugin miscPlugin, @NonNull EmoteCloseBracketInlineProcessor emoteCloseBracketInlineProcessor, + @NonNull EmotePlugin emotePlugin, @NonNull ImageAndGifPlugin imageAndGifPlugin, int markdownColor, int spoilerBackgroundColor, @@ -53,7 +53,7 @@ public class MarkdownUtils { .setOnLinkLongClickListener(onLinkLongClickListener))) .usePlugin(LinkifyPlugin.create(Linkify.WEB_URLS)) .usePlugin(imageAndGifPlugin) - .usePlugin(EmotePlugin.create(context)) + .usePlugin(emotePlugin) .usePlugin(TableEntryPlugin.create(context)) .build(); } -- cgit v1.2.3