diff options
Diffstat (limited to '')
3 files changed, 72 insertions, 97 deletions
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SpoilerParserPlugin.java b/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SpoilerParserPlugin.java index 1cca0cfe..3a05b71c 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SpoilerParserPlugin.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SpoilerParserPlugin.java @@ -3,6 +3,7 @@ package ml.docilealligator.infinityforreddit.markdown; import android.graphics.Color; import android.text.SpannableStringBuilder; import android.text.Spanned; +import android.util.Pair; import android.widget.TextView; import androidx.annotation.NonNull; @@ -13,8 +14,7 @@ import org.commonmark.node.HtmlBlock; import org.commonmark.node.HtmlInline; import org.commonmark.parser.Parser; -import java.util.LinkedHashMap; -import java.util.Map; +import java.util.ArrayList; import java.util.Set; import java.util.Stack; @@ -52,21 +52,21 @@ public class SpoilerParserPlugin extends AbstractMarkwonPlugin { public void afterSetText(@NonNull TextView textView) { textView.setHighlightColor(Color.TRANSPARENT); - if(textView.getText().length() < 5) { + if (textView.getText().length() < 5) { return; } SpannableStringBuilder markdownStringBuilder = new SpannableStringBuilder(textView.getText()); - LinkedHashMap<Integer, Integer> spoilers = parse(markdownStringBuilder); - if(spoilers.size() == 0) { + ArrayList<Pair<Integer, Integer>> spoilers = parse(markdownStringBuilder); + if (spoilers.size() == 0) { return; } - int offset = 2; - for (Map.Entry<Integer, Integer> entry : spoilers.entrySet()) { - int spoilerStart = entry.getKey() - offset; - int spoilerEnd = entry.getValue() - offset; + int offset = 2; + for (Pair<Integer, Integer> spoiler : spoilers) { + int spoilerStart = spoiler.first - offset; + int spoilerEnd = spoiler.second - offset; // Try not to set a spoiler span if it's inside a CodeSpan CodeSpan[] codeSpans = markdownStringBuilder.getSpans(spoilerStart, spoilerEnd, CodeSpan.class); @@ -78,6 +78,7 @@ public class SpoilerParserPlugin extends AbstractMarkwonPlugin { SpoilerSpan spoilerSpan = new SpoilerSpan(textColor, backgroundColor); markdownStringBuilder.setSpan(spoilerSpan, spoilerStart, spoilerEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); offset += 4; + continue; } for (CodeSpan codeSpan : codeSpans) { @@ -108,7 +109,7 @@ public class SpoilerParserPlugin extends AbstractMarkwonPlugin { } } } - if(offset > 2) { + if (offset > 2) { textView.setText(markdownStringBuilder); } } @@ -117,86 +118,45 @@ public class SpoilerParserPlugin extends AbstractMarkwonPlugin { // Don't allow more than one new line after every non-blank line // Try not to care about recursing spoilers, we just want the outermost spoiler because // spoiler revealing-hiding breaks with recursing spoilers - private LinkedHashMap<Integer, Integer> parse(SpannableStringBuilder markdown) { + private ArrayList<Pair<Integer, Integer>> parse(SpannableStringBuilder markdown) { final int MAX_NEW_LINE = 1; - var openSpoilerStack = new Stack<Integer>(); - var closedSpoilerMap = new LinkedHashMap<Integer, Integer>(); - int variable_max_depth = calculateBalance(0, markdown) + 1; + int length = markdown.length(); + Stack<Integer> openSpoilerStack = new Stack<>(); + ArrayList<Pair<Integer, Integer>> closedSpoilers = new ArrayList<>(); int new_lines = 0; - int depth = 0; - for (int i = 0; i < markdown.length(); i++) { - if (markdown.charAt(i) == '\u2000' || markdown.charAt(i) == '\t') { - continue; - } else if (markdown.charAt(i) == '>' && (i + 1) < markdown.length() && markdown.charAt(i + 1) == '!') { - openSpoilerStack.push(i + 1); - depth++; - } else if (openSpoilerStack.size() > 0 - && markdown.charAt(i) == '!' && (i + 1) < markdown.length() - && markdown.charAt(i + 1) == '<') { - var pos = i + 1; - for (int j = 0; j < depth; j++) { - if (!openSpoilerStack.isEmpty()) pos = openSpoilerStack.peek(); - if (pos + 1 <= i) { - if (!openSpoilerStack.isEmpty()) pos = openSpoilerStack.peek(); - break; - } else { - if (!openSpoilerStack.isEmpty()) pos = openSpoilerStack.pop(); - } - } - if (depth <= variable_max_depth && pos + 1 <= i) //Spoiler content cannot be zero or less length - { - openSpoilerStack.clear(); - closedSpoilerMap.put(pos + 1, i); - } - depth--; - } else if (markdown.charAt(i) == '\n') { + for (int i = 0; i < length; i++) { + if (markdown.charAt(i) == '\n') { new_lines++; - if (openSpoilerStack.size() >= 1 && new_lines > MAX_NEW_LINE) { + if (new_lines > MAX_NEW_LINE) { openSpoilerStack.clear(); new_lines = 0; - depth = 0; - variable_max_depth = calculateBalance(i, markdown) + 1; } - } else { + } else if ((markdown.charAt(i) != '>') + && (markdown.charAt(i) != '<') + && (markdown.charAt(i) != '!')) { new_lines = 0; - } - - if (openSpoilerStack.size() >= 32) // No - { - openSpoilerStack.clear(); - closedSpoilerMap.clear(); - continue; - } - } - return closedSpoilerMap; - } - - private int calculateBalance(int index, SpannableStringBuilder line) { - final int MAX_NEW_LINE = 1; - int new_lines = 0; - int opening = 0; - int closing = 0; - for (int i = index; i < line.length(); i++) { - if (line.charAt(i) == '\u0020' || line.charAt(i) == '\t') { - continue; - } else if (line.charAt(i) == '>' - && (i + 1) < line.length() - && line.charAt(i + 1) == '!') { - opening++; - } else if (line.charAt(i) == '!' && (i + 1) < line.length() - && line.charAt(i + 1) == '<') { - closing++; - } else if (line.charAt(i) == '\n') { - new_lines++; - if (new_lines > MAX_NEW_LINE) { - break; + } else if ((i + 1 < length) + && markdown.charAt(i) == '>' + && markdown.charAt(i + 1) == '!') { + openSpoilerStack.push(i + 2); + } else if ((i + 1 < length) && (i - 1 >= 0) + && openSpoilerStack.size() > 0 + && markdown.charAt(i - 1) != '>' + && markdown.charAt(i) == '!' + && markdown.charAt(i + 1) == '<') { + var pos = openSpoilerStack.pop(); + if (!closedSpoilers.isEmpty() + && closedSpoilers.get(closedSpoilers.size() - 1).first > pos + && closedSpoilers.get(closedSpoilers.size() - 1).second < i) { + closedSpoilers.remove(closedSpoilers.size() - 1); + } + if (pos != i) { + closedSpoilers.add(Pair.create(pos, i)); } } else { new_lines = 0; - continue; } } - return Math.abs(opening - closing); + return closedSpoilers; } - } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/post/ParsePost.java b/app/src/main/java/ml/docilealligator/infinityforreddit/post/ParsePost.java index 0685170a..834db92f 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/post/ParsePost.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/post/ParsePost.java @@ -541,7 +541,7 @@ public class ParsePost { } } catch (IllegalArgumentException ignore) { } } else if (post.getPostType() == Post.LINK_TYPE || post.getPostType() == Post.NO_PREVIEW_LINK_TYPE) { - if (data.has(JSONUtils.GALLERY_DATA_KEY)) { + if (!data.isNull(JSONUtils.GALLERY_DATA_KEY)) { JSONArray galleryIdsArray = data.getJSONObject(JSONUtils.GALLERY_DATA_KEY).getJSONArray(JSONUtils.ITEMS_KEY); JSONObject galleryObject = data.getJSONObject(JSONUtils.MEDIA_METADATA_KEY); ArrayList<Post.Gallery> gallery = new ArrayList<>(); diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/utils/Utils.java b/app/src/main/java/ml/docilealligator/infinityforreddit/utils/Utils.java index e7ee8d6a..41bb5e98 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/utils/Utils.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/utils/Utils.java @@ -49,7 +49,7 @@ import ml.docilealligator.infinityforreddit.SortType; import ml.docilealligator.infinityforreddit.UploadedImage; import retrofit2.Retrofit; -public class Utils { +public final class Utils { public static final int NETWORK_TYPE_OTHER = -1; public static final int NETWORK_TYPE_WIFI = 0; public static final int NETWORK_TYPE_CELLULAR = 1; @@ -60,21 +60,36 @@ public class Utils { private static final long MONTH_MILLIS = 30 * DAY_MILLIS; private static final long YEAR_MILLIS = 12 * MONTH_MILLIS; + public static final Pattern[] REGEX_PATTERN = { + Pattern.compile("((?<=[\\s])|^)/[rRuU]/[\\w-]+/{0,1}"), + Pattern.compile("((?<=[\\s])|^)[rRuU]/[\\w-]+/{0,1}"), + Pattern.compile("\\^{2,}"), + Pattern.compile("(^|^ *|\\n *)#(?!($|\\s|#))"), + Pattern.compile("(^|^ *|\\n *)##(?!($|\\s|#))"), + Pattern.compile("(^|^ *|\\n *)###(?!($|\\s|#))"), + Pattern.compile("(^|^ *|\\n *)####(?!($|\\s|#))"), + Pattern.compile("(^|^ *|\\n *)#####(?!($|\\s|#))"), + Pattern.compile("(^|^ *|\\n *)######(?!($|\\s|#))"), + Pattern.compile("!\\[gif]\\(giphy\\|\\w+\\)"), + Pattern.compile("!\\[gif]\\(giphy\\|\\w+\\|downsized\\)"), + Pattern.compile("!\\[gif]\\(emote\\|\\w+\\|\\w+\\)"), + Pattern.compile("!\\[img]\\(emote\\|\\w+\\|\\w+\\)") + }; + public static String modifyMarkdown(String markdown) { - StringBuilder regexed = new StringBuilder(markdown - .replaceAll("((?<=[\\s])|^)/[rRuU]/[\\w-]+/{0,1}", "[$0](https://www.reddit.com$0)") - .replaceAll("((?<=[\\s])|^)[rRuU]/[\\w-]+/{0,1}", "[$0](https://www.reddit.com/$0)") - .replaceAll("\\^{2,}", "^") - .replaceAll("(^|^ *|\\n *)#(?!($|\\s|#))", "$0 ") - .replaceAll("(^|^ *|\\n *)##(?!($|\\s|#))", "$0 ") - .replaceAll("(^|^ *|\\n *)###(?!($|\\s|#))", "$0 ") - .replaceAll("(^|^ *|\\n *)####(?!($|\\s|#))", "$0 ") - .replaceAll("(^|^ *|\\n *)#####(?!($|\\s|#))", "$0 ") - .replaceAll("(^|^ *|\\n *)######(?!($|\\s|#))", "$0 ")); + String regexed = REGEX_PATTERN[0].matcher(markdown).replaceAll("[$0](https://www.reddit.com$0)"); + regexed = REGEX_PATTERN[1].matcher(regexed).replaceAll("[$0](https://www.reddit.com/$0)"); + regexed = REGEX_PATTERN[2].matcher(regexed).replaceAll("^"); + regexed = REGEX_PATTERN[3].matcher(regexed).replaceAll("$0"); + regexed = REGEX_PATTERN[4].matcher(regexed).replaceAll("$0"); + regexed = REGEX_PATTERN[5].matcher(regexed).replaceAll("$0"); + regexed = REGEX_PATTERN[6].matcher(regexed).replaceAll("$0"); + regexed = REGEX_PATTERN[7].matcher(regexed).replaceAll("$0"); + regexed = REGEX_PATTERN[8].matcher(regexed).replaceAll("$0"); //return fixSuperScript(regexed); // We don't want to fix super scripts here because we need the original markdown later for editing posts - return regexed.toString(); + return regexed; } public static String fixSuperScript(String regexedMarkdown) { @@ -121,21 +136,21 @@ public class Utils { public static String parseInlineGifInComments(String markdown) { StringBuilder markdownStringBuilder = new StringBuilder(markdown); - Pattern inlineGifPattern = Pattern.compile("!\\[gif]\\(giphy\\|\\w+\\)"); + Pattern inlineGifPattern = REGEX_PATTERN[9]; Matcher matcher = inlineGifPattern.matcher(markdownStringBuilder); while (matcher.find()) { - markdownStringBuilder.replace(matcher.start(), matcher.end(), "[gif](https://media3.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 = Pattern.compile("!\\[gif]\\(giphy\\|\\w+\\|downsized\\)"); + Pattern inlineGifPattern2 = REGEX_PATTERN[10]; Matcher matcher2 = inlineGifPattern2.matcher(markdownStringBuilder); while (matcher2.find()) { - markdownStringBuilder.replace(matcher2.start(), matcher2.end(), "[gif](https://media3.giphy.com/media/" + markdownStringBuilder.substring(matcher2.start() + "![gif](giphy|".length(), matcher2.end() - "|downsized\\)".length()) + "/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); } - Pattern inlineGifPattern3 = Pattern.compile("!\\[gif]\\(emote\\|\\w+\\|\\w+\\)"); + Pattern inlineGifPattern3 = REGEX_PATTERN[11]; Matcher matcher3 = inlineGifPattern3.matcher(markdownStringBuilder); while (matcher3.find()) { markdownStringBuilder.replace(matcher3.start(), matcher3.end(), |