mirror of https://github.com/M66B/FairEmail.git
Experiment: markdown support
This commit is contained in:
parent
8937b3e2a6
commit
3350c11980
|
@ -55,3 +55,4 @@ FairEmail uses parts or all of:
|
||||||
* [AG Filters Registry](https://github.com/AdguardTeam/FiltersRegistry). [GNU Lesser General Public License Version 3](https://github.com/AdguardTeam/FiltersRegistry/blob/master/LICENSE).
|
* [AG Filters Registry](https://github.com/AdguardTeam/FiltersRegistry). [GNU Lesser General Public License Version 3](https://github.com/AdguardTeam/FiltersRegistry/blob/master/LICENSE).
|
||||||
* [Certificate transparency for Android and JVM](https://github.com/appmattus/certificatetransparency). Copyright 2023 Appmattus Limited. [Apache License 2.0](https://github.com/appmattus/certificatetransparency/blob/main/LICENSE.md).
|
* [Certificate transparency for Android and JVM](https://github.com/appmattus/certificatetransparency). Copyright 2023 Appmattus Limited. [Apache License 2.0](https://github.com/appmattus/certificatetransparency/blob/main/LICENSE.md).
|
||||||
* [ZXing](https://github.com/zxing/zxing). Copyright (C) 2014 ZXing authors. [Apache License 2.0](https://github.com/zxing/zxing/blob/master/LICENSE).
|
* [ZXing](https://github.com/zxing/zxing). Copyright (C) 2014 ZXing authors. [Apache License 2.0](https://github.com/zxing/zxing/blob/master/LICENSE).
|
||||||
|
* [https://github.com/vsch/flexmark-java](flexmark-java). Copyright (c) 2015-2016, Atlassian Pty Ltd. Copyright (c) 2016-2018, Vladimir Schneider. [BSD-2-Clause license](https://github.com/vsch/flexmark-java/blob/master/LICENSE.txt).
|
||||||
|
|
|
@ -134,7 +134,11 @@ android {
|
||||||
'LICENSE-2.0.txt',
|
'LICENSE-2.0.txt',
|
||||||
'RELEASE.txt',
|
'RELEASE.txt',
|
||||||
'DebugProbesKt.bin',
|
'DebugProbesKt.bin',
|
||||||
'font_metrics.properties'
|
'font_metrics.properties',
|
||||||
|
'META-INF/LICENSE-LGPL-2.1.txt',
|
||||||
|
'META-INF/LICENSE-LGPL-3.txt',
|
||||||
|
'META-INF/LICENSE-W3C-TEST',
|
||||||
|
'META-INF/DEPENDENCIES'
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -557,6 +561,7 @@ dependencies {
|
||||||
def vcard_version = "0.12.1"
|
def vcard_version = "0.12.1"
|
||||||
def relinker_version = "1.4.5"
|
def relinker_version = "1.4.5"
|
||||||
def markwon_version = "4.6.2"
|
def markwon_version = "4.6.2"
|
||||||
|
def flexmark_version = "0.64.8"
|
||||||
def bouncycastle_version = "1.77"
|
def bouncycastle_version = "1.77"
|
||||||
def colorpicker_version = "0.0.15"
|
def colorpicker_version = "0.0.15"
|
||||||
def overscroll_version = "1.1.1"
|
def overscroll_version = "1.1.1"
|
||||||
|
@ -765,6 +770,13 @@ dependencies {
|
||||||
// https://mvnrepository.com/artifact/io.noties.markwon/core
|
// https://mvnrepository.com/artifact/io.noties.markwon/core
|
||||||
implementation "io.noties.markwon:core:$markwon_version"
|
implementation "io.noties.markwon:core:$markwon_version"
|
||||||
implementation "io.noties.markwon:html:$markwon_version"
|
implementation "io.noties.markwon:html:$markwon_version"
|
||||||
|
implementation "io.noties.markwon:editor:$markwon_version"
|
||||||
|
|
||||||
|
// https://github.com/vsch/flexmark-java
|
||||||
|
// https://mvnrepository.com/artifact/com.vladsch.flexmark/flexmark
|
||||||
|
//implementation "com.vladsch.flexmark:flexmark:$flexmark_version"
|
||||||
|
implementation "com.vladsch.flexmark:flexmark-ext-tables:$flexmark_version"
|
||||||
|
implementation "com.vladsch.flexmark:flexmark-html2md-converter:$flexmark_version"
|
||||||
|
|
||||||
// // https://github.com/QuadFlask/colorpicker
|
// // https://github.com/QuadFlask/colorpicker
|
||||||
//implementation "com.github.QuadFlask:colorpicker:$colorpicker_version"
|
//implementation "com.github.QuadFlask:colorpicker:$colorpicker_version"
|
||||||
|
|
|
@ -55,3 +55,4 @@ FairEmail uses parts or all of:
|
||||||
* [AG Filters Registry](https://github.com/AdguardTeam/FiltersRegistry). [GNU Lesser General Public License Version 3](https://github.com/AdguardTeam/FiltersRegistry/blob/master/LICENSE).
|
* [AG Filters Registry](https://github.com/AdguardTeam/FiltersRegistry). [GNU Lesser General Public License Version 3](https://github.com/AdguardTeam/FiltersRegistry/blob/master/LICENSE).
|
||||||
* [Certificate transparency for Android and JVM](https://github.com/appmattus/certificatetransparency). Copyright 2023 Appmattus Limited. [Apache License 2.0](https://github.com/appmattus/certificatetransparency/blob/main/LICENSE.md).
|
* [Certificate transparency for Android and JVM](https://github.com/appmattus/certificatetransparency). Copyright 2023 Appmattus Limited. [Apache License 2.0](https://github.com/appmattus/certificatetransparency/blob/main/LICENSE.md).
|
||||||
* [ZXing](https://github.com/zxing/zxing). Copyright (C) 2014 ZXing authors. [Apache License 2.0](https://github.com/zxing/zxing/blob/master/LICENSE).
|
* [ZXing](https://github.com/zxing/zxing). Copyright (C) 2014 ZXing authors. [Apache License 2.0](https://github.com/zxing/zxing/blob/master/LICENSE).
|
||||||
|
* [https://github.com/vsch/flexmark-java](flexmark-java). Copyright (c) 2015-2016, Atlassian Pty Ltd. Copyright (c) 2016-2018, Vladimir Schneider. [BSD-2-Clause license](https://github.com/vsch/flexmark-java/blob/master/LICENSE.txt).
|
||||||
|
|
|
@ -136,6 +136,12 @@ import androidx.recyclerview.widget.RecyclerView;
|
||||||
import com.google.android.material.bottomnavigation.BottomNavigationView;
|
import com.google.android.material.bottomnavigation.BottomNavigationView;
|
||||||
import com.google.android.material.bottomnavigation.LabelVisibilityMode;
|
import com.google.android.material.bottomnavigation.LabelVisibilityMode;
|
||||||
import com.google.android.material.snackbar.Snackbar;
|
import com.google.android.material.snackbar.Snackbar;
|
||||||
|
import com.vladsch.flexmark.ext.gfm.strikethrough.StrikethroughExtension;
|
||||||
|
import com.vladsch.flexmark.ext.tables.TablesExtension;
|
||||||
|
import com.vladsch.flexmark.html.HtmlRenderer;
|
||||||
|
import com.vladsch.flexmark.html2md.converter.FlexmarkHtmlConverter;
|
||||||
|
import com.vladsch.flexmark.parser.Parser;
|
||||||
|
import com.vladsch.flexmark.util.data.MutableDataSet;
|
||||||
|
|
||||||
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
|
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
|
||||||
import org.bouncycastle.cert.jcajce.JcaCertStore;
|
import org.bouncycastle.cert.jcajce.JcaCertStore;
|
||||||
|
@ -227,6 +233,9 @@ import javax.mail.util.ByteArrayDataSource;
|
||||||
import biweekly.ICalendar;
|
import biweekly.ICalendar;
|
||||||
import biweekly.component.VEvent;
|
import biweekly.component.VEvent;
|
||||||
import biweekly.property.Organizer;
|
import biweekly.property.Organizer;
|
||||||
|
import io.noties.markwon.Markwon;
|
||||||
|
import io.noties.markwon.editor.MarkwonEditor;
|
||||||
|
import io.noties.markwon.editor.MarkwonEditorTextWatcher;
|
||||||
|
|
||||||
public class FragmentCompose extends FragmentBase {
|
public class FragmentCompose extends FragmentBase {
|
||||||
private enum State {NONE, LOADING, LOADED}
|
private enum State {NONE, LOADING, LOADED}
|
||||||
|
@ -280,6 +289,7 @@ public class FragmentCompose extends FragmentBase {
|
||||||
|
|
||||||
private ContentResolver resolver;
|
private ContentResolver resolver;
|
||||||
private AdapterAttachment adapter;
|
private AdapterAttachment adapter;
|
||||||
|
private MarkwonEditorTextWatcher markwonWatcher;
|
||||||
|
|
||||||
private boolean autoscroll_editor;
|
private boolean autoscroll_editor;
|
||||||
private int compose_color;
|
private int compose_color;
|
||||||
|
@ -291,6 +301,7 @@ public class FragmentCompose extends FragmentBase {
|
||||||
private boolean style = false;
|
private boolean style = false;
|
||||||
private boolean media = true;
|
private boolean media = true;
|
||||||
private boolean compact = false;
|
private boolean compact = false;
|
||||||
|
private boolean markdown = false;
|
||||||
private int zoom = 0;
|
private int zoom = 0;
|
||||||
private boolean nav_color;
|
private boolean nav_color;
|
||||||
private boolean lt_enabled;
|
private boolean lt_enabled;
|
||||||
|
@ -1119,6 +1130,19 @@ public class FragmentCompose extends FragmentBase {
|
||||||
invalidateOptionsMenu();
|
invalidateOptionsMenu();
|
||||||
Helper.setViewsEnabled(view, false);
|
Helper.setViewsEnabled(view, false);
|
||||||
|
|
||||||
|
// https://noties.io/Markwon/docs/v4/editor/
|
||||||
|
try {
|
||||||
|
final Markwon markwon = Markwon.create(getContext());
|
||||||
|
final MarkwonEditor editor = MarkwonEditor.create(markwon);
|
||||||
|
markwonWatcher = MarkwonEditorTextWatcher.withPreRender(
|
||||||
|
editor,
|
||||||
|
Helper.getParallelExecutor(),
|
||||||
|
etBody);
|
||||||
|
} catch (Throwable ex) {
|
||||||
|
Log.e(ex);
|
||||||
|
markwonWatcher = null;
|
||||||
|
}
|
||||||
|
|
||||||
final DB db = DB.getInstance(getContext());
|
final DB db = DB.getInstance(getContext());
|
||||||
|
|
||||||
SimpleCursorAdapter cadapter = new SimpleCursorAdapter(
|
SimpleCursorAdapter cadapter = new SimpleCursorAdapter(
|
||||||
|
@ -1936,6 +1960,7 @@ public class FragmentCompose extends FragmentBase {
|
||||||
menu.findItem(R.id.menu_style).setEnabled(state == State.LOADED);
|
menu.findItem(R.id.menu_style).setEnabled(state == State.LOADED);
|
||||||
menu.findItem(R.id.menu_media).setEnabled(state == State.LOADED);
|
menu.findItem(R.id.menu_media).setEnabled(state == State.LOADED);
|
||||||
menu.findItem(R.id.menu_compact).setEnabled(state == State.LOADED);
|
menu.findItem(R.id.menu_compact).setEnabled(state == State.LOADED);
|
||||||
|
menu.findItem(R.id.menu_markdown).setEnabled(state == State.LOADED);
|
||||||
menu.findItem(R.id.menu_contact_group).setEnabled(state == State.LOADED);
|
menu.findItem(R.id.menu_contact_group).setEnabled(state == State.LOADED);
|
||||||
menu.findItem(R.id.menu_manage_android_contacts).setEnabled(state == State.LOADED);
|
menu.findItem(R.id.menu_manage_android_contacts).setEnabled(state == State.LOADED);
|
||||||
menu.findItem(R.id.menu_manage_local_contacts).setEnabled(state == State.LOADED);
|
menu.findItem(R.id.menu_manage_local_contacts).setEnabled(state == State.LOADED);
|
||||||
|
@ -1992,6 +2017,7 @@ public class FragmentCompose extends FragmentBase {
|
||||||
boolean send_chips = prefs.getBoolean("send_chips", true);
|
boolean send_chips = prefs.getBoolean("send_chips", true);
|
||||||
boolean send_dialog = prefs.getBoolean("send_dialog", true);
|
boolean send_dialog = prefs.getBoolean("send_dialog", true);
|
||||||
boolean image_dialog = prefs.getBoolean("image_dialog", true);
|
boolean image_dialog = prefs.getBoolean("image_dialog", true);
|
||||||
|
boolean experiments = prefs.getBoolean("experiments", false);
|
||||||
|
|
||||||
menu.findItem(R.id.menu_save_drafts).setChecked(save_drafts);
|
menu.findItem(R.id.menu_save_drafts).setChecked(save_drafts);
|
||||||
menu.findItem(R.id.menu_send_chips).setChecked(send_chips);
|
menu.findItem(R.id.menu_send_chips).setChecked(send_chips);
|
||||||
|
@ -2000,6 +2026,8 @@ public class FragmentCompose extends FragmentBase {
|
||||||
menu.findItem(R.id.menu_style).setChecked(style);
|
menu.findItem(R.id.menu_style).setChecked(style);
|
||||||
menu.findItem(R.id.menu_media).setChecked(media);
|
menu.findItem(R.id.menu_media).setChecked(media);
|
||||||
menu.findItem(R.id.menu_compact).setChecked(compact);
|
menu.findItem(R.id.menu_compact).setChecked(compact);
|
||||||
|
menu.findItem(R.id.menu_markdown).setChecked(markdown);
|
||||||
|
menu.findItem(R.id.menu_markdown).setVisible(experiments);
|
||||||
|
|
||||||
View image = media_bar.findViewById(R.id.menu_image);
|
View image = media_bar.findViewById(R.id.menu_image);
|
||||||
if (image != null)
|
if (image != null)
|
||||||
|
@ -2083,6 +2111,9 @@ public class FragmentCompose extends FragmentBase {
|
||||||
} else if (itemId == R.id.menu_compact) {
|
} else if (itemId == R.id.menu_compact) {
|
||||||
onMenuCompact();
|
onMenuCompact();
|
||||||
return true;
|
return true;
|
||||||
|
} else if (itemId == R.id.menu_markdown) {
|
||||||
|
onMenuMarkdown();
|
||||||
|
return true;
|
||||||
} else if (itemId == R.id.menu_contact_group) {
|
} else if (itemId == R.id.menu_contact_group) {
|
||||||
onMenuContactGroup();
|
onMenuContactGroup();
|
||||||
return true;
|
return true;
|
||||||
|
@ -2315,6 +2346,11 @@ public class FragmentCompose extends FragmentBase {
|
||||||
setCompact(compact);
|
setCompact(compact);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onMenuMarkdown() {
|
||||||
|
markdown = !markdown;
|
||||||
|
onAction(R.id.menu_save, "Markdown");
|
||||||
|
}
|
||||||
|
|
||||||
private void setCompact(boolean compact) {
|
private void setCompact(boolean compact) {
|
||||||
bottom_navigation.setLabelVisibilityMode(compact
|
bottom_navigation.setLabelVisibilityMode(compact
|
||||||
? LabelVisibilityMode.LABEL_VISIBILITY_UNLABELED
|
? LabelVisibilityMode.LABEL_VISIBILITY_UNLABELED
|
||||||
|
@ -4990,6 +5026,7 @@ public class FragmentCompose extends FragmentBase {
|
||||||
args.putString("subject", etSubject.getText().toString().trim());
|
args.putString("subject", etSubject.getText().toString().trim());
|
||||||
args.putCharSequence("loaded", (Spanned) etBody.getTag());
|
args.putCharSequence("loaded", (Spanned) etBody.getTag());
|
||||||
args.putCharSequence("spanned", etBody.getText());
|
args.putCharSequence("spanned", etBody.getText());
|
||||||
|
args.putBoolean("markdown", markdown);
|
||||||
args.putBoolean("signature", cbSignature.isChecked());
|
args.putBoolean("signature", cbSignature.isChecked());
|
||||||
args.putBoolean("empty", isEmpty());
|
args.putBoolean("empty", isEmpty());
|
||||||
args.putBoolean("notext", notext);
|
args.putBoolean("notext", notext);
|
||||||
|
@ -6171,6 +6208,9 @@ public class FragmentCompose extends FragmentBase {
|
||||||
Elements ref = doc.select("div[fairemail=reference]");
|
Elements ref = doc.select("div[fairemail=reference]");
|
||||||
ref.remove();
|
ref.remove();
|
||||||
|
|
||||||
|
boolean markdown = Boolean.parseBoolean(doc.body().attr("markdown"));
|
||||||
|
args.putBoolean("markdown", markdown);
|
||||||
|
|
||||||
File refFile = data.draft.getRefFile(context);
|
File refFile = data.draft.getRefFile(context);
|
||||||
if (refFile.exists()) {
|
if (refFile.exists()) {
|
||||||
ref.html(Helper.readText(refFile));
|
ref.html(Helper.readText(refFile));
|
||||||
|
@ -6243,6 +6283,7 @@ public class FragmentCompose extends FragmentBase {
|
||||||
working = data.draft.id;
|
working = data.draft.id;
|
||||||
dsn = (data.draft.dsn != null && !EntityMessage.DSN_NONE.equals(data.draft.dsn));
|
dsn = (data.draft.dsn != null && !EntityMessage.DSN_NONE.equals(data.draft.dsn));
|
||||||
encrypt = data.draft.ui_encrypt;
|
encrypt = data.draft.ui_encrypt;
|
||||||
|
markdown = args.getBoolean("markdown");
|
||||||
invalidateOptionsMenu();
|
invalidateOptionsMenu();
|
||||||
|
|
||||||
subject = data.draft.subject;
|
subject = data.draft.subject;
|
||||||
|
@ -6665,6 +6706,7 @@ public class FragmentCompose extends FragmentBase {
|
||||||
String subject = args.getString("subject");
|
String subject = args.getString("subject");
|
||||||
Spanned loaded = (Spanned) args.getCharSequence("loaded");
|
Spanned loaded = (Spanned) args.getCharSequence("loaded");
|
||||||
Spanned spanned = (Spanned) args.getCharSequence("spanned");
|
Spanned spanned = (Spanned) args.getCharSequence("spanned");
|
||||||
|
boolean markdown = args.getBoolean("markdown");
|
||||||
boolean signature = args.getBoolean("signature");
|
boolean signature = args.getBoolean("signature");
|
||||||
boolean empty = args.getBoolean("empty");
|
boolean empty = args.getBoolean("empty");
|
||||||
boolean notext = args.getBoolean("notext");
|
boolean notext = args.getBoolean("notext");
|
||||||
|
@ -6673,7 +6715,22 @@ public class FragmentCompose extends FragmentBase {
|
||||||
boolean silent = extras.getBoolean("silent");
|
boolean silent = extras.getBoolean("silent");
|
||||||
|
|
||||||
boolean dirty = false;
|
boolean dirty = false;
|
||||||
String body = HtmlHelper.toHtml(spanned, context);
|
String body;
|
||||||
|
if (markdown) {
|
||||||
|
MutableDataSet options = new MutableDataSet();
|
||||||
|
options.set(Parser.EXTENSIONS, Arrays.asList(
|
||||||
|
TablesExtension.create(),
|
||||||
|
StrikethroughExtension.create()));
|
||||||
|
Parser parser = Parser.builder(options).build();
|
||||||
|
HtmlRenderer renderer = HtmlRenderer.builder(options).build();
|
||||||
|
String html = renderer.render(parser.parse(spanned.toString()));
|
||||||
|
|
||||||
|
Document doc = JsoupEx.parse(html);
|
||||||
|
doc.body().attr("markdown", "true");
|
||||||
|
body = doc.html();
|
||||||
|
} else
|
||||||
|
body = HtmlHelper.toHtml(spanned, context);
|
||||||
|
|
||||||
EntityMessage draft;
|
EntityMessage draft;
|
||||||
|
|
||||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
|
@ -7581,12 +7638,15 @@ public class FragmentCompose extends FragmentBase {
|
||||||
Bundle args = new Bundle();
|
Bundle args = new Bundle();
|
||||||
args.putLong("id", draft.id);
|
args.putLong("id", draft.id);
|
||||||
args.putBoolean("show_images", show_images);
|
args.putBoolean("show_images", show_images);
|
||||||
|
args.putBoolean("markdown", markdown);
|
||||||
|
|
||||||
new SimpleTask<Spanned[]>() {
|
new SimpleTask<Spanned[]>() {
|
||||||
@Override
|
@Override
|
||||||
protected void onPreExecute(Bundle args) {
|
protected void onPreExecute(Bundle args) {
|
||||||
// Needed to get width for images
|
// Needed to get width for images
|
||||||
grpBody.setVisibility(View.VISIBLE);
|
grpBody.setVisibility(View.VISIBLE);
|
||||||
|
if (markwonWatcher != null)
|
||||||
|
etBody.removeTextChangedListener(markwonWatcher);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -7602,12 +7662,18 @@ public class FragmentCompose extends FragmentBase {
|
||||||
Helper.setViewsEnabled(view, true);
|
Helper.setViewsEnabled(view, true);
|
||||||
|
|
||||||
invalidateOptionsMenu();
|
invalidateOptionsMenu();
|
||||||
|
|
||||||
|
if (markdown && markwonWatcher != null) {
|
||||||
|
etBody.addTextChangedListener(markwonWatcher);
|
||||||
|
markwonWatcher.afterTextChanged(etBody.getText());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Spanned[] onExecute(final Context context, Bundle args) throws Throwable {
|
protected Spanned[] onExecute(final Context context, Bundle args) throws Throwable {
|
||||||
final long id = args.getLong("id");
|
final long id = args.getLong("id");
|
||||||
final boolean show_images = args.getBoolean("show_images", false);
|
final boolean show_images = args.getBoolean("show_images", false);
|
||||||
|
final boolean markdown = args.getBoolean("markdown", false);
|
||||||
|
|
||||||
int colorPrimary = Helper.resolveColor(context, androidx.appcompat.R.attr.colorPrimary);
|
int colorPrimary = Helper.resolveColor(context, androidx.appcompat.R.attr.colorPrimary);
|
||||||
final int colorBlockquote = Helper.resolveColor(context, R.attr.colorBlockquote, colorPrimary);
|
final int colorBlockquote = Helper.resolveColor(context, R.attr.colorBlockquote, colorPrimary);
|
||||||
|
@ -7624,35 +7690,41 @@ public class FragmentCompose extends FragmentBase {
|
||||||
Elements ref = doc.select("div[fairemail=reference]");
|
Elements ref = doc.select("div[fairemail=reference]");
|
||||||
ref.remove();
|
ref.remove();
|
||||||
|
|
||||||
HtmlHelper.clearAnnotations(doc); // Legacy left-overs
|
Spanned spannedBody;
|
||||||
|
if (markdown) {
|
||||||
|
MutableDataSet options = new MutableDataSet();
|
||||||
|
spannedBody = new SpannableStringBuilder(FlexmarkHtmlConverter.builder(options).build().convert(doc.html()));
|
||||||
|
} else {
|
||||||
|
HtmlHelper.clearAnnotations(doc); // Legacy left-overs
|
||||||
|
|
||||||
doc = HtmlHelper.sanitizeCompose(context, doc.html(), true);
|
doc = HtmlHelper.sanitizeCompose(context, doc.html(), true);
|
||||||
|
|
||||||
Spanned spannedBody = HtmlHelper.fromDocument(context, doc, new HtmlHelper.ImageGetterEx() {
|
spannedBody = HtmlHelper.fromDocument(context, doc, new HtmlHelper.ImageGetterEx() {
|
||||||
@Override
|
@Override
|
||||||
public Drawable getDrawable(Element element) {
|
public Drawable getDrawable(Element element) {
|
||||||
return ImageHelper.decodeImage(context,
|
return ImageHelper.decodeImage(context,
|
||||||
id, element, true, zoom, 1.0f, etBody);
|
id, element, true, zoom, 1.0f, etBody);
|
||||||
|
}
|
||||||
|
}, null);
|
||||||
|
|
||||||
|
SpannableStringBuilder bodyBuilder = new SpannableStringBuilderEx(spannedBody);
|
||||||
|
QuoteSpan[] bodySpans = bodyBuilder.getSpans(0, bodyBuilder.length(), QuoteSpan.class);
|
||||||
|
for (QuoteSpan quoteSpan : bodySpans) {
|
||||||
|
QuoteSpan q;
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P)
|
||||||
|
q = new QuoteSpan(colorBlockquote);
|
||||||
|
else
|
||||||
|
q = new QuoteSpan(colorBlockquote, quoteStripe, quoteGap);
|
||||||
|
bodyBuilder.setSpan(q,
|
||||||
|
bodyBuilder.getSpanStart(quoteSpan),
|
||||||
|
bodyBuilder.getSpanEnd(quoteSpan),
|
||||||
|
bodyBuilder.getSpanFlags(quoteSpan));
|
||||||
|
bodyBuilder.removeSpan(quoteSpan);
|
||||||
}
|
}
|
||||||
}, null);
|
|
||||||
|
|
||||||
SpannableStringBuilder bodyBuilder = new SpannableStringBuilderEx(spannedBody);
|
spannedBody = bodyBuilder;
|
||||||
QuoteSpan[] bodySpans = bodyBuilder.getSpans(0, bodyBuilder.length(), QuoteSpan.class);
|
|
||||||
for (QuoteSpan quoteSpan : bodySpans) {
|
|
||||||
QuoteSpan q;
|
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P)
|
|
||||||
q = new QuoteSpan(colorBlockquote);
|
|
||||||
else
|
|
||||||
q = new QuoteSpan(colorBlockquote, quoteStripe, quoteGap);
|
|
||||||
bodyBuilder.setSpan(q,
|
|
||||||
bodyBuilder.getSpanStart(quoteSpan),
|
|
||||||
bodyBuilder.getSpanEnd(quoteSpan),
|
|
||||||
bodyBuilder.getSpanFlags(quoteSpan));
|
|
||||||
bodyBuilder.removeSpan(quoteSpan);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
spannedBody = bodyBuilder;
|
|
||||||
|
|
||||||
Spanned spannedRef = null;
|
Spanned spannedRef = null;
|
||||||
if (!ref.isEmpty()) {
|
if (!ref.isEmpty()) {
|
||||||
Document dref = JsoupEx.parse(ref.outerHtml());
|
Document dref = JsoupEx.parse(ref.outerHtml());
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24"
|
||||||
|
android:tint="?attr/colorControlNormal">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M15,4l0,2l3,0l0,12l-3,0l0,2l5,0l0,-16z"/>
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M4,20l5,0l0,-2l-3,0l0,-12l3,0l0,-2l-5,0z"/>
|
||||||
|
</vector>
|
|
@ -79,6 +79,13 @@
|
||||||
android:icon="@drawable/outline_unfold_less_24"
|
android:icon="@drawable/outline_unfold_less_24"
|
||||||
android:title="@string/title_compact"
|
android:title="@string/title_compact"
|
||||||
app:showAsAction="never" />
|
app:showAsAction="never" />
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/menu_markdown"
|
||||||
|
android:checkable="true"
|
||||||
|
android:icon="@drawable/twotone_data_array_24"
|
||||||
|
android:title="@string/title_markdown"
|
||||||
|
app:showAsAction="never" />
|
||||||
</group>
|
</group>
|
||||||
|
|
||||||
<group android:id="@+id/group_operations">
|
<group android:id="@+id/group_operations">
|
||||||
|
|
|
@ -1739,6 +1739,7 @@
|
||||||
<string name="title_image_dialog">Show image options</string>
|
<string name="title_image_dialog">Show image options</string>
|
||||||
<string name="title_style_toolbar">Style toolbar</string>
|
<string name="title_style_toolbar">Style toolbar</string>
|
||||||
<string name="title_media_toolbar">Media toolbar</string>
|
<string name="title_media_toolbar">Media toolbar</string>
|
||||||
|
<string name="title_markdown" translatable="false">Markdown</string>
|
||||||
<string name="title_manage_android_contacts">Manage Android\'s contacts</string>
|
<string name="title_manage_android_contacts">Manage Android\'s contacts</string>
|
||||||
<string name="title_manage_local_contacts">Manage local contacts</string>
|
<string name="title_manage_local_contacts">Manage local contacts</string>
|
||||||
<string name="title_insert_contact_group">Insert contact group</string>
|
<string name="title_insert_contact_group">Insert contact group</string>
|
||||||
|
|
Loading…
Reference in New Issue