Start showing images from preview.redd.it in posts.

This commit is contained in:
Docile-Alligator
2023-11-17 08:58:33 -05:00
parent 5f1a23a2a4
commit adb60910de
14 changed files with 355 additions and 18 deletions

View File

@ -1,7 +1,6 @@
package ml.docilealligator.infinityforreddit.activities;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
@ -15,7 +14,6 @@ import android.text.TextUtils;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.TextView;
import android.widget.Toast;
@ -153,6 +151,8 @@ public class CommentActivity extends BaseActivity implements UploadImageEnabledA
addOnOffsetChangedListener(binding.commentAppbarLayout);
}
mGlide = Glide.with(this);
mAccessToken = mCurrentAccountSharedPreferences.getString(SharedPreferencesUtils.ACCESS_TOKEN, null);
if (mAccessToken == null) {
finish();
@ -209,7 +209,7 @@ public class CommentActivity extends BaseActivity implements UploadImageEnabledA
};
Markwon postBodyMarkwon = MarkdownUtils.createFullRedditMarkwon(this,
miscPlugin, parentTextColor, parentSpoilerBackgroundColor, null);
MarkwonAdapter markwonAdapter = MarkdownUtils.createTablesAdapter();
MarkwonAdapter markwonAdapter = MarkdownUtils.createTablesAdapter(this, mGlide);
binding.commentContentMarkdownView.setLayoutManager(new LinearLayoutManagerBugFixed(this));
binding.commentContentMarkdownView.setAdapter(markwonAdapter);
markwonAdapter.setMarkdown(postBodyMarkwon, parentBodyMarkdown);
@ -225,8 +225,6 @@ public class CommentActivity extends BaseActivity implements UploadImageEnabledA
setSupportActionBar(binding.commentToolbar);
mGlide = Glide.with(this);
if (savedInstanceState != null) {
selectedAccount = savedInstanceState.getParcelable(SELECTED_ACCOUNT_STATE);
uploadedImages = savedInstanceState.getParcelableArrayList(UPLOADED_IMAGES_STATE);

View File

@ -18,6 +18,7 @@ import androidx.appcompat.widget.Toolbar;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.google.android.material.appbar.AppBarLayout;
import com.google.android.material.appbar.CollapsingToolbarLayout;
@ -141,7 +142,7 @@ public class FullMarkdownActivity extends BaseActivity {
Markwon markwon = MarkdownUtils.createFullRedditMarkwon(this,
miscPlugin, markdownColor, spoilerBackgroundColor, null);
MarkwonAdapter markwonAdapter = MarkdownUtils.createTablesAdapter();
MarkwonAdapter markwonAdapter = MarkdownUtils.createTablesAdapter(this, Glide.with(this));
LinearLayoutManagerBugFixed linearLayoutManager = new SwipeLockLinearLayoutManager(this, new SwipeLockInterface() {
@Override
public void lockSwipe() {

View File

@ -178,7 +178,7 @@ public class WikiActivity extends BaseActivity {
markwon = MarkdownUtils.createFullRedditMarkwon(this,
miscPlugin, markdownColor, spoilerBackgroundColor, onLinkLongClickListener);
markwonAdapter = MarkdownUtils.createTablesAdapter();
markwonAdapter = MarkdownUtils.createTablesAdapter(this, mGlide);
LinearLayoutManagerBugFixed linearLayoutManager = new SwipeLockLinearLayoutManager(this, new SwipeLockInterface() {
@Override
public void lockSwipe() {

View File

@ -289,7 +289,7 @@ public class PostDetailRecyclerViewAdapter extends RecyclerView.Adapter<Recycler
};
mPostDetailMarkwon = MarkdownUtils.createFullRedditMarkwon(mActivity,
miscPlugin, markdownColor, postSpoilerBackgroundColor, onLinkLongClickListener);
mMarkwonAdapter = MarkdownUtils.createTablesAdapter();
mMarkwonAdapter = MarkdownUtils.createTablesAdapter(activity, mGlide);
mSeparatePostAndComments = separatePostAndComments;
mLegacyAutoplayVideoControllerUI = sharedPreferences.getBoolean(SharedPreferencesUtils.LEGACY_AUTOPLAY_VIDEO_CONTROLLER_UI, false);

View File

@ -12,6 +12,8 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import java.util.ArrayList;
import butterknife.BindView;
@ -136,7 +138,7 @@ public class RulesRecyclerViewAdapter extends RecyclerView.Adapter<RulesRecycler
if (activity.typeface != null) {
shortNameTextView.setTypeface(activity.typeface);
}
markwonAdapter = MarkdownUtils.createTablesAdapter();
markwonAdapter = MarkdownUtils.createTablesAdapter(activity, Glide.with(activity));
SwipeLockLinearLayoutManager swipeLockLinearLayoutManager = new SwipeLockLinearLayoutManager(activity,
new SwipeLockInterface() {
@Override

View File

@ -18,6 +18,8 @@ import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import com.bumptech.glide.Glide;
import java.util.concurrent.Executor;
import javax.inject.Inject;
@ -144,7 +146,7 @@ public class SidebarFragment extends Fragment {
};
Markwon markwon = MarkdownUtils.createFullRedditMarkwon(activity,
miscPlugin, markdownColor, spoilerBackgroundColor, onLinkLongClickListener);
MarkwonAdapter markwonAdapter = MarkdownUtils.createTablesAdapter();
MarkwonAdapter markwonAdapter = MarkdownUtils.createTablesAdapter(activity, Glide.with(this));
linearLayoutManager = new LinearLayoutManagerBugFixed(activity);
recyclerView.setLayoutManager(linearLayoutManager);

View File

@ -0,0 +1,6 @@
package ml.docilealligator.infinityforreddit.markdown;
import org.commonmark.node.CustomBlock;
public class ImageAndGifBlock extends CustomBlock {
}

View File

@ -0,0 +1,50 @@
package ml.docilealligator.infinityforreddit.markdown;
import android.util.Log;
import org.commonmark.node.Block;
import org.commonmark.parser.block.AbstractBlockParser;
import org.commonmark.parser.block.AbstractBlockParserFactory;
import org.commonmark.parser.block.BlockContinue;
import org.commonmark.parser.block.BlockStart;
import org.commonmark.parser.block.MatchedBlockParser;
import org.commonmark.parser.block.ParserState;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class ImageAndGifBlockParser extends AbstractBlockParser {
private ImageAndGifBlock imageAndGifBlock;
ImageAndGifBlockParser() {
this.imageAndGifBlock = new ImageAndGifBlock();
}
@Override
public Block getBlock() {
return imageAndGifBlock;
}
@Override
public BlockContinue tryContinue(ParserState parserState) {
return null;
}
public static class Factory extends AbstractBlockParserFactory {
private Pattern redditPreviewPattern = Pattern.compile("!\\[img]\\(https://preview.redd.it/\\w+.(jpg|png)((\\?+[-a-zA-Z0-9()@:%_+.~#?&/=]*)|)\\)");
@Override
public BlockStart tryStart(ParserState state, MatchedBlockParser matchedBlockParser) {
String line = state.getLine().toString();
Log.i("asdfa", "s " + line + "fuck");
Matcher matcher = redditPreviewPattern.matcher(line);
if (matcher.find()) {
if (matcher.end() == line.length()) {
return BlockStart.of(new ImageAndGifBlockParser());
}
}
return BlockStart.none();
}
}
}

View File

@ -0,0 +1,198 @@
package ml.docilealligator.infinityforreddit.markdown;
import android.graphics.drawable.Drawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.bumptech.glide.RequestBuilder;
import com.bumptech.glide.RequestManager;
import com.bumptech.glide.load.DataSource;
import com.bumptech.glide.load.engine.GlideException;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.request.target.Target;
import io.noties.markwon.Markwon;
import io.noties.markwon.recycler.MarkwonAdapter;
import jp.wasabeef.glide.transformations.BlurTransformation;
import ml.docilealligator.infinityforreddit.activities.BaseActivity;
import ml.docilealligator.infinityforreddit.databinding.MarkdownImageAndGifBlockBinding;
public class ImageAndGifEntry extends MarkwonAdapter.Entry<ImageAndGifBlock, ImageAndGifEntry.Holder> {
private BaseActivity baseActivity;
private RequestManager glide;
public ImageAndGifEntry(BaseActivity baseActivity, RequestManager glide) {
this.baseActivity = baseActivity;
this.glide = glide;
}
@NonNull
@Override
public Holder createHolder(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) {
return new Holder(MarkdownImageAndGifBlockBinding.inflate(inflater, parent, false));
}
@Override
public void bindHolder(@NonNull Markwon markwon, @NonNull Holder holder, @NonNull ImageAndGifBlock node) {
holder.binding.progressBarMarkdownImageAndGifBlock.setVisibility(View.VISIBLE);
RequestBuilder<Drawable> imageRequestBuilder = glide.load("https://upload.wikimedia.org/wikipedia/commons/thumb/b/b6/Image_created_with_a_mobile_phone.png/1280px-Image_created_with_a_mobile_phone.png").listener(holder.requestListener);
boolean blurImage = false;
if (blurImage) {
imageRequestBuilder.apply(RequestOptions.bitmapTransform(new BlurTransformation(50, 10)))
.into(holder.binding.imageViewMarkdownImageAndGifBlock);
} else {
imageRequestBuilder.centerInside().into(holder.binding.imageViewMarkdownImageAndGifBlock);
}
}
@Override
public void onViewRecycled(@NonNull Holder holder) {
super.onViewRecycled(holder);
glide.clear(holder.binding.imageViewMarkdownImageAndGifBlock);
holder.binding.progressBarMarkdownImageAndGifBlock.setVisibility(View.GONE);
holder.binding.loadImageErrorTextViewMarkdownImageAndGifBlock.setVisibility(View.GONE);
}
public class Holder extends MarkwonAdapter.Holder {
MarkdownImageAndGifBlockBinding binding;
RequestListener<Drawable> requestListener;
public Holder(@NonNull MarkdownImageAndGifBlockBinding binding) {
super(binding.getRoot());
this.binding = binding;
requestListener = new RequestListener<>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
binding.progressBarMarkdownImageAndGifBlock.setVisibility(View.GONE);
binding.loadImageErrorTextViewMarkdownImageAndGifBlock.setVisibility(View.VISIBLE);
return false;
}
@Override
public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
binding.progressBarMarkdownImageAndGifBlock.setVisibility(View.GONE);
return false;
}
};
}
/*private final RequestListener<Drawable> requestListener = new RequestListener<Drawable>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
binding.progressBar.setVisibility(View.GONE);
return false;
}
@Override
public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
binding.progressBar.setVisibility(View.GONE);
return false;
}
};*/
/*public Holder(@NonNull AdapterGifEntryBinding binding) {
super(binding.getRoot());
this.binding = binding;
binding.progressBar.setIndeterminateTintList(ColorStateList.valueOf(customThemeWrapper.getColorAccent()));
binding.giphyWatermark.setTextColor(customThemeWrapper.getCommentColor());
binding.gifLink.setTextColor(customThemeWrapper.getLinkColor());
}*/
/*void bindImage(ImageMetadata image) {
binding.gifLink.setVisibility(View.GONE);
binding.iv.setVisibility(View.VISIBLE);
binding.progressBar.setVisibility(View.VISIBLE);
binding.giphyWatermark.setVisibility(View.GONE);
ViewGroup.LayoutParams params = binding.iv.getLayoutParams();
if (image.x > image.y) {
params.height = dpToPx(160);
params.width = params.height * image.x / image.y;
} else {
params.width = dpToPx(160);
params.height = params.width * image.y / image.x;
}
binding.iv.setLayoutParams(params);
// todo: check if waitForLayout is necessary here since we explicitly set width/height in LP
Target<Drawable> target = new DrawableImageViewTarget(binding.iv)
.waitForLayout();
glide.load(image.getUrl())
.addListener(requestListener)
.error(R.drawable.ic_error_outline_black_24dp)
.into(target);
}
void bindGif(GiphyGifMetadata gif) {
if (!canLoadGif()) {
// video autoplay is disabled, don't load gif
binding.gifLink.setVisibility(View.VISIBLE);
binding.iv.setVisibility(View.GONE);
binding.progressBar.setVisibility(View.GONE);
binding.giphyWatermark.setVisibility(View.GONE);
binding.gifLink.setOnClickListener(v -> {
onClickListener.accept(Uri.parse(gif.getGifUrl()));
});
return;
}
binding.gifLink.setVisibility(View.GONE);
binding.iv.setVisibility(View.VISIBLE);
binding.progressBar.setVisibility(View.VISIBLE);
binding.giphyWatermark.setVisibility(View.VISIBLE);
ViewGroup.LayoutParams params = binding.iv.getLayoutParams();
if (gif.x > gif.y) {
params.height = dpToPx(160);
params.width = params.height * gif.x / gif.y;
} else {
params.width = dpToPx(160);
params.height = params.width * gif.y / gif.x;
}
binding.iv.setLayoutParams(params);
// todo: check if waitForLayout is necessary here since we explicitly set width/height in LP
Target<Drawable> target = new DrawableImageViewTarget(binding.iv)
.waitForLayout();
glide.load(gif.getGifUrl())
.addListener(requestListener)
.error(R.drawable.ic_error_outline_black_24dp)
.into(target);
}
void recycle() {
glide.clear(binding.iv);
}
@SuppressWarnings("SameParameterValue")
private int dpToPx(int dp) {
float density = itemView.getContext().getResources().getDisplayMetrics().density;
return (int) (dp * density);
}
private boolean canLoadGif() {
// ideally this would be injected, but it is a bit unpleasant to do
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(itemView.getContext());
String dataSavingMode = sharedPreferences.getString(SharedPreferencesUtils.DATA_SAVING_MODE, SharedPreferencesUtils.DATA_SAVING_MODE_OFF);
Log.i("GifEntry", "datasaving=" + dataSavingMode);
if (dataSavingMode.equals(SharedPreferencesUtils.DATA_SAVING_MODE_ALWAYS)) {
return false;
} else if (dataSavingMode.equals(SharedPreferencesUtils.DATA_SAVING_MODE_ONLY_ON_CELLULAR_DATA)) {
int networkType = Utils.getConnectedNetwork(itemView.getContext());
return networkType != Utils.NETWORK_TYPE_CELLULAR;
} else {
return true;
}
}*/
}
}

View File

@ -0,0 +1,23 @@
package ml.docilealligator.infinityforreddit.markdown;
import android.util.Log;
import androidx.annotation.NonNull;
import org.commonmark.parser.Parser;
import io.noties.markwon.AbstractMarkwonPlugin;
public class ImageAndGifPlugin extends AbstractMarkwonPlugin {
@NonNull
@Override
public String processMarkdown(@NonNull String markdown) {
Log.i("asdfa", "imageandgifplugin " + markdown + "fuck");
return super.processMarkdown(markdown);
}
@Override
public void configureParser(@NonNull Parser.Builder builder) {
builder.customBlockParserFactory(new ImageAndGifBlockParser.Factory());
}
}

View File

@ -6,6 +6,8 @@ import android.text.util.Linkify;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.bumptech.glide.RequestManager;
import org.commonmark.ext.gfm.tables.TableBlock;
import io.noties.markwon.Markwon;
@ -21,6 +23,7 @@ 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.activities.BaseActivity;
import ml.docilealligator.infinityforreddit.customviews.CustomMarkwonAdapter;
public class MarkdownUtils {
@ -47,6 +50,7 @@ public class MarkdownUtils {
.usePlugin(MovementMethodPlugin.create(new SpoilerAwareMovementMethod()
.setOnLinkLongClickListener(onLinkLongClickListener)))
.usePlugin(LinkifyPlugin.create(Linkify.WEB_URLS))
.usePlugin(new ImageAndGifPlugin())
.usePlugin(TableEntryPlugin.create(context))
.build();
}
@ -93,11 +97,12 @@ public class MarkdownUtils {
* Creates a MarkwonAdapter configured with support for tables.
*/
@NonNull
public static MarkwonAdapter createTablesAdapter() {
public static MarkwonAdapter createTablesAdapter(BaseActivity baseActivity, RequestManager glide) {
return MarkwonAdapter.builder(R.layout.adapter_default_entry, R.id.text)
.include(TableBlock.class, TableEntry.create(builder -> builder
.tableLayout(R.layout.adapter_table_block, R.id.table_layout)
.textLayoutIsRoot(R.layout.view_table_entry_cell)))
.include(ImageAndGifBlock.class, new ImageAndGifEntry(baseActivity, glide))
.build();
}

View File

@ -319,7 +319,7 @@ public class ParsePost {
if (data.isNull(JSONUtils.SELFTEXT_KEY)) {
post.setSelfText("");
} else {
post.setSelfText(Utils.modifyMarkdown(Utils.trimTrailingWhitespace(data.getString(JSONUtils.SELFTEXT_KEY))));
post.setSelfText(Utils.modifyMarkdown(Utils.parseInlineRedditImages(Utils.trimTrailingWhitespace(data.getString(JSONUtils.SELFTEXT_KEY)))));
}
String authority = uri.getAuthority();
@ -505,7 +505,7 @@ public class ParsePost {
if (data.isNull(JSONUtils.SELFTEXT_KEY)) {
post.setSelfText("");
} else {
post.setSelfText(Utils.modifyMarkdown(Utils.trimTrailingWhitespace(data.getString(JSONUtils.SELFTEXT_KEY))));
post.setSelfText(Utils.modifyMarkdown(Utils.parseInlineRedditImages(Utils.trimTrailingWhitespace(data.getString(JSONUtils.SELFTEXT_KEY)))));
}
post.setPreviews(previews);
@ -580,7 +580,7 @@ public class ParsePost {
if (data.isNull(JSONUtils.SELFTEXT_KEY)) {
post.setSelfText("");
} else {
post.setSelfText(Utils.modifyMarkdown(Utils.trimTrailingWhitespace(data.getString(JSONUtils.SELFTEXT_KEY))));
post.setSelfText(Utils.modifyMarkdown(Utils.parseInlineRedditImages(Utils.trimTrailingWhitespace(data.getString(JSONUtils.SELFTEXT_KEY)))));
}
String authority = uri.getAuthority();
@ -724,7 +724,7 @@ public class ParsePost {
if (data.isNull(JSONUtils.SELFTEXT_KEY)) {
post.setSelfText("");
} else {
String selfText = Utils.modifyMarkdown(Utils.trimTrailingWhitespace(data.getString(JSONUtils.SELFTEXT_KEY)));
String selfText = Utils.modifyMarkdown(Utils.parseInlineRedditImages(Utils.trimTrailingWhitespace(data.getString(JSONUtils.SELFTEXT_KEY))));
post.setSelfText(selfText);
if (data.isNull(JSONUtils.SELFTEXT_HTML_KEY)) {
post.setSelfTextPlainTrimmed("");

View File

@ -19,6 +19,7 @@ import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.style.TypefaceSpan;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
@ -76,6 +77,7 @@ public final class Utils {
Pattern.compile("!\\[gif]\\(giphy\\|\\w+\\)"),
Pattern.compile("!\\[gif]\\(giphy\\|\\w+\\|downsized\\)"),
Pattern.compile("!\\[gif]\\(emote\\|\\w+\\|\\w+\\)"),
Pattern.compile("https://preview.redd.it/\\w+.(jpg|png)((\\?+[-a-zA-Z0-9()@:%_+.~#?&/=]*)|)")
};
public static String modifyMarkdown(String markdown) {
@ -91,14 +93,14 @@ public final class Utils {
Pattern inlineGifPattern = REGEX_PATTERNS[3];
Matcher matcher = inlineGifPattern.matcher(markdownStringBuilder);
while (matcher.find()) {
markdownStringBuilder.replace(matcher.start(), matcher.end(), "[gif](https://i.giphy.com/media/" + markdownStringBuilder.substring(matcher.start() + "![gif](giphy|".length(), matcher.end() - 1) + "/giphy.mp4)");
markdownStringBuilder.replace(matcher.start(), matcher.end(), "![gif](https://i.giphy.com/media/" + markdownStringBuilder.substring(matcher.start() + "![gif](giphy|".length(), matcher.end() - 1) + "/giphy.mp4)");
matcher = inlineGifPattern.matcher(markdownStringBuilder);
}
Pattern inlineGifPattern2 = REGEX_PATTERNS[4];
Matcher matcher2 = inlineGifPattern2.matcher(markdownStringBuilder);
while (matcher2.find()) {
markdownStringBuilder.replace(matcher2.start(), matcher2.end(), "[gif](https://i.giphy.com/media/" + markdownStringBuilder.substring(matcher2.start() + "![gif](giphy|".length(), matcher2.end() - "|downsized\\)".length() + 1) + "/giphy.mp4)");
markdownStringBuilder.replace(matcher2.start(), matcher2.end(), "![gif](https://i.giphy.com/media/" + markdownStringBuilder.substring(matcher2.start() + "![gif](giphy|".length(), matcher2.end() - "|downsized\\)".length() + 1) + "/giphy.mp4)");
matcher2 = inlineGifPattern2.matcher(markdownStringBuilder);
}
@ -106,7 +108,7 @@ public final class Utils {
Matcher matcher3 = inlineGifPattern3.matcher(markdownStringBuilder);
while (matcher3.find()) {
markdownStringBuilder.replace(matcher3.start(), matcher3.end(),
"[gif](https://reddit-meta-production.s3.amazonaws.com/public/fortnitebr/emotes/snoomoji_emotes/"
"![gif](https://reddit-meta-production.s3.amazonaws.com/public/fortnitebr/emotes/snoomoji_emotes/"
+ markdownStringBuilder.substring(
matcher3.start() + "![gif](emote|".length(), matcher3.end() - 1).replace('|', '/') + ".gif)");
matcher3 = inlineGifPattern3.matcher(markdownStringBuilder);
@ -148,6 +150,25 @@ public final class Utils {
return markdown;
}
public static String parseInlineRedditImages(String markdown) {
StringBuilder markdownStringBuilder = new StringBuilder(markdown);
Pattern inlineRedditImagePattern = REGEX_PATTERNS[6];
Matcher matcher = inlineRedditImagePattern.matcher(markdownStringBuilder);
int start = 0;
while (matcher.find(start)) {
int fileNameStartIndex = "https://preview.redd.it/".length();
String replacingText = "![" + /*markdownStringBuilder.substring(fileNameStartIndex,
markdownStringBuilder.indexOf(".", fileNameStartIndex))*/"img"
+ "](" + markdownStringBuilder.substring(matcher.start(), matcher.end()) + ")";
markdownStringBuilder.replace(matcher.start(), matcher.end(), replacingText);
start = replacingText.length() + matcher.start();
matcher = inlineRedditImagePattern.matcher(markdownStringBuilder);
Log.i("asdf", "S " + start + markdownStringBuilder.length());
}
return markdownStringBuilder.toString();
}
public static String trimTrailingWhitespace(String source) {
if (source == null) {

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/image_wrapper_relative_layout_markdown_image_and_gif_block"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ml.docilealligator.infinityforreddit.customviews.AspectRatioGifImageView
android:id="@+id/image_view_markdown_image_and_gif_block"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true" />
<ProgressBar
android:id="@+id/progress_bar_markdown_image_and_gif_block"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
<TextView
android:id="@+id/load_image_error_text_view_markdown_image_and_gif_block"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:drawableTop="@drawable/ic_error_outline_black_24dp"
android:fontFamily="?attr/font_family"
android:gravity="center"
android:text="@string/error_loading_image_tap_to_retry"
android:textSize="?attr/font_default"
android:visibility="gone" />
</FrameLayout>