diff --git a/app/src/main/java/eu/faircode/email/HtmlEx.java b/app/src/main/java/eu/faircode/email/HtmlEx.java
index 5cfceaccd2..f6db9f051c 100644
--- a/app/src/main/java/eu/faircode/email/HtmlEx.java
+++ b/app/src/main/java/eu/faircode/email/HtmlEx.java
@@ -211,7 +211,7 @@ public class HtmlEx {
private /* static */ void withinBlockquoteIndividual(StringBuilder out, Spanned text, int start,
int end) {
- boolean isInList = false;
+ Boolean isInBulletList = null;
int next;
for (int i = start; i <= end; i = next) {
next = TextUtils.indexOf(text, '\n', i, end);
@@ -220,42 +220,47 @@ public class HtmlEx {
}
if (next == i) {
- if (isInList) {
+ if (isInBulletList != null) {
// Current paragraph is no longer a list item; close the previously opened list
- isInList = false;
- out.append("\n");
+ out.append(isInBulletList ? "\n" : "\n");
+ isInBulletList = null;
}
out.append("
\n");
} else {
- boolean isListItem = false;
+ Boolean isBulletListItem = null;
ParagraphStyle[] paragraphStyles = text.getSpans(i, next, ParagraphStyle.class);
for (ParagraphStyle paragraphStyle : paragraphStyles) {
final int spanFlags = text.getSpanFlags(paragraphStyle);
if ((spanFlags & Spanned.SPAN_PARAGRAPH) == Spanned.SPAN_PARAGRAPH
&& paragraphStyle instanceof BulletSpan) {
- isListItem = true;
+ isBulletListItem = !(paragraphStyle instanceof eu.faircode.email.NumberSpan);
break;
}
}
- if (isListItem && !isInList) {
+ if (isBulletListItem != null && isInBulletList != null && isBulletListItem != isInBulletList) {
+ out.append(isInBulletList ? "\n" : "\n");
+ isInBulletList = null;
+ }
+
+ if (isBulletListItem != null && isInBulletList == null) {
// Current paragraph is the first item in a list
- isInList = true;
- out.append("
\n");
}
- if (isInList && !isListItem) {
+ if (isInBulletList != null && isBulletListItem == null) {
// Current paragraph is no longer a list item; close the previously opened list
- isInList = false;
- out.append("
\n");
+ out.append(isInBulletList ? "\n" : "\n");
+ isInBulletList = null;
}
- String tagType = isListItem ? "li" : "p";
+ String tagType = isBulletListItem != null ? "li" : "p";
out.append("<").append(tagType)
.append(getTextDirection(text, i, next))
- .append(getTextStyles(text, i, next, !isListItem, true))
+ .append(getTextStyles(text, i, next, isBulletListItem == null, true))
.append(">");
withinParagraph(out, text, i, next);
@@ -264,9 +269,9 @@ public class HtmlEx {
out.append(tagType);
out.append(">\n");
- if (next == end && isInList) {
- isInList = false;
- out.append("\n");
+ if (next == end && isInBulletList != null) {
+ out.append(isInBulletList ? "\n" : "\n");
+ isInBulletList = null;
}
}
diff --git a/app/src/main/java/eu/faircode/email/HtmlHelper.java b/app/src/main/java/eu/faircode/email/HtmlHelper.java
index 5a1cce454d..97260e93ef 100644
--- a/app/src/main/java/eu/faircode/email/HtmlHelper.java
+++ b/app/src/main/java/eu/faircode/email/HtmlHelper.java
@@ -767,22 +767,6 @@ public class HtmlHelper {
for (Element subp : document.select("sub,sup"))
subp.tagName("small");
- // Lists
- // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/li
- if (!view) {
- for (Element li : document.select("li")) {
- Element parent = li.parent();
- if (parent == null || "ul".equals(parent.tagName()))
- continue; // li.prependText("• ");
- else
- li.prependText((li.elementSiblingIndex() + 1) + ". ");
- li.tagName("span");
- li.appendElement("br"); // line break after list item
- }
- document.select("ol").tagName("div");
- //document.select("ul").tagName("div");
- }
-
// Tables
// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/table
for (Element col : document.select("th,td")) {
@@ -2291,7 +2275,7 @@ public class HtmlHelper {
int s = start.get(spans[i]);
int e = end.get(spans[i]);
int f = flags.get(spans[i]);
- if (spans[i] instanceof BulletSpan)
+ if (spans[i] instanceof BulletSpan || spans[i] instanceof NumberSpan)
if (s > 1 && ssb.charAt(s - 1) == '\n' &&
e > 1 && ssb.charAt(e - 1) == '\n')
f |= Spanned.SPAN_PARAGRAPH;
@@ -2349,42 +2333,6 @@ public class HtmlHelper {
return reverse;
}
- private static class NumberSpan implements LeadingMarginSpan {
- private TextPaint tp;
- private String number;
- private int margin;
-
- public NumberSpan(int gapWidth, int color, float textSize, int index) {
- tp = new TextPaint();
- tp.setStyle(Paint.Style.FILL);
- tp.setColor(color);
- tp.setTypeface(Typeface.MONOSPACE);
- tp.setTextSize(textSize);
-
- number = index + ".";
- margin = Math.round(tp.measureText(number) + gapWidth);
- }
-
- @Override
- public int getLeadingMargin(boolean first) {
- // https://issuetracker.google.com/issues/36956124
- // This is called before drawLeadingMargin to justify the text
- return margin;
- }
-
- @Override
- public void drawLeadingMargin(Canvas c, Paint p, int x, int dir, int top, int baseline, int bottom, CharSequence text, int start, int end, boolean first, Layout layout) {
- if (text instanceof Spanned &&
- ((Spanned) text).getSpanStart(this) == start) {
- float textSize = tp.getTextSize();
- if (textSize > p.getTextSize())
- tp.setTextSize(p.getTextSize());
- c.drawText(number, x + dir, baseline, tp);
- tp.setTextSize(textSize);
- }
- }
- }
-
public static class LineSpan extends ReplacementSpan {
private int lineColor;
private float strokeWidth;
diff --git a/app/src/main/java/eu/faircode/email/NumberSpan.java b/app/src/main/java/eu/faircode/email/NumberSpan.java
new file mode 100644
index 0000000000..06797f355b
--- /dev/null
+++ b/app/src/main/java/eu/faircode/email/NumberSpan.java
@@ -0,0 +1,64 @@
+package eu.faircode.email;
+
+/*
+ This file is part of FairEmail.
+
+ FairEmail is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ FairEmail is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with FairEmail. If not, see .
+
+ Copyright 2018-2020 by Marcel Bokhorst (M66B)
+*/
+
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Typeface;
+import android.text.Layout;
+import android.text.Spanned;
+import android.text.TextPaint;
+import android.text.style.BulletSpan;
+
+public class NumberSpan extends BulletSpan {
+ private TextPaint tp;
+ private String number;
+ private int margin;
+
+ public NumberSpan(int gapWidth, int color, float textSize, int index) {
+ tp = new TextPaint();
+ tp.setStyle(Paint.Style.FILL);
+ tp.setColor(color);
+ tp.setTypeface(Typeface.MONOSPACE);
+ tp.setTextSize(textSize);
+
+ number = index + ".";
+ margin = Math.round(tp.measureText(number) + gapWidth);
+ }
+
+ @Override
+ public int getLeadingMargin(boolean first) {
+ // https://issuetracker.google.com/issues/36956124
+ // This is called before drawLeadingMargin to justify the text
+ return margin;
+ }
+
+ @Override
+ public void drawLeadingMargin(Canvas c, Paint p, int x, int dir, int top, int baseline, int bottom, CharSequence text, int start, int end, boolean first, Layout layout) {
+ if (text instanceof Spanned &&
+ ((Spanned) text).getSpanStart(this) == start) {
+ float textSize = tp.getTextSize();
+ if (textSize > p.getTextSize())
+ tp.setTextSize(p.getTextSize());
+ c.drawText(number, x + dir, baseline, tp);
+ tp.setTextSize(textSize);
+ }
+ }
+}
diff --git a/app/src/main/java/eu/faircode/email/StyleHelper.java b/app/src/main/java/eu/faircode/email/StyleHelper.java
index e5798d94a6..4f87b389e4 100644
--- a/app/src/main/java/eu/faircode/email/StyleHelper.java
+++ b/app/src/main/java/eu/faircode/email/StyleHelper.java
@@ -2,6 +2,7 @@ package eu.faircode.email;
import android.app.Activity;
import android.app.Dialog;
+import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Typeface;
import android.os.Build;
@@ -16,6 +17,7 @@ import android.text.style.TypefaceSpan;
import android.text.style.URLSpan;
import android.text.style.UnderlineSpan;
import android.view.MenuItem;
+import android.view.SubMenu;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
@@ -96,9 +98,10 @@ public class StyleHelper {
popupMenu.inflate(R.menu.popup_style);
String[] fontNames = anchor.getResources().getStringArray(R.array.fontNameNames);
+ SubMenu smenu = popupMenu.getMenu().findItem(R.id.menu_style_font).getSubMenu();
for (int i = 0; i < fontNames.length; i++)
- popupMenu.getMenu().add(R.id.group_style_font, i, 4, fontNames[i]);
- popupMenu.getMenu().add(R.id.group_style_font, fontNames.length, 4, R.string.title_style_font_default);
+ smenu.add(R.id.group_style_font, i, 0, fontNames[i]);
+ smenu.add(R.id.group_style_font, fontNames.length, 0, R.string.title_style_font_default);
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
@@ -198,18 +201,25 @@ public class StyleHelper {
for (BulletSpan span : spans)
t.removeSpan(span);
- int colorAccent = Helper.resolveColor(etBody.getContext(), R.attr.colorAccent);
- int dp3 = Helper.dp2pixels(etBody.getContext(), 3);
- int dp6 = Helper.dp2pixels(etBody.getContext(), 6);
+ Context context = etBody.getContext();
+ int colorAccent = Helper.resolveColor(context, R.attr.colorAccent);
+ int dp3 = Helper.dp2pixels(context, 3);
+ int dp6 = Helper.dp2pixels(context, 6);
+ float textSize = Helper.getTextSize(context, 0);
+
int i = s;
int j = s + 1;
+ int index = 1;
while (j < e) {
if (i > 0 && t.charAt(i - 1) == '\n' && t.charAt(j) == '\n') {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P)
- t.setSpan(new BulletSpan(dp6, colorAccent), i, j + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE | Spanned.SPAN_PARAGRAPH);
+ if (item.getItemId() == R.id.menu_style_list_bullets)
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P)
+ t.setSpan(new BulletSpan(dp6, colorAccent), i, j + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE | Spanned.SPAN_PARAGRAPH);
+ else
+ t.setSpan(new BulletSpan(dp6, colorAccent, dp3), i, j + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE | Spanned.SPAN_PARAGRAPH);
else
- t.setSpan(new BulletSpan(dp6, colorAccent, dp3), i, j + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE | Spanned.SPAN_PARAGRAPH);
+ t.setSpan(new NumberSpan(dp6, colorAccent, textSize, index++), i, j + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE | Spanned.SPAN_PARAGRAPH);
i = j + 1;
}
diff --git a/app/src/main/res/menu/popup_style.xml b/app/src/main/res/menu/popup_style.xml
index 2481eb05dc..25365b6b76 100644
--- a/app/src/main/res/menu/popup_style.xml
+++ b/app/src/main/res/menu/popup_style.xml
@@ -1,20 +1,25 @@
+
-
-
-
+ -
+
+
+
+
+
+
+
-
+
+ -
+
+
+
+
Small
Medium
Large
+ Color …
+ List
+ Bullets
+ Numbered
Font
Default
- Color …
- Create list
Clear formatting
Insert link
diff --git a/patches/HtmlExNumber.patch b/patches/HtmlExNumber.patch
new file mode 100644
index 0000000000..db7c66386c
--- /dev/null
+++ b/patches/HtmlExNumber.patch
@@ -0,0 +1,87 @@
+diff --git a/app/src/main/java/eu/faircode/email/HtmlEx.java b/app/src/main/java/eu/faircode/email/HtmlEx.java
+index 5cfceaccd..f6db9f051 100644
+--- a/app/src/main/java/eu/faircode/email/HtmlEx.java
++++ b/app/src/main/java/eu/faircode/email/HtmlEx.java
+@@ -211,7 +211,7 @@ public class HtmlEx {
+
+ private /* static */ void withinBlockquoteIndividual(StringBuilder out, Spanned text, int start,
+ int end) {
+- boolean isInList = false;
++ Boolean isInBulletList = null;
+ int next;
+ for (int i = start; i <= end; i = next) {
+ next = TextUtils.indexOf(text, '\n', i, end);
+@@ -220,42 +220,47 @@ public class HtmlEx {
+ }
+
+ if (next == i) {
+- if (isInList) {
++ if (isInBulletList != null) {
+ // Current paragraph is no longer a list item; close the previously opened list
+- isInList = false;
+- out.append("\n");
++ out.append(isInBulletList ? "\n" : "\n");
++ isInBulletList = null;
+ }
+ out.append("
\n");
+ } else {
+- boolean isListItem = false;
++ Boolean isBulletListItem = null;
+ ParagraphStyle[] paragraphStyles = text.getSpans(i, next, ParagraphStyle.class);
+ for (ParagraphStyle paragraphStyle : paragraphStyles) {
+ final int spanFlags = text.getSpanFlags(paragraphStyle);
+ if ((spanFlags & Spanned.SPAN_PARAGRAPH) == Spanned.SPAN_PARAGRAPH
+ && paragraphStyle instanceof BulletSpan) {
+- isListItem = true;
++ isBulletListItem = !(paragraphStyle instanceof eu.faircode.email.NumberSpan);
+ break;
+ }
+ }
+
+- if (isListItem && !isInList) {
++ if (isBulletListItem != null && isInBulletList != null && isBulletListItem != isInBulletList) {
++ out.append(isInBulletList ? "\n" : "\n");
++ isInBulletList = null;
++ }
++
++ if (isBulletListItem != null && isInBulletList == null) {
+ // Current paragraph is the first item in a list
+- isInList = true;
+- out.append("\n");
+ }
+
+- if (isInList && !isListItem) {
++ if (isInBulletList != null && isBulletListItem == null) {
+ // Current paragraph is no longer a list item; close the previously opened list
+- isInList = false;
+- out.append("
\n");
++ out.append(isInBulletList ? "\n" : "\n");
++ isInBulletList = null;
+ }
+
+- String tagType = isListItem ? "li" : "p";
++ String tagType = isBulletListItem != null ? "li" : "p";
+ out.append("<").append(tagType)
+ .append(getTextDirection(text, i, next))
+- .append(getTextStyles(text, i, next, !isListItem, true))
++ .append(getTextStyles(text, i, next, isBulletListItem == null, true))
+ .append(">");
+
+ withinParagraph(out, text, i, next);
+@@ -264,9 +269,9 @@ public class HtmlEx {
+ out.append(tagType);
+ out.append(">\n");
+
+- if (next == end && isInList) {
+- isInList = false;
+- out.append("\n");
++ if (next == end && isInBulletList != null) {
++ out.append(isInBulletList ? "\n" : "\n");
++ isInBulletList = null;
+ }
+ }
+