Show images in comments and post

Replace image links in posts and comments with actual images.
This commit is contained in:
Balazs Toldi 2023-08-03 13:50:51 +02:00
parent 6d114f84fa
commit 079269efea
No known key found for this signature in database
GPG Key ID: 6C7D440036F99D58
12 changed files with 32 additions and 63 deletions

View File

@ -8,8 +8,8 @@ android {
applicationId "eu.toldi.infinityforlemmy" applicationId "eu.toldi.infinityforlemmy"
minSdk 21 minSdk 21
targetSdk 33 targetSdk 33
versionCode 126 versionCode 128
versionName "0.0.6" versionName "0.0.8"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
javaCompileOptions { javaCompileOptions {
annotationProcessorOptions { annotationProcessorOptions {
@ -169,6 +169,7 @@ dependencies {
implementation "io.noties.markwon:recycler-table:$markwonVersion" implementation "io.noties.markwon:recycler-table:$markwonVersion"
implementation "io.noties.markwon:simple-ext:$markwonVersion" implementation "io.noties.markwon:simple-ext:$markwonVersion"
implementation "io.noties.markwon:inline-parser:$markwonVersion" implementation "io.noties.markwon:inline-parser:$markwonVersion"
implementation "io.noties.markwon:image-glide:$markwonVersion"
implementation 'com.atlassian.commonmark:commonmark-ext-gfm-tables:0.14.0' implementation 'com.atlassian.commonmark:commonmark-ext-gfm-tables:0.14.0'
implementation 'me.saket:better-link-movement-method:2.2.0' implementation 'me.saket:better-link-movement-method:2.2.0'

View File

@ -513,8 +513,8 @@ public class CommentActivity extends BaseActivity implements UploadImageEnabledA
int start = Math.max(binding.commentCommentEditText.getSelectionStart(), 0); int start = Math.max(binding.commentCommentEditText.getSelectionStart(), 0);
int end = Math.max(binding.commentCommentEditText.getSelectionEnd(), 0); int end = Math.max(binding.commentCommentEditText.getSelectionEnd(), 0);
binding.commentCommentEditText.getText().replace(Math.min(start, end), Math.max(start, end), binding.commentCommentEditText.getText().replace(Math.min(start, end), Math.max(start, end),
"[" + uploadedImage.imageName + "](" + uploadedImage.imageUrl + ")", "![" + uploadedImage.imageName + "](" + uploadedImage.imageUrl + ")",
0, "[]()".length() + uploadedImage.imageName.length() + uploadedImage.imageUrl.length()); 0, "![]()".length() + uploadedImage.imageName.length() + uploadedImage.imageUrl.length());
} }
@Override @Override

View File

@ -345,7 +345,7 @@ public class EditCommentActivity extends BaseActivity implements UploadImageEnab
int start = Math.max(contentEditText.getSelectionStart(), 0); int start = Math.max(contentEditText.getSelectionStart(), 0);
int end = Math.max(contentEditText.getSelectionEnd(), 0); int end = Math.max(contentEditText.getSelectionEnd(), 0);
contentEditText.getText().replace(Math.min(start, end), Math.max(start, end), contentEditText.getText().replace(Math.min(start, end), Math.max(start, end),
"[" + uploadedImage.imageName + "](" + uploadedImage.imageUrl + ")", "![" + uploadedImage.imageName + "](" + uploadedImage.imageUrl + ")",
0, "[]()".length() + uploadedImage.imageName.length() + uploadedImage.imageUrl.length()); 0, "![]()".length() + uploadedImage.imageName.length() + uploadedImage.imageUrl.length());
} }
} }

View File

@ -456,7 +456,7 @@ public class EditPostActivity extends BaseActivity implements UploadImageEnabled
int start = Math.max(contentEditText.getSelectionStart(), 0); int start = Math.max(contentEditText.getSelectionStart(), 0);
int end = Math.max(contentEditText.getSelectionEnd(), 0); int end = Math.max(contentEditText.getSelectionEnd(), 0);
contentEditText.getText().replace(Math.min(start, end), Math.max(start, end), contentEditText.getText().replace(Math.min(start, end), Math.max(start, end),
"[" + uploadedImage.imageName + "](" + uploadedImage.imageUrl + ")", "![" + uploadedImage.imageName + "](" + uploadedImage.imageUrl + ")",
0, "[]()".length() + uploadedImage.imageName.length() + uploadedImage.imageUrl.length()); 0, "![]()".length() + uploadedImage.imageName.length() + uploadedImage.imageUrl.length());
} }
} }

View File

