Enable quotes inline

pull/156/head
M66B 6 years ago
parent bb3893e3d3
commit bbfb33bae6

@ -103,7 +103,7 @@ public class ActivityEml extends ActivityBase {
result.parts = HtmlHelper.fromHtml(sb.toString()); result.parts = HtmlHelper.fromHtml(sb.toString());
result.html = parts.getHtml(context); result.html = parts.getHtml(context);
result.body = HtmlHelper.fromHtml(HtmlHelper.sanitize(context, result.html, true)); result.body = HtmlHelper.fromHtml(HtmlHelper.sanitize(context, result.html));
ByteArrayOutputStream bos = new ByteArrayOutputStream(); ByteArrayOutputStream bos = new ByteArrayOutputStream();
mmessage.writeTo(bos); mmessage.writeTo(bos);

@ -51,6 +51,7 @@ import android.text.SpannableStringBuilder;
import android.text.Spanned; import android.text.Spanned;
import android.text.TextUtils; import android.text.TextUtils;
import android.text.method.ArrowKeyMovementMethod; import android.text.method.ArrowKeyMovementMethod;
import android.text.style.DynamicDrawableSpan;
import android.text.style.ImageSpan; import android.text.style.ImageSpan;
import android.text.style.QuoteSpan; import android.text.style.QuoteSpan;
import android.text.style.StyleSpan; import android.text.style.StyleSpan;
@ -244,7 +245,6 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
private BottomNavigationView bnvActions; private BottomNavigationView bnvActions;
private ToggleButton tbHtml; private ToggleButton tbHtml;
private ImageButton ibQuotes;
private ImageButton ibImages; private ImageButton ibImages;
private ImageButton ibFull; private ImageButton ibFull;
private TextView tvBody; private TextView tvBody;
@ -338,7 +338,6 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
bnvActions = itemView.findViewById(R.id.bnvActions); bnvActions = itemView.findViewById(R.id.bnvActions);
tbHtml = itemView.findViewById(R.id.tbHtml); tbHtml = itemView.findViewById(R.id.tbHtml);
ibQuotes = itemView.findViewById(R.id.ibQuotes);
ibImages = itemView.findViewById(R.id.ibImages); ibImages = itemView.findViewById(R.id.ibImages);
ibFull = itemView.findViewById(R.id.ibFull); ibFull = itemView.findViewById(R.id.ibFull);
tvBody = itemView.findViewById(R.id.tvBody); tvBody = itemView.findViewById(R.id.tvBody);
@ -395,7 +394,6 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
btnSaveAttachments.setOnClickListener(this); btnSaveAttachments.setOnClickListener(this);
tbHtml.setOnCheckedChangeListener(this); tbHtml.setOnCheckedChangeListener(this);
ibQuotes.setOnClickListener(this);
ibImages.setOnClickListener(this); ibImages.setOnClickListener(this);
ibFull.setOnClickListener(this); ibFull.setOnClickListener(this);
@ -418,7 +416,6 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
btnDownloadAttachments.setOnClickListener(null); btnDownloadAttachments.setOnClickListener(null);
btnSaveAttachments.setOnClickListener(null); btnSaveAttachments.setOnClickListener(null);
tbHtml.setOnCheckedChangeListener(null); tbHtml.setOnCheckedChangeListener(null);
ibQuotes.setOnClickListener(null);
ibImages.setOnClickListener(null); ibImages.setOnClickListener(null);
ibFull.setOnClickListener(null); ibFull.setOnClickListener(null);
@ -718,7 +715,6 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
tvNoInternetAttachments.setVisibility(View.GONE); tvNoInternetAttachments.setVisibility(View.GONE);
tbHtml.setVisibility(View.GONE); tbHtml.setVisibility(View.GONE);
ibQuotes.setVisibility(View.GONE);
ibImages.setVisibility(View.GONE); ibImages.setVisibility(View.GONE);
ibFull.setVisibility(View.GONE); ibFull.setVisibility(View.GONE);
tvBody.setVisibility(View.GONE); tvBody.setVisibility(View.GONE);
@ -776,7 +772,6 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
tbHtml.setChecked(show_html); tbHtml.setChecked(show_html);
tbHtml.setVisibility(hasWebView ? View.INVISIBLE : View.GONE); tbHtml.setVisibility(hasWebView ? View.INVISIBLE : View.GONE);
ibQuotes.setVisibility(!show_html ? View.INVISIBLE : View.GONE);
ibImages.setVisibility(!show_html ? View.INVISIBLE : View.GONE); ibImages.setVisibility(!show_html ? View.INVISIBLE : View.GONE);
ibFull.setVisibility(show_html ? View.INVISIBLE : View.GONE); ibFull.setVisibility(show_html ? View.INVISIBLE : View.GONE);
@ -965,8 +960,11 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
tvBody.setText(body); tvBody.setText(body);
tvBody.setMovementMethod(null); tvBody.setMovementMethod(null);
boolean show_quotes = properties.getValue("quotes", message.id);
Bundle args = new Bundle(); Bundle args = new Bundle();
args.putSerializable("message", message); args.putSerializable("message", message);
args.putBoolean("show_quotes", show_quotes);
bodyTask.execute(context, owner, args, "message:body"); bodyTask.execute(context, owner, args, "message:body");
} }
} }
@ -1032,8 +1030,11 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
if (show_html) if (show_html)
onShowHtmlConfirmed(message); onShowHtmlConfirmed(message);
else { else {
boolean show_quotes = properties.getValue("quotes", message.id);
Bundle args = new Bundle(); Bundle args = new Bundle();
args.putSerializable("message", message); args.putSerializable("message", message);
args.putBoolean("show_quotes", show_quotes);
bodyTask.execute(context, owner, args, "message:body"); bodyTask.execute(context, owner, args, "message:body");
} }
} }
@ -1069,8 +1070,6 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
onDownloadAttachments(message); onDownloadAttachments(message);
else if (view.getId() == R.id.btnSaveAttachments) else if (view.getId() == R.id.btnSaveAttachments)
onSaveAttachments(message); onSaveAttachments(message);
else if (view.getId() == R.id.ibQuotes)
onShowQuotes(message);
else if (view.getId() == R.id.ibImages) else if (view.getId() == R.id.ibImages)
onShowImages(message); onShowImages(message);
else if (view.getId() == R.id.ibFull) else if (view.getId() == R.id.ibFull)
@ -1418,7 +1417,6 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
boolean show_images = properties.getValue("images", message.id); boolean show_images = properties.getValue("images", message.id);
tbHtml.setVisibility(View.VISIBLE); tbHtml.setVisibility(View.VISIBLE);
ibQuotes.setVisibility(View.GONE);
ibImages.setVisibility(show_images ? View.GONE : View.INVISIBLE); ibImages.setVisibility(show_images ? View.GONE : View.INVISIBLE);
ibFull.setVisibility(View.INVISIBLE); ibFull.setVisibility(View.INVISIBLE);
rvImage.setVisibility(adapterImage.getItemCount() > 0 ? View.INVISIBLE : View.GONE); rvImage.setVisibility(adapterImage.getItemCount() > 0 ? View.INVISIBLE : View.GONE);
@ -1528,7 +1526,6 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
private void onHideHtml(TupleMessageEx message) { private void onHideHtml(TupleMessageEx message) {
properties.setValue("html", message.id, false); properties.setValue("html", message.id, false);
ibQuotes.setVisibility(View.INVISIBLE);
ibImages.setVisibility(View.INVISIBLE); ibImages.setVisibility(View.INVISIBLE);
ibFull.setVisibility(View.GONE); ibFull.setVisibility(View.GONE);
@ -1539,8 +1536,11 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
tvBody.setText(body); tvBody.setText(body);
tvBody.setMovementMethod(null); tvBody.setMovementMethod(null);
boolean show_quotes = properties.getValue("quotes", message.id);
Bundle args = new Bundle(); Bundle args = new Bundle();
args.putSerializable("message", message); args.putSerializable("message", message);
args.putBoolean("show_quotes", show_quotes);
bodyTask.execute(context, owner, args, "message:body"); bodyTask.execute(context, owner, args, "message:body");
} }
@ -1640,15 +1640,6 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
settings.setStandardFontFamily("monospace"); settings.setStandardFontFamily("monospace");
} }
private void onShowQuotes(final TupleMessageEx message) {
properties.setValue("quotes", message.id, true);
ibQuotes.setEnabled(false);
Bundle args = new Bundle();
args.putSerializable("message", message);
bodyTask.execute(context, owner, args, "message:body");
}
private void onShowImages(final TupleMessageEx message) { private void onShowImages(final TupleMessageEx message) {
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
if (prefs.getBoolean("show_images_confirmed", false)) { if (prefs.getBoolean("show_images_confirmed", false)) {
@ -1679,8 +1670,11 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
private void onShowImagesConfirmed(final TupleMessageEx message) { private void onShowImagesConfirmed(final TupleMessageEx message) {
properties.setValue("images", message.id, true); properties.setValue("images", message.id, true);
boolean show_quotes = properties.getValue("quotes", message.id);
Bundle args = new Bundle(); Bundle args = new Bundle();
args.putSerializable("message", message); args.putSerializable("message", message);
args.putBoolean("show_quotes", show_quotes);
boolean show_html = properties.getValue("html", message.id); boolean show_html = properties.getValue("html", message.id);
if (show_html) if (show_html)
@ -1722,9 +1716,10 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
private SimpleTask<SpannableStringBuilder> bodyTask = new SimpleTask<SpannableStringBuilder>() { private SimpleTask<SpannableStringBuilder> bodyTask = new SimpleTask<SpannableStringBuilder>() {
@Override @Override
protected SpannableStringBuilder onExecute(Context context, final Bundle args) { protected SpannableStringBuilder onExecute(final Context context, final Bundle args) {
DB db = DB.getInstance(context); DB db = DB.getInstance(context);
TupleMessageEx message = (TupleMessageEx) args.getSerializable("message"); TupleMessageEx message = (TupleMessageEx) args.getSerializable("message");
boolean show_quotes = args.getBoolean("show_quotes");
String body; String body;
try { try {
@ -1749,6 +1744,23 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
builder.removeSpan(quoteSpan); builder.removeSpan(quoteSpan);
} }
if (!show_quotes) {
StyledQuoteSpan[] squotes = builder.getSpans(0, builder.length(), StyledQuoteSpan.class);
for (StyledQuoteSpan squote : squotes)
builder.setSpan(new DynamicDrawableSpan() {
@Override
public Drawable getDrawable() {
Drawable d = context.getDrawable(R.drawable.baseline_format_quote_24);
d.setTint(colorAccent);
d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
return d;
}
},
builder.getSpanStart(squote),
builder.getSpanEnd(squote),
builder.getSpanFlags(squote));
}
args.putBoolean("has_quotes", builder.getSpans(0, body.length(), StyledQuoteSpan.class).length > 0); args.putBoolean("has_quotes", builder.getSpans(0, body.length(), StyledQuoteSpan.class).length > 0);
args.putBoolean("has_images", builder.getSpans(0, body.length(), ImageSpan.class).length > 0); args.putBoolean("has_images", builder.getSpans(0, body.length(), ImageSpan.class).length > 0);
@ -1774,12 +1786,11 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
boolean show_images = properties.getValue("images", message.id); boolean show_images = properties.getValue("images", message.id);
tbHtml.setVisibility(hasWebView ? View.VISIBLE : View.GONE); tbHtml.setVisibility(hasWebView ? View.VISIBLE : View.GONE);
ibQuotes.setVisibility(has_quotes && !show_quotes ? View.VISIBLE : View.GONE);
ibImages.setVisibility(has_images && !show_images ? View.VISIBLE : View.GONE); ibImages.setVisibility(has_images && !show_images ? View.VISIBLE : View.GONE);
tvBody.setText(body); tvBody.setText(body);
tvBody.setTextIsSelectable(false); tvBody.setTextIsSelectable(false);
tvBody.setTextIsSelectable(true); tvBody.setTextIsSelectable(true);
tvBody.setMovementMethod(new TouchHandler(message.id)); tvBody.setMovementMethod(new TouchHandler(message));
tvBody.setVisibility(View.VISIBLE); tvBody.setVisibility(View.VISIBLE);
pbBody.setVisibility(View.GONE); pbBody.setVisibility(View.GONE);
rvImage.setVisibility(adapterImage.getItemCount() > 0 ? View.VISIBLE : View.GONE); rvImage.setVisibility(adapterImage.getItemCount() > 0 ? View.VISIBLE : View.GONE);
@ -1792,10 +1803,9 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
}; };
private Spanned decodeHtml(final Context context, final EntityMessage message, String body) { private Spanned decodeHtml(final Context context, final EntityMessage message, String body) {
final boolean show_quotes = properties.getValue("quotes", message.id);
final boolean show_images = properties.getValue("images", message.id); final boolean show_images = properties.getValue("images", message.id);
String html = HtmlHelper.sanitize(context, body, show_quotes); String html = HtmlHelper.sanitize(context, body);
if (debug) if (debug)
html += "<pre>" + Html.escapeHtml(html) + "</pre>"; html += "<pre>" + Html.escapeHtml(html) + "</pre>";
@ -1819,10 +1829,10 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
} }
private class TouchHandler extends ArrowKeyMovementMethod { private class TouchHandler extends ArrowKeyMovementMethod {
private long id; private TupleMessageEx message;
TouchHandler(long id) { TouchHandler(TupleMessageEx message) {
this.id = id; this.message = message;
} }
@Override @Override
@ -1853,7 +1863,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
ImageSpan[] image = buffer.getSpans(off, off, ImageSpan.class); ImageSpan[] image = buffer.getSpans(off, off, ImageSpan.class);
if (image.length > 0 && image[0].getSource() != null) { if (image.length > 0 && image[0].getSource() != null) {
boolean show_images = properties.getValue("images", id); boolean show_images = properties.getValue("images", message.id);
if (show_images) { if (show_images) {
onOpenImage(image[0].getDrawable()); onOpenImage(image[0].getDrawable());
return true; return true;
@ -1865,6 +1875,16 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
} }
} }
} }
DynamicDrawableSpan[] ddss = buffer.getSpans(off, off, DynamicDrawableSpan.class);
if (ddss.length > 0) {
properties.setValue("quotes", message.id, true);
Bundle args = new Bundle();
args.putSerializable("message", message);
args.putBoolean("show_quotes", true);
bodyTask.execute(context, owner, args, "message:body");
}
} }
return super.onTouchEvent(widget, buffer, event); return super.onTouchEvent(widget, buffer, event);

@ -2755,7 +2755,7 @@ public class FragmentCompose extends FragmentBase {
Spanned spannedReference = null; Spanned spannedReference = 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), true); String quote = HtmlHelper.sanitize(context, Helper.readText(refFile));
Spanned spannedQuote = HtmlHelper.fromHtml(quote, Spanned spannedQuote = HtmlHelper.fromHtml(quote,
new Html.ImageGetter() { new Html.ImageGetter() {
@Override @Override

@ -110,7 +110,7 @@ public class HtmlHelper {
return document.outerHtml(); return document.outerHtml();
} }
static String sanitize(Context context, String html, boolean showQuotes) { static String sanitize(Context context, String html) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean paranoid = prefs.getBoolean("paranoid", true); boolean paranoid = prefs.getBoolean("paranoid", true);
@ -125,11 +125,6 @@ public class HtmlHelper {
.addProtocols("img", "src", "data"); .addProtocols("img", "src", "data");
final Document document = new Cleaner(whitelist).clean(parsed); final Document document = new Cleaner(whitelist).clean(parsed);
// Quotes
if (!showQuotes)
for (Element quote : document.select("blockquote"))
quote.html("&#8230;");
// Short quotes // Short quotes
for (Element q : document.select("q")) { for (Element q : document.select("q")) {
q.prependText("\""); q.prependText("\"");

@ -507,17 +507,6 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/bnvActions" /> app:layout_constraintTop_toBottomOf="@id/bnvActions" />
<ImageButton
android:id="@+id/ibQuotes"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="3dp"
android:layout_marginEnd="6dp"
android:contentDescription="@string/title_legend_show_quotes"
android:src="@drawable/baseline_format_quote_24"
app:layout_constraintEnd_toStartOf="@+id/ibImages"
app:layout_constraintTop_toBottomOf="@id/bnvActions" />
<ImageButton <ImageButton
android:id="@+id/ibImages" android:id="@+id/ibImages"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -545,7 +534,7 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:barrierDirection="bottom" app:barrierDirection="bottom"
app:constraint_referenced_ids="tbHtml,ibQuotes,ibImages,ibFull" /> app:constraint_referenced_ids="tbHtml,ibImages,ibFull" />
<eu.faircode.email.ContentLoadingProgressBar <eu.faircode.email.ContentLoadingProgressBar
android:id="@+id/pbBody" android:id="@+id/pbBody"

@ -498,17 +498,6 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/bnvActions" /> app:layout_constraintTop_toBottomOf="@id/bnvActions" />
<ImageButton
android:id="@+id/ibQuotes"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="3dp"
android:layout_marginEnd="6dp"
android:contentDescription="@string/title_legend_show_quotes"
android:src="@drawable/baseline_format_quote_24"
app:layout_constraintEnd_toStartOf="@+id/ibImages"
app:layout_constraintTop_toBottomOf="@id/bnvActions" />
<ImageButton <ImageButton
android:id="@+id/ibImages" android:id="@+id/ibImages"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -536,7 +525,7 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:barrierDirection="bottom" app:barrierDirection="bottom"
app:constraint_referenced_ids="tbHtml,ibQuotes,ibImages,ibFull" /> app:constraint_referenced_ids="tbHtml,ibImages,ibFull" />
<eu.faircode.email.ContentLoadingProgressBar <eu.faircode.email.ContentLoadingProgressBar
android:id="@+id/pbBody" android:id="@+id/pbBody"

Loading…
Cancel
Save