Switched to QuoteSpan

There is special processing for QuoteSpans in Android that doesn't work on extended QuoteSpans
pull/178/head
M66B 5 years ago
parent f03717a25c
commit c1eacc2c80

@ -1913,7 +1913,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
} }
// Draw images // Draw images
Spanned spanned = HtmlHelper.fromDocument(context, document, new Html.ImageGetter() { SpannableStringBuilder ssb = HtmlHelper.fromDocument(context, document, new Html.ImageGetter() {
@Override @Override
public Drawable getDrawable(String source) { public Drawable getDrawable(String source) {
Drawable drawable = ImageHelper.decodeImage(context, message.id, source, show_images, zoom, tvBody); Drawable drawable = ImageHelper.decodeImage(context, message.id, source, show_images, zoom, tvBody);
@ -1927,34 +1927,29 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
} }
}, null); }, null);
if (show_quotes)
return ssb;
// Replace quote spans // Replace quote spans
final int px = Helper.dp2pixels(context, 24 + (zoom) * 8); final int px = Helper.dp2pixels(context, 24 + (zoom) * 8);
SpannableStringBuilder builder = new SpannableStringBuilder(spanned); QuoteSpan[] quoteSpans = ssb.getSpans(0, ssb.length(), QuoteSpan.class);
QuoteSpan[] quoteSpans = builder.getSpans(0, builder.length(), QuoteSpan.class);
for (QuoteSpan quoteSpan : quoteSpans) { for (QuoteSpan quoteSpan : quoteSpans) {
int s = builder.getSpanStart(quoteSpan); int s = ssb.getSpanStart(quoteSpan);
int e = builder.getSpanEnd(quoteSpan); int e = ssb.getSpanEnd(quoteSpan);
ssb.setSpan(
builder.removeSpan(quoteSpan); new DynamicDrawableSpan() {
@Override
StyledQuoteSpan squote = new StyledQuoteSpan(context, colorPrimary); public Drawable getDrawable() {
builder.setSpan(squote, s, e, Spanned.SPAN_INCLUSIVE_INCLUSIVE); Drawable d = context.getDrawable(R.drawable.baseline_format_quote_24);
d.setTint(colorAccent);
if (!show_quotes) d.setBounds(0, 0, px, px);
builder.setSpan( return d;
new DynamicDrawableSpan() { }
@Override },
public Drawable getDrawable() { s, e, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
Drawable d = context.getDrawable(R.drawable.baseline_format_quote_24);
d.setTint(colorAccent);
d.setBounds(0, 0, px, px);
return d;
}
},
s, e, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
} }
return builder; return ssb;
} }
} }