@ -792,7 +792,7 @@ public class PostImageActivity extends BaseActivity implements FlairBottomSheetF
int start = Math.max(contentEditText.getSelectionStart(), 0); int start = Math.max(contentEditText.getSelectionStart(), 0);
int end = Math.max(contentEditText.getSelectionEnd(), 0); int end = Math.max(contentEditText.getSelectionEnd(), 0);
contentEditText.getText().replace(Math.min(start, end), Math.max(start, end), contentEditText.getText().replace(Math.min(start, end), Math.max(start, end),
"[" + uploadedImage.imageName + "](" + uploadedImage.imageUrl + ")", "![" + uploadedImage.imageName + "](" + uploadedImage.imageUrl + ")",
0, "[]()".length() + uploadedImage.imageName.length() + uploadedImage.imageUrl.length()); 0, "![]()".length() + uploadedImage.imageName.length() + uploadedImage.imageUrl.length());
} }
} }

View File

@ -722,7 +722,7 @@ public class PostLinkActivity extends BaseActivity implements FlairBottomSheetFr
int start = Math.max(contentEditText.getSelectionStart(), 0); int start = Math.max(contentEditText.getSelectionStart(), 0);
int end = Math.max(contentEditText.getSelectionEnd(), 0); int end = Math.max(contentEditText.getSelectionEnd(), 0);
contentEditText.getText().replace(Math.min(start, end), Math.max(start, end), contentEditText.getText().replace(Math.min(start, end), Math.max(start, end),
"[" + uploadedImage.imageName + "](" + uploadedImage.imageUrl + ")", "![" + uploadedImage.imageName + "](" + uploadedImage.imageUrl + ")",
0, "[]()".length() + uploadedImage.imageName.length() + uploadedImage.imageUrl.length()); 0, "![]()".length() + uploadedImage.imageName.length() + uploadedImage.imageUrl.length());
} }
} }

View File

@ -673,8 +673,8 @@ public class PostTextActivity extends BaseActivity implements FlairBottomSheetFr
int start = Math.max(contentEditText.getSelectionStart(), 0); int start = Math.max(contentEditText.getSelectionStart(), 0);
int end = Math.max(contentEditText.getSelectionEnd(), 0); int end = Math.max(contentEditText.getSelectionEnd(), 0);
contentEditText.getText().replace(Math.min(start, end), Math.max(start, end), contentEditText.getText().replace(Math.min(start, end), Math.max(start, end),
"[" + uploadedImage.imageName + "](" + uploadedImage.imageUrl + ")", "![" + uploadedImage.imageName + "](" + uploadedImage.imageUrl + ")",
0, "[]()".length() + uploadedImage.imageName.length() + uploadedImage.imageUrl.length()); 0, "![]()".length() + uploadedImage.imageName.length() + uploadedImage.imageUrl.length());
} }
@Override @Override

View File

