summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas <tschneider.ac@gmail.com>2023-08-07 17:03:14 +0200
committerThomas <tschneider.ac@gmail.com>2023-08-07 17:03:14 +0200
commite954fd860a946950ca39c96857b62e83db799492 (patch)
treeef4a03d2ba51e8974e0370f3f129c26474195f4e
parent6790158ed960ad25a55135870aac08bb1da4571a (diff)
Markdown support
-rw-r--r--app/build.gradle5
-rw-r--r--app/src/main/java/app/fedilab/android/MainApplication.java2
-rw-r--r--app/src/main/java/app/fedilab/android/mastodon/client/entities/app/MarkdownConverter.java10
-rw-r--r--app/src/main/java/app/fedilab/android/mastodon/helper/SpannableHelper.java99
-rw-r--r--app/src/main/res/values/strings.xml2
-rw-r--r--app/src/main/res/xml/pref_timelines.xml7
6 files changed, 93 insertions, 32 deletions
diff --git a/app/build.gradle b/app/build.gradle
index beb7c2618..0322bcae1 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -85,6 +85,8 @@ android {
}
}
configurations {
+ cleanedAnnotations
+ implementation.exclude group: 'org.jetbrains', module: 'annotations'
all {
exclude group: 'androidx.lifecycle', module: 'lifecycle-viewmodel-ktx'
}
@@ -186,6 +188,9 @@ dependencies {
implementation 'io.noties.markwon:core:4.6.2'
+ implementation 'io.noties.markwon:ext-tables:4.6.2'
+ implementation 'io.noties.markwon:syntax-highlight:4.6.2'
+ annotationProcessor 'io.noties:prism4j-bundler:2.0.0'
//************ CAST **************///
diff --git a/app/src/main/java/app/fedilab/android/MainApplication.java b/app/src/main/java/app/fedilab/android/MainApplication.java
index 8ad75b088..4192a96d0 100644
--- a/app/src/main/java/app/fedilab/android/MainApplication.java
+++ b/app/src/main/java/app/fedilab/android/MainApplication.java
@@ -42,7 +42,9 @@ import java.util.Objects;
import app.fedilab.android.mastodon.helper.ThemeHelper;
import app.fedilab.android.peertube.services.GlobalUploadObserver;
import es.dmoral.toasty.Toasty;
+import io.noties.prism4j.annotations.PrismBundle;
+@PrismBundle(includeAll = true, grammarLocatorClassName = ".MySuperGrammerLocator")
public class MainApplication extends MultiDexApplication {
diff --git a/app/src/main/java/app/fedilab/android/mastodon/client/entities/app/MarkdownConverter.java b/app/src/main/java/app/fedilab/android/mastodon/client/entities/app/MarkdownConverter.java
index 54dd38d58..cc074fb6d 100644
--- a/app/src/main/java/app/fedilab/android/mastodon/client/entities/app/MarkdownConverter.java
+++ b/app/src/main/java/app/fedilab/android/mastodon/client/entities/app/MarkdownConverter.java
@@ -37,5 +37,15 @@ public class MarkdownConverter {
public String code;
public int position;
public URLSpan urlSpan;
+
+ public int regexPosition(List<MarkdownItem> markdownItems) {
+ int position = 0;
+ for (MarkdownItem markdownItem : markdownItems) {
+ if (markdownItem.code.equals(code) && position <= this.position) {
+ position++;
+ }
+ }
+ return position;
+ }
}
}
diff --git a/app/src/main/java/app/fedilab/android/mastodon/helper/SpannableHelper.java b/app/src/main/java/app/fedilab/android/mastodon/helper/SpannableHelper.java
index 50c4d847c..5341c3776 100644
--- a/app/src/main/java/app/fedilab/android/mastodon/helper/SpannableHelper.java
+++ b/app/src/main/java/app/fedilab/android/mastodon/helper/SpannableHelper.java
@@ -43,6 +43,7 @@ import android.view.View;
import android.webkit.URLUtil;
import android.widget.Toast;
+import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.core.content.ContextCompat;
@@ -71,6 +72,7 @@ import java.util.regex.Pattern;
import javax.net.ssl.HttpsURLConnection;
import app.fedilab.android.BaseMainActivity;
+import app.fedilab.android.MySuperGrammerLocator;
import app.fedilab.android.R;
import app.fedilab.android.activities.MainActivity;
import app.fedilab.android.databinding.PopupLinksBinding;
@@ -89,6 +91,10 @@ import app.fedilab.android.mastodon.ui.drawer.StatusAdapter;
import app.fedilab.android.mastodon.viewmodel.mastodon.FiltersVM;
import es.dmoral.toasty.Toasty;
import io.noties.markwon.Markwon;
+import io.noties.markwon.ext.tables.TablePlugin;
+import io.noties.markwon.syntax.Prism4jThemeDefault;
+import io.noties.markwon.syntax.SyntaxHighlightPlugin;
+import io.noties.prism4j.Prism4j;
public class SpannableHelper {
@@ -149,44 +155,56 @@ public class SpannableHelper {
} else {
initialContent = new SpannableString(text);
}
-
+ boolean markdownSupport = sharedpreferences.getBoolean(context.getString(R.string.SET_MARKDOWN_SUPPORT), true);
//Get all links
- MarkdownConverter markdownConverter = new MarkdownConverter();
- markdownConverter.markdownItems = new ArrayList<>();
- int next;
- int position = 0;
- for (int i = 0; i < initialContent.length(); i = next) {
- // find the next span transition
- next = initialContent.nextSpanTransition(i, initialContent.length(), URLSpan.class);
- MarkdownConverter.MarkdownItem markdownItem = new MarkdownConverter.MarkdownItem();
- markdownItem.code = initialContent.subSequence(i, next).toString();
-
- markdownItem.position = position;
- // get all spans in this range
- URLSpan[] spans = initialContent.getSpans(i, next, URLSpan.class);
- if (spans != null && spans.length > 0) {
- markdownItem.urlSpan = spans[0];
+ SpannableStringBuilder content;
+ if (markdownSupport) {
+ MarkdownConverter markdownConverter = new MarkdownConverter();
+ markdownConverter.markdownItems = new ArrayList<>();
+ int next;
+ int position = 0;
+ for (int i = 0; i < initialContent.length(); i = next) {
+ // find the next span transition
+ next = initialContent.nextSpanTransition(i, initialContent.length(), URLSpan.class);
+ MarkdownConverter.MarkdownItem markdownItem = new MarkdownConverter.MarkdownItem();
+ markdownItem.code = initialContent.subSequence(i, next).toString();
+
+ markdownItem.position = position;
+ // get all spans in this range
+ URLSpan[] spans = initialContent.getSpans(i, next, URLSpan.class);
+ if (spans != null && spans.length > 0) {
+ markdownItem.urlSpan = spans[0];
+ }
+
+ if (markdownItem.code.trim().length() > 0) {
+ markdownConverter.markdownItems.add(markdownItem);
+ position++;
+ }
}
- if (markdownItem.code.trim().length() > 0) {
- markdownConverter.markdownItems.add(markdownItem);
+ final Markwon markwon = Markwon.builder(context)
+ .usePlugin(TablePlugin.create(context))
+ .usePlugin(SyntaxHighlightPlugin.create(new Prism4j(new MySuperGrammerLocator()), Prism4jThemeDefault.create())).build();
+
+ final Spanned markdown = markwon.toMarkdown(initialContent.toString());
+ content = new SpannableStringBuilder(markdown);
+ position = 0;
+ for (MarkdownConverter.MarkdownItem markdownItem : markdownConverter.markdownItems) {
+ Pattern p = Pattern.compile("(" + Pattern.quote(markdownItem.code) + ")", Pattern.CASE_INSENSITIVE);
+ Matcher m = p.matcher(content);
+ int fetchPosition = 1;
+ while (m.find()) {
+ int regexPosition = markdownItem.regexPosition(markdownConverter.markdownItems);
+ if (regexPosition == fetchPosition) {
+ content.setSpan(markdownItem.urlSpan, m.start(), m.end(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
+ }
+ fetchPosition++;
+ }
position++;
}
+ } else {
+ content = new SpannableStringBuilder(initialContent);
}
- final Markwon markwon = Markwon.create(context);
-
- final Spanned markdown = markwon.toMarkdown(initialContent.toString());
- SpannableStringBuilder content = new SpannableStringBuilder(markdown);
- position = 0;
- for (MarkdownConverter.MarkdownItem markdownItem : markdownConverter.markdownItems) {
- Pattern p = Pattern.compile("(" + Pattern.quote(markdownItem.code) + ")", Pattern.CASE_INSENSITIVE);
- Matcher m = p.matcher(content);
- while (m.find()) {
- content.setSpan(markdownItem.urlSpan, m.start(), m.end(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
- }
- position++;
- }
-
URLSpan[] urls = content.getSpans(0, (content.length() - 1), URLSpan.class);
//Loop through links
@@ -336,6 +354,23 @@ public class SpannableHelper {
return trimSpannable(new SpannableStringBuilder(content));
}
+ public interface Prism4jTheme {
+
+ @ColorInt
+ int background();
+
+ @ColorInt
+ int textColor();
+
+ void apply(
+ @NonNull String language,
+ @NonNull Prism4j.Syntax syntax,
+ @NonNull SpannableStringBuilder builder,
+ int start,
+ int end
+ );
+ }
+
private static void makeLinks(Context context, SpannableStringBuilder content, String url, int start, int end) {
String newUrl = url;
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 5697d8511..45dee809f 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1156,6 +1156,7 @@
<string name="SET_GROUP_REBLOGS" translatable="false">SET_GROUP_REBLOGS</string>
<string name="SET_BOOST_ORIGINAL_DATE" translatable="false">SET_BOOST_ORIGINAL_DATE</string>
+ <string name="SET_MARKDOWN_SUPPORT" translatable="false">SET_MARKDOWN_SUPPORT</string>
<string name="SET_TRUNCATE_LINKS" translatable="false">SET_TRUNCATE_LINKS</string>
<string name="SET_TRUNCATE_LINKS_MAX" translatable="false">SET_TRUNCATE_LINKS_MAX</string>
@@ -1907,6 +1908,7 @@
<string name="also_followed_by">Followed by:</string>
<string name="Directory">Directory</string>
<string name="boost_original_date">Display original date for boosts</string>
+ <string name="markdown_support">Markdown support</string>
<string name="set_disable_release_notes">Disable release notes</string>
<string name="set_disable_release_notes_indication">When a new version is published, you will not be alerted inside the app.</string>
<string name="formula">Formula</string>
diff --git a/app/src/main/res/xml/pref_timelines.xml b/app/src/main/res/xml/pref_timelines.xml
index 410c18e62..6c5fc27bd 100644
--- a/app/src/main/res/xml/pref_timelines.xml
+++ b/app/src/main/res/xml/pref_timelines.xml
@@ -53,6 +53,13 @@
<SwitchPreferenceCompat
android:defaultValue="true"
app:iconSpaceReserved="false"
+ app:key="@string/SET_MARKDOWN_SUPPORT"
+ app:singleLineTitle="false"
+ app:title="@string/markdown_support" />
+
+ <SwitchPreferenceCompat
+ android:defaultValue="true"
+ app:iconSpaceReserved="false"
app:key="@string/SET_TRUNCATE_LINKS"
app:singleLineTitle="false"
app:title="@string/truncate_links" />