Optionally show text colors

pull/162/head
M66B 6 years ago
parent 7b183675c3
commit 214774fa09

@ -139,7 +139,7 @@ public class ActivityEML extends ActivityBase {
result.html = parts.getHtml(context); result.html = parts.getHtml(context);
if (result.html != null) { if (result.html != null) {
result.body = HtmlHelper.fromHtml(HtmlHelper.sanitize(context, result.html, false)); result.body = HtmlHelper.fromHtml(HtmlHelper.sanitize(context, result.html, false, false));
if (result.html.length() > 100 * 1024) if (result.html.length() > 100 * 1024)
result.html = null; result.html = null;
} }

@ -2527,6 +2527,10 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
boolean show_quotes = args.getBoolean("show_quotes"); boolean show_quotes = args.getBoolean("show_quotes");
int zoom = args.getInt("zoom"); int zoom = args.getInt("zoom");
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean text_color = prefs.getBoolean("text_color", true);
boolean inline = prefs.getBoolean("inline_images", false);
if (message == null || !message.content) if (message == null || !message.content)
return null; return null;
@ -2537,9 +2541,6 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
String body = Helper.readText(file); String body = Helper.readText(file);
Document document = Jsoup.parse(body); Document document = Jsoup.parse(body);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean inline = prefs.getBoolean("inline_images", false);
boolean has_images = false; boolean has_images = false;
for (Element img : document.select("img")) { for (Element img : document.select("img")) {
if (inline) { if (inline) {
@ -2561,7 +2562,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
body = document.html(); body = document.html();
} }
String html = HtmlHelper.sanitize(context, body, show_images); String html = HtmlHelper.sanitize(context, body, text_color, show_images);
if (debug) { if (debug) {
Document format = Jsoup.parse(html); Document format = Jsoup.parse(html);
format.outputSettings().prettyPrint(true).outline(true).indentAmount(1); format.outputSettings().prettyPrint(true).outline(true).indentAmount(1);

@ -2011,6 +2011,7 @@ public class FragmentCompose extends FragmentBase {
long answer = args.getLong("answer", -1); long answer = args.getLong("answer", -1);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean text_color = prefs.getBoolean("text_color", true);
boolean plain_only = prefs.getBoolean("plain_only", false); boolean plain_only = prefs.getBoolean("plain_only", false);
Log.i("Load draft action=" + action + " id=" + id + " reference=" + reference); Log.i("Load draft action=" + action + " id=" + id + " reference=" + reference);
@ -2071,7 +2072,7 @@ public class FragmentCompose extends FragmentBase {
data.draft.subject = args.getString("subject", ""); data.draft.subject = args.getString("subject", "");
body = args.getString("body", ""); body = args.getString("body", "");
if (!TextUtils.isEmpty(body)) if (!TextUtils.isEmpty(body))
body = HtmlHelper.sanitize(context, body, false); body = HtmlHelper.sanitize(context, body, text_color, false);
if (answer > 0) { if (answer > 0) {
EntityAnswer a = db.answer().getAnswer(answer); EntityAnswer a = db.answer().getAnswer(answer);
@ -2137,7 +2138,7 @@ public class FragmentCompose extends FragmentBase {
data.draft.subject = ref.subject; data.draft.subject = ref.subject;
if (ref.content) { if (ref.content) {
String html = Helper.readText(ref.getFile(context)); String html = Helper.readText(ref.getFile(context));
body = HtmlHelper.sanitize(context, html, true); body = HtmlHelper.sanitize(context, html, text_color, true);
} }
} else if ("list".equals(action)) { } else if ("list".equals(action)) {
data.draft.subject = ref.subject; data.draft.subject = ref.subject;
@ -2371,7 +2372,7 @@ public class FragmentCompose extends FragmentBase {
if (data.draft.content) { if (data.draft.content) {
File file = data.draft.getFile(context); File file = data.draft.getFile(context);
String html = Helper.readText(file); String html = Helper.readText(file);
html = HtmlHelper.sanitize(context, html, true); html = HtmlHelper.sanitize(context, html, true, true);
Helper.writeText(file, html); Helper.writeText(file, html);
} else { } else {
if (data.draft.uid == null) if (data.draft.uid == null)
@ -3065,6 +3066,9 @@ public class FragmentCompose extends FragmentBase {
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);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean text_color = prefs.getBoolean("text_color", true);
DB db = DB.getInstance(context); DB db = DB.getInstance(context);
EntityMessage draft = db.message().getMessage(id); EntityMessage draft = db.message().getMessage(id);
if (draft == null || !draft.content) if (draft == null || !draft.content)
@ -3076,7 +3080,7 @@ public class FragmentCompose extends FragmentBase {
Spanned spannedRef = null; Spanned spannedRef = null;
File refFile = draft.getRefFile(context); File refFile = draft.getRefFile(context);
if (refFile.exists()) { if (refFile.exists()) {
String quote = HtmlHelper.sanitize(context, Helper.readText(refFile), show_images); String quote = HtmlHelper.sanitize(context, Helper.readText(refFile), text_color, show_images);
Spanned spannedQuote = HtmlHelper.fromHtml(quote, Spanned spannedQuote = HtmlHelper.fromHtml(quote,
new Html.ImageGetter() { new Html.ImageGetter() {
@Override @Override

@ -41,7 +41,9 @@ public class FragmentOptions extends FragmentBase {
"subscriptions", "subscriptions",
"startup", "cards", "date", "threading", "highlight_unread", "avatars", "generated_icons", "identicons", "circular", "startup", "cards", "date", "threading", "highlight_unread", "avatars", "generated_icons", "identicons", "circular",
"name_email", "authentication", "subject_top", "subject_italic", "subject_ellipsize", "flags", "preview", "preview_italic", "name_email", "authentication", "subject_top", "subject_italic", "subject_ellipsize", "flags", "preview", "preview_italic",
"addresses", "attachments_alt", "contrast", "monospaced", "inline_images", "collapse_quotes", "autocontent", "seekbar", "actionbar", "addresses", "attachments_alt",
"contrast", "monospaced", "text_color",
"inline_images", "collapse_quotes", "autocontent", "seekbar", "actionbar",
"autoscroll", "swipenav", "autoexpand", "autoclose", "onclose", "autoscroll", "swipenav", "autoexpand", "autoclose", "onclose",
"experiments", "debug", "experiments", "debug",
"biometrics" "biometrics"

@ -66,8 +66,9 @@ public class FragmentOptionsDisplay extends FragmentBase implements SharedPrefer
private SwitchCompat swContrast; private SwitchCompat swContrast;
private SwitchCompat swMonospaced; private SwitchCompat swMonospaced;
private SwitchCompat swImagesInline; private SwitchCompat swTextColor;
private SwitchCompat swCollapseQuotes; private SwitchCompat swCollapseQuotes;
private SwitchCompat swImagesInline;
private SwitchCompat swRemoteContent; private SwitchCompat swRemoteContent;
private SwitchCompat swSeekbar; private SwitchCompat swSeekbar;
private SwitchCompat swActionbar; private SwitchCompat swActionbar;
@ -77,7 +78,8 @@ public class FragmentOptionsDisplay extends FragmentBase implements SharedPrefer
"avatars", "generated_icons", "identicons", "circular", "name_email", "avatars", "generated_icons", "identicons", "circular", "name_email",
"authentication", "subject_top", "subject_italic", "subject_ellipsize", "authentication", "subject_top", "subject_italic", "subject_ellipsize",
"flags", "preview", "preview_italic", "addresses", "attachments_alt", "flags", "preview", "preview_italic", "addresses", "attachments_alt",
"contrast", "monospaced", "inline_images", "collapse_quotes", "autocontent", "seekbar", "actionbar", "contrast", "monospaced", "text_color",
"inline_images", "collapse_quotes", "autocontent", "seekbar", "actionbar",
}; };
@Override @Override
@ -112,8 +114,9 @@ public class FragmentOptionsDisplay extends FragmentBase implements SharedPrefer
swAttachmentsAlt = view.findViewById(R.id.swAttachmentsAlt); swAttachmentsAlt = view.findViewById(R.id.swAttachmentsAlt);
swContrast = view.findViewById(R.id.swContrast); swContrast = view.findViewById(R.id.swContrast);
swMonospaced = view.findViewById(R.id.swMonospaced); swMonospaced = view.findViewById(R.id.swMonospaced);
swImagesInline = view.findViewById(R.id.swImagesInline); swTextColor = view.findViewById(R.id.swTextColor);
swCollapseQuotes = view.findViewById(R.id.swCollapseQuotes); swCollapseQuotes = view.findViewById(R.id.swCollapseQuotes);
swImagesInline = view.findViewById(R.id.swImagesInline);
swRemoteContent = view.findViewById(R.id.swRemoteContent); swRemoteContent = view.findViewById(R.id.swRemoteContent);
swSeekbar = view.findViewById(R.id.swSeekbar); swSeekbar = view.findViewById(R.id.swSeekbar);
swActionbar = view.findViewById(R.id.swActionbar); swActionbar = view.findViewById(R.id.swActionbar);
@ -297,10 +300,10 @@ public class FragmentOptionsDisplay extends FragmentBase implements SharedPrefer
} }
}); });
swImagesInline.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { swTextColor.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override @Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
prefs.edit().putBoolean("inline_images", checked).apply(); prefs.edit().putBoolean("text_color", checked).apply();
} }
}); });
@ -311,6 +314,13 @@ public class FragmentOptionsDisplay extends FragmentBase implements SharedPrefer
} }
}); });
swImagesInline.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
prefs.edit().putBoolean("inline_images", checked).apply();
}
});
swRemoteContent.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { swRemoteContent.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override @Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
@ -416,8 +426,9 @@ public class FragmentOptionsDisplay extends FragmentBase implements SharedPrefer
swAttachmentsAlt.setChecked(prefs.getBoolean("attachments_alt", false)); swAttachmentsAlt.setChecked(prefs.getBoolean("attachments_alt", false));
swContrast.setChecked(prefs.getBoolean("contrast", false)); swContrast.setChecked(prefs.getBoolean("contrast", false));
swMonospaced.setChecked(prefs.getBoolean("monospaced", false)); swMonospaced.setChecked(prefs.getBoolean("monospaced", false));
swImagesInline.setChecked(prefs.getBoolean("inline_images", false)); swTextColor.setChecked(prefs.getBoolean("text_color", true));
swCollapseQuotes.setChecked(prefs.getBoolean("collapse_quotes", false)); swCollapseQuotes.setChecked(prefs.getBoolean("collapse_quotes", false));
swImagesInline.setChecked(prefs.getBoolean("inline_images", false));
swRemoteContent.setChecked(prefs.getBoolean("autocontent", false)); swRemoteContent.setChecked(prefs.getBoolean("autocontent", false));
swSeekbar.setChecked(prefs.getBoolean("seekbar", false)); swSeekbar.setChecked(prefs.getBoolean("seekbar", false));
swActionbar.setChecked(prefs.getBoolean("actionbar", true)); swActionbar.setChecked(prefs.getBoolean("actionbar", true));

@ -93,7 +93,7 @@ public class HtmlHelper {
private static final ExecutorService executor = private static final ExecutorService executor =
Executors.newSingleThreadExecutor(Helper.backgroundThreadFactory); Executors.newSingleThreadExecutor(Helper.backgroundThreadFactory);
static String sanitize(Context context, String html, boolean show_images) { static String sanitize(Context context, String html, boolean text_color, boolean show_images) {
Document parsed = Jsoup.parse(html); Document parsed = Jsoup.parse(html);
// <html xmlns:v="urn:schemas-microsoft-com:vml" // <html xmlns:v="urn:schemas-microsoft-com:vml"
@ -133,13 +133,15 @@ public class HtmlHelper {
Whitelist whitelist = Whitelist.relaxed() Whitelist whitelist = Whitelist.relaxed()
.addTags("hr", "abbr", "big") .addTags("hr", "abbr", "big")
.addAttributes("span", "style")
.removeTags("col", "colgroup", "thead", "tbody") .removeTags("col", "colgroup", "thead", "tbody")
.removeAttributes("table", "width") .removeAttributes("table", "width")
.removeAttributes("td", "colspan", "rowspan", "width") .removeAttributes("td", "colspan", "rowspan", "width")
.removeAttributes("th", "colspan", "rowspan", "width") .removeAttributes("th", "colspan", "rowspan", "width")
.addProtocols("img", "src", "cid") .addProtocols("img", "src", "cid")
.addProtocols("img", "src", "data"); .addProtocols("img", "src", "data");
if (text_color)
whitelist.addAttributes("span", "style");
final Document document = new Cleaner(whitelist).clean(parsed); final Document document = new Cleaner(whitelist).clean(parsed);
// Sanitize span styles // Sanitize span styles

@ -347,39 +347,51 @@
app:switchPadding="12dp" /> app:switchPadding="12dp" />
<androidx.appcompat.widget.SwitchCompat <androidx.appcompat.widget.SwitchCompat
android:id="@+id/swImagesInline" android:id="@+id/swTextColor"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="12dp" android:layout_marginTop="12dp"
android:text="@string/title_advanced_images_inline" android:enabled="true"
android:text="@string/title_advanced_text_color"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/swMonospaced" app:layout_constraintTop_toBottomOf="@id/swMonospaced"
app:switchPadding="12dp" /> app:switchPadding="12dp" />
<TextView <androidx.appcompat.widget.SwitchCompat
android:id="@+id/tvImagesInlineHint" android:id="@+id/swCollapseQuotes"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginEnd="48dp" android:layout_marginTop="12dp"
android:text="@string/title_advanced_inline_hint" android:text="@string/title_advanced_collapse_quotes"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textStyle="italic"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/swImagesInline" /> app:layout_constraintTop_toBottomOf="@id/swTextColor"
app:switchPadding="12dp" />
<androidx.appcompat.widget.SwitchCompat <androidx.appcompat.widget.SwitchCompat
android:id="@+id/swCollapseQuotes" android:id="@+id/swImagesInline"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="12dp" android:layout_marginTop="12dp"
android:text="@string/title_advanced_collapse_quotes" android:text="@string/title_advanced_images_inline"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvImagesInlineHint" app:layout_constraintTop_toBottomOf="@id/swCollapseQuotes"
app:switchPadding="12dp" /> app:switchPadding="12dp" />
<TextView
android:id="@+id/tvImagesInlineHint"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="48dp"
android:text="@string/title_advanced_inline_hint"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textStyle="italic"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/swImagesInline" />
<androidx.appcompat.widget.SwitchCompat <androidx.appcompat.widget.SwitchCompat
android:id="@+id/swRemoteContent" android:id="@+id/swRemoteContent"
android:layout_width="0dp" android:layout_width="0dp"
@ -388,7 +400,7 @@
android:text="@string/title_advanced_remote_content" android:text="@string/title_advanced_remote_content"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/swCollapseQuotes" app:layout_constraintTop_toBottomOf="@id/tvImagesInlineHint"
app:switchPadding="12dp" /> app:switchPadding="12dp" />
<TextView <TextView

@ -256,8 +256,9 @@
<string name="title_advanced_attachments_alt">Show attachments after the message text</string> <string name="title_advanced_attachments_alt">Show attachments after the message text</string>
<string name="title_advanced_contrast">Use high contrast for message text</string> <string name="title_advanced_contrast">Use high contrast for message text</string>
<string name="title_advanced_monospaced">Use monospaced font for message text</string> <string name="title_advanced_monospaced">Use monospaced font for message text</string>
<string name="title_advanced_images_inline">Automatically show inline images</string> <string name="title_advanced_text_color">Show text colors</string>
<string name="title_advanced_collapse_quotes">Collapse quoted text</string> <string name="title_advanced_collapse_quotes">Collapse quoted text</string>
<string name="title_advanced_images_inline">Automatically show inline images</string>
<string name="title_advanced_remote_content">Automatically show remote content when viewing original messages</string> <string name="title_advanced_remote_content">Automatically show remote content when viewing original messages</string>
<string name="title_advanced_seekbar">Show relative conversation position with a dot</string> <string name="title_advanced_seekbar">Show relative conversation position with a dot</string>
<string name="title_advanced_actionbar">Show conversation action bar</string> <string name="title_advanced_actionbar">Show conversation action bar</string>

Loading…
Cancel
Save