@ -42,7 +42,7 @@ import io.noties.markwon.Markwon;
import io.noties.markwon.MarkwonConfiguration; import io.noties.markwon.MarkwonConfiguration;
import io.noties.markwon.core.MarkwonTheme; import io.noties.markwon.core.MarkwonTheme;
import io.noties.markwon.ext.strikethrough.StrikethroughPlugin; import io.noties.markwon.ext.strikethrough.StrikethroughPlugin;
import io.noties.markwon.inlineparser.BangInlineProcessor; import io.noties.markwon.image.glide.GlideImagesPlugin;
import io.noties.markwon.inlineparser.HtmlInlineProcessor; import io.noties.markwon.inlineparser.HtmlInlineProcessor;
import io.noties.markwon.inlineparser.MarkwonInlineParserPlugin; import io.noties.markwon.inlineparser.MarkwonInlineParserPlugin;
import io.noties.markwon.linkify.LinkifyPlugin; import io.noties.markwon.linkify.LinkifyPlugin;
@ -105,7 +105,6 @@ public class MessageRecyclerViewAdapter extends PagedListAdapter<CommentInteract
mMarkwon = Markwon.builder(mActivity) mMarkwon = Markwon.builder(mActivity)
.usePlugin(MarkwonInlineParserPlugin.create(plugin -> { .usePlugin(MarkwonInlineParserPlugin.create(plugin -> {
plugin.excludeInlineProcessor(HtmlInlineProcessor.class); plugin.excludeInlineProcessor(HtmlInlineProcessor.class);
plugin.excludeInlineProcessor(BangInlineProcessor.class);
})) }))
.usePlugin(new AbstractMarkwonPlugin() { .usePlugin(new AbstractMarkwonPlugin() {
@Override @Override
@ -129,6 +128,7 @@ public class MessageRecyclerViewAdapter extends PagedListAdapter<CommentInteract
.usePlugin(StrikethroughPlugin.create()) .usePlugin(StrikethroughPlugin.create())
.usePlugin(MovementMethodPlugin.create(new SpoilerAwareMovementMethod())) .usePlugin(MovementMethodPlugin.create(new SpoilerAwareMovementMethod()))
.usePlugin(LinkifyPlugin.create(Linkify.WEB_URLS)) .usePlugin(LinkifyPlugin.create(Linkify.WEB_URLS))
.usePlugin(GlideImagesPlugin.create(mActivity))
.build(); .build();
mAccessToken = accessToken; mAccessToken = accessToken;
if (where.equals(FetchMessage.WHERE_MESSAGES)) { if (where.equals(FetchMessage.WHERE_MESSAGES)) {

View File

@ -24,7 +24,6 @@ import java.util.TimeZone;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import eu.toldi.infinityforlemmy.markdown.MarkdownUtils;
import eu.toldi.infinityforlemmy.utils.JSONUtils; import eu.toldi.infinityforlemmy.utils.JSONUtils;
import eu.toldi.infinityforlemmy.utils.LemmyUtils; import eu.toldi.infinityforlemmy.utils.LemmyUtils;
@ -304,7 +303,7 @@ public class ParseComment {
e.printStackTrace(); e.printStackTrace();
} }
} }
String content = MarkdownUtils.processImageCaptions(commentObj.getString("content"), "Image"); String content = commentObj.getString("content");
String commentMarkdown = content; String commentMarkdown = content;
String commentRawText = content; String commentRawText = content;
String linkId = postObj.getString("id"); String linkId = postObj.getString("id");

View File

@ -8,7 +8,6 @@ import androidx.annotation.Nullable;
import org.commonmark.ext.gfm.tables.TableBlock; import org.commonmark.ext.gfm.tables.TableBlock;
import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import eu.toldi.infinityforlemmy.R; import eu.toldi.infinityforlemmy.R;
@ -16,6 +15,7 @@ import eu.toldi.infinityforlemmy.customviews.CustomMarkwonAdapter;
import io.noties.markwon.Markwon; import io.noties.markwon.Markwon;
import io.noties.markwon.MarkwonPlugin; import io.noties.markwon.MarkwonPlugin;
import io.noties.markwon.ext.strikethrough.StrikethroughPlugin; import io.noties.markwon.ext.strikethrough.StrikethroughPlugin;
import io.noties.markwon.image.glide.GlideImagesPlugin;
import io.noties.markwon.inlineparser.BangInlineProcessor; import io.noties.markwon.inlineparser.BangInlineProcessor;
import io.noties.markwon.inlineparser.HtmlInlineProcessor; import io.noties.markwon.inlineparser.HtmlInlineProcessor;
import io.noties.markwon.inlineparser.MarkwonInlineParserPlugin; import io.noties.markwon.inlineparser.MarkwonInlineParserPlugin;
@ -38,9 +38,9 @@ public class MarkdownUtils {
int spoilerBackgroundColor, int spoilerBackgroundColor,
@Nullable BetterLinkMovementMethod.OnLinkLongClickListener onLinkLongClickListener) { @Nullable BetterLinkMovementMethod.OnLinkLongClickListener onLinkLongClickListener) {
return Markwon.builder(context) return Markwon.builder(context)
.usePlugin(GlideImagesPlugin.create(context))
.usePlugin(MarkwonInlineParserPlugin.create(plugin -> { .usePlugin(MarkwonInlineParserPlugin.create(plugin -> {
plugin.excludeInlineProcessor(HtmlInlineProcessor.class); plugin.excludeInlineProcessor(HtmlInlineProcessor.class);
plugin.excludeInlineProcessor(BangInlineProcessor.class);
})) }))
.usePlugin(miscPlugin) .usePlugin(miscPlugin)
.usePlugin(SuperscriptPlugin.create()) .usePlugin(SuperscriptPlugin.create())
@ -60,7 +60,6 @@ public class MarkdownUtils {
return Markwon.builder(context) return Markwon.builder(context)
.usePlugin(MarkwonInlineParserPlugin.create(plugin -> { .usePlugin(MarkwonInlineParserPlugin.create(plugin -> {
plugin.excludeInlineProcessor(HtmlInlineProcessor.class); plugin.excludeInlineProcessor(HtmlInlineProcessor.class);
plugin.excludeInlineProcessor(BangInlineProcessor.class);
})) }))
.usePlugin(miscPlugin) .usePlugin(miscPlugin)
.usePlugin(SuperscriptPlugin.create()) .usePlugin(SuperscriptPlugin.create())
@ -70,6 +69,7 @@ public class MarkdownUtils {
.setOnLinkLongClickListener(onLinkLongClickListener))) .setOnLinkLongClickListener(onLinkLongClickListener)))
.usePlugin(LinkifyPlugin.create(Linkify.WEB_URLS)) .usePlugin(LinkifyPlugin.create(Linkify.WEB_URLS))
.usePlugin(TableEntryPlugin.create(context)) .usePlugin(TableEntryPlugin.create(context))
.usePlugin(GlideImagesPlugin.create(context))
.build(); .build();
} }
@ -104,6 +104,15 @@ public class MarkdownUtils {
.build(); .build();
} }
@NonNull
public static MarkwonAdapter createTablesAndImagesAdapter(@NonNull Context context) {
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)))
.build();
}
/** /**
* Creates a CustomMarkwonAdapter configured with support for tables. * Creates a CustomMarkwonAdapter configured with support for tables.
*/ */
@ -119,35 +128,4 @@ public class MarkdownUtils {
private static final Pattern emptyPattern = Pattern.compile("!\\[\\]\\((.*?)\\)"); private static final Pattern emptyPattern = Pattern.compile("!\\[\\]\\((.*?)\\)");
private static final Pattern nonEmptyPattern = Pattern.compile("!\\[(.*?)\\]\\((.*?)\\)"); private static final Pattern nonEmptyPattern = Pattern.compile("!\\[(.*?)\\]\\((.*?)\\)");
public static String processImageCaptions(String markdown, String replacementCaption) {
// Pattern for Markdown images with empty captions
// Pattern for Markdown images with non-empty captions
Matcher emptyMatcher = emptyPattern.matcher(markdown);
StringBuffer sb = new StringBuffer();
while (emptyMatcher.find()) {
// Replace the matched pattern with the same URL, but with a caption
emptyMatcher.appendReplacement(sb, "[" + replacementCaption + "](" + emptyMatcher.group(1) + ")");
}
// Append the rest of the content
emptyMatcher.appendTail(sb);
// Now process non-empty captions
Matcher nonEmptyMatcher = nonEmptyPattern.matcher(sb.toString());
StringBuffer finalSb = new StringBuffer();
while (nonEmptyMatcher.find()) {
// Replace the matched pattern with the same URL and caption, but without the "!"
nonEmptyMatcher.appendReplacement(finalSb, "[" + nonEmptyMatcher.group(1) + "](" + nonEmptyMatcher.group(2) + ")");
}
// Append the rest of the content
nonEmptyMatcher.appendTail(finalSb);
return finalSb.toString();
}
} }