@ -77,20 +77,27 @@ public class EditTextCompose extends FixedEditText {
return false; return false;
html = "<div>" + HtmlHelper.formatPre(text.toString()) + "</div>"; html = "<div>" + HtmlHelper.formatPre(text.toString()) + "</div>";
} }
Document document = HtmlHelper.sanitizeCompose(context, html, false); Document document = HtmlHelper.sanitizeCompose(context, html, false);
Spanned paste = HtmlHelper.fromDocument(context, document); Spanned paste = HtmlHelper.fromHtml(document.html());
int colorPrimary = Helper.resolveColor(context, R.attr.colorPrimary); int colorPrimary = Helper.resolveColor(context, R.attr.colorPrimary);
int dp3 = Helper.dp2pixels(context, 3);
int dp6 = Helper.dp2pixels(context, 6);
SpannableStringBuilder ssb = new SpannableStringBuilder(paste); SpannableStringBuilder ssb = new SpannableStringBuilder(paste);
QuoteSpan[] spans = ssb.getSpans(0, ssb.length(), QuoteSpan.class); QuoteSpan[] spans = ssb.getSpans(0, ssb.length(), QuoteSpan.class);
for (QuoteSpan span : spans) { for (QuoteSpan quoteSpan : spans) {
ssb.setSpan( QuoteSpan q;
new StyledQuoteSpan(context, colorPrimary), if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P)
ssb.getSpanStart(span), q = new QuoteSpan(colorPrimary);
ssb.getSpanEnd(span), else
q = new QuoteSpan(colorPrimary, dp3, dp6);
ssb.setSpan(q,
ssb.getSpanStart(quoteSpan),
ssb.getSpanEnd(quoteSpan),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
ssb.removeSpan(span); ssb.removeSpan(quoteSpan);
} }
int start = getSelectionStart(); int start = getSelectionStart();

@ -47,6 +47,7 @@ import android.net.Network;
import android.net.NetworkCapabilities; import android.net.NetworkCapabilities;
import android.net.NetworkRequest; import android.net.NetworkRequest;
import android.net.Uri; import android.net.Uri;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.OperationCanceledException; import android.os.OperationCanceledException;
@ -485,8 +486,8 @@ public class FragmentCompose extends FragmentBase {
// break block quotes // break block quotes
boolean broken = false; boolean broken = false;
SpannableStringBuilder ssb = new SpannableStringBuilder(text); SpannableStringBuilder ssb = new SpannableStringBuilder(text);
StyledQuoteSpan[] spans = ssb.getSpans(start + 1, start + 1, StyledQuoteSpan.class); QuoteSpan[] spans = ssb.getSpans(start + 1, start + 1, QuoteSpan.class);
for (StyledQuoteSpan span : spans) { for (QuoteSpan span : spans) {
int s = ssb.getSpanStart(span); int s = ssb.getSpanStart(span);
int e = ssb.getSpanEnd(span); int e = ssb.getSpanEnd(span);
int f = ssb.getSpanFlags(span); int f = ssb.getSpanFlags(span);
@ -497,11 +498,19 @@ public class FragmentCompose extends FragmentBase {
ssb.charAt(start) == '\n' && ssb.charAt(e - 1) == '\n') { ssb.charAt(start) == '\n' && ssb.charAt(e - 1) == '\n') {
broken = true; broken = true;
StyledQuoteSpan q1 = new StyledQuoteSpan(getContext(), span.getColor()); QuoteSpan q1;
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P)
q1 = new QuoteSpan(span.getColor());
else
q1 = new QuoteSpan(span.getColor(), span.getStripeWidth(), span.getGapWidth());
ssb.setSpan(q1, s, start, f); ssb.setSpan(q1, s, start, f);
Log.i("Span " + s + "..." + start); Log.i("Span " + s + "..." + start);
StyledQuoteSpan q2 = new StyledQuoteSpan(getContext(), span.getColor()); QuoteSpan q2;
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P)
q2 = new QuoteSpan(span.getColor());
else
q2 = new QuoteSpan(span.getColor(), span.getStripeWidth(), span.getGapWidth());
ssb.setSpan(q2, start + 1, e, f); ssb.setSpan(q2, start + 1, e, f);
Log.i("Span " + (start + 1) + "..." + e); Log.i("Span " + (start + 1) + "..." + e);
@ -4428,6 +4437,8 @@ public class FragmentCompose extends FragmentBase {
final boolean show_images = args.getBoolean("show_images", false); final boolean show_images = args.getBoolean("show_images", false);
int colorPrimary = Helper.resolveColor(context, R.attr.colorPrimary); int colorPrimary = Helper.resolveColor(context, R.attr.colorPrimary);
int dp3 = Helper.dp2pixels(context, 3);
int dp6 = Helper.dp2pixels(context, 6);
DB db = DB.getInstance(context); DB db = DB.getInstance(context);
EntityMessage draft = db.message().getMessage(id); EntityMessage draft = db.message().getMessage(id);
@ -4449,8 +4460,12 @@ public class FragmentCompose extends FragmentBase {
SpannableStringBuilder bodyBuilder = new SpannableStringBuilder(spannedBody); SpannableStringBuilder bodyBuilder = new SpannableStringBuilder(spannedBody);
QuoteSpan[] bodySpans = bodyBuilder.getSpans(0, bodyBuilder.length(), QuoteSpan.class); QuoteSpan[] bodySpans = bodyBuilder.getSpans(0, bodyBuilder.length(), QuoteSpan.class);
for (QuoteSpan quoteSpan : bodySpans) { for (QuoteSpan quoteSpan : bodySpans) {
bodyBuilder.setSpan( QuoteSpan q;
new StyledQuoteSpan(context, colorPrimary), if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P)
q = new QuoteSpan(colorPrimary);
else
q = new QuoteSpan(colorPrimary, dp3, dp6);
bodyBuilder.setSpan(q,
bodyBuilder.getSpanStart(quoteSpan), bodyBuilder.getSpanStart(quoteSpan),
bodyBuilder.getSpanEnd(quoteSpan), bodyBuilder.getSpanEnd(quoteSpan),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
@ -4463,7 +4478,7 @@ public class FragmentCompose extends FragmentBase {
if (!ref.isEmpty()) { if (!ref.isEmpty()) {
Document dref = JsoupEx.parse(ref.outerHtml()); Document dref = JsoupEx.parse(ref.outerHtml());
Document quote = HtmlHelper.sanitizeView(context, dref, show_images); Document quote = HtmlHelper.sanitizeView(context, dref, show_images);
SpannableStringBuilder ssb = HtmlHelper.fromDocument(context, quote, spannedRef = HtmlHelper.fromDocument(context, quote,
new Html.ImageGetter() { new Html.ImageGetter() {
@Override @Override
public Drawable getDrawable(String source) { public Drawable getDrawable(String source) {
@ -4471,18 +4486,6 @@ public class FragmentCompose extends FragmentBase {
} }
}, },
null); null);
QuoteSpan[] refSpans = ssb.getSpans(0, ssb.length(), QuoteSpan.class);
for (QuoteSpan quoteSpan : refSpans) {
ssb.setSpan(
new StyledQuoteSpan(context, colorPrimary),
ssb.getSpanStart(quoteSpan),
ssb.getSpanEnd(quoteSpan),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
ssb.removeSpan(quoteSpan);
}
spannedRef = ssb;
} }
args.putBoolean("ref_has_images", spannedRef != null && args.putBoolean("ref_has_images", spannedRef != null &&

@ -1716,10 +1716,11 @@ public class HtmlHelper {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean debug = prefs.getBoolean("debug", false); boolean debug = prefs.getBoolean("debug", false);
int colorAccent = Helper.resolveColor(context, R.attr.colorAccent); final int colorPrimary = Helper.resolveColor(context, R.attr.colorPrimary);
int dp3 = Helper.dp2pixels(context, 3); final int colorAccent = Helper.resolveColor(context, R.attr.colorAccent);
int dp6 = Helper.dp2pixels(context, 6); final int dp3 = Helper.dp2pixels(context, 3);
int dp24 = Helper.dp2pixels(context, 24); final int dp6 = Helper.dp2pixels(context, 6);
final int dp24 = Helper.dp2pixels(context, 24);
// https://developer.mozilla.org/en-US/docs/Web/HTML/Block-level_elements // https://developer.mozilla.org/en-US/docs/Web/HTML/Block-level_elements
NodeTraversor.traverse(new NodeVisitor() { NodeTraversor.traverse(new NodeVisitor() {
@ -1897,7 +1898,12 @@ public class HtmlHelper {
case "blockquote": case "blockquote":
if (start > 0 && ssb.charAt(start - 1) != '\n') if (start > 0 && ssb.charAt(start - 1) != '\n')
ssb.insert(start++, "\n"); ssb.insert(start++, "\n");
ssb.setSpan(new QuoteSpan(), start, ssb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P)
ssb.setSpan(new QuoteSpan(colorPrimary), start, ssb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
else
ssb.setSpan(new QuoteSpan(colorPrimary, dp3, dp6), start, ssb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
if (ssb.length() > 1 && ssb.charAt(ssb.length() - 1) != '\n') if (ssb.length() > 1 && ssb.charAt(ssb.length() - 1) != '\n')
ssb.append("\n"); ssb.append("\n");
break; break;

@ -1,62 +0,0 @@
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 <http://www.gnu.org/licenses/>.
Copyright 2018-2020 by Marcel Bokhorst (M66B)
*/
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.text.Layout;
import android.text.style.QuoteSpan;
import androidx.annotation.NonNull;
public class StyledQuoteSpan extends QuoteSpan {
private int stripeWidth;
private int gapWidth;
StyledQuoteSpan(Context context, int color) {
super(color);
stripeWidth = Helper.dp2pixels(context, 3);
gapWidth = Helper.dp2pixels(context, 6);
}
@Override
public int getLeadingMargin(boolean first) {
return stripeWidth + gapWidth;
}
@Override
public void drawLeadingMargin(
@NonNull Canvas c, @NonNull Paint p,
int x, int dir, int top, int baseline, int bottom,
@NonNull CharSequence text, int start, int end, boolean first,
@NonNull Layout layout) {
Paint.Style style = p.getStyle();
int color = p.getColor();
p.setStyle(Paint.Style.FILL);
p.setColor(getColor());
c.drawRect(x, top, x + dir * stripeWidth, bottom, p);
p.setStyle(style);
p.setColor(color);
}
}
Loading…
Cancel
Save