View File

@ -33,7 +33,6 @@ import java.util.concurrent.Executor;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import eu.toldi.infinityforlemmy.markdown.MarkdownUtils;
import eu.toldi.infinityforlemmy.postfilter.PostFilter; import eu.toldi.infinityforlemmy.postfilter.PostFilter;
import eu.toldi.infinityforlemmy.utils.JSONUtils; import eu.toldi.infinityforlemmy.utils.JSONUtils;
import eu.toldi.infinityforlemmy.utils.LemmyUtils; import eu.toldi.infinityforlemmy.utils.LemmyUtils;
@ -654,14 +653,6 @@ public class ParsePost {
post.setVoteType(data.getInt("my_vote")); post.setVoteType(data.getInt("my_vote"));
post.setScore(post.getScore() - 1); post.setScore(post.getScore() - 1);
} }
if (!data.getJSONObject("post").isNull("body")) {
String body = MarkdownUtils.processImageCaptions(data.getJSONObject("post").getString("body"), "Image");
post.setSelfText(body);
post.setSelfTextPlain(body);
post.setSelfTextPlainTrimmed(body.trim());
}
return post; return post;
} }

View File

@ -382,8 +382,8 @@ public final class Utils {
int start = Math.max(editText.getSelectionStart(), 0); int start = Math.max(editText.getSelectionStart(), 0);
int end = Math.max(editText.getSelectionEnd(), 0); int end = Math.max(editText.getSelectionEnd(), 0);
editText.getText().replace(Math.min(start, end), Math.max(start, end), editText.getText().replace(Math.min(start, end), Math.max(start, end),
"[" + fileName + "](" + imageUrlOrError + ")", "![" + fileName + "](" + imageUrlOrError + ")",
0, "[]()".length() + fileName.length() + imageUrlOrError.length()); 0, "![]()".length() + fileName.length() + imageUrlOrError.length());
Snackbar.make(coordinatorLayout, R.string.upload_image_success, Snackbar.LENGTH_LONG).show(); Snackbar.make(coordinatorLayout, R.string.upload_image_success, Snackbar.LENGTH_LONG).show();
} else { } else {
Toast.makeText(context, R.string.upload_image_failed, Toast.LENGTH_LONG).show(); Toast.makeText(context, R.string.upload_image_failed, Toast.LENGTH_LONG).show();