Switched to QuoteSpan

There is special processing for QuoteSpans in Android that doesn't work on extended QuoteSpans
This commit is contained in:
M66B 2020-05-03 14:11:38 +02:00
parent f03717a25c
commit c1eacc2c80
5 changed files with 66 additions and 117 deletions

View File

@ -1913,7 +1913,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
}
// Draw images
Spanned spanned = HtmlHelper.fromDocument(context, document, new Html.ImageGetter() {
SpannableStringBuilder ssb = HtmlHelper.fromDocument(context, document, new Html.ImageGetter() {
@Override
public Drawable getDrawable(String source) {
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);
if (show_quotes)
return ssb;
// Replace quote spans
final int px = Helper.dp2pixels(context, 24 + (zoom) * 8);
SpannableStringBuilder builder = new SpannableStringBuilder(spanned);
QuoteSpan[] quoteSpans = builder.getSpans(0, builder.length(), QuoteSpan.class);
QuoteSpan[] quoteSpans = ssb.getSpans(0, ssb.length(), QuoteSpan.class);
for (QuoteSpan quoteSpan : quoteSpans) {
int s = builder.getSpanStart(quoteSpan);
int e = builder.getSpanEnd(quoteSpan);
builder.removeSpan(quoteSpan);
StyledQuoteSpan squote = new StyledQuoteSpan(context, colorPrimary);
builder.setSpan(squote, s, e, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
if (!show_quotes)
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, px, px);
return d;
}
},
s, e, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
int s = ssb.getSpanStart(quoteSpan);
int e = ssb.getSpanEnd(quoteSpan);
ssb.setSpan(
new DynamicDrawableSpan() {
@Override
public Drawable getDrawable() {
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;
}
}

View File

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

View File

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

View File

@ -1716,10 +1716,11 @@ public class HtmlHelper {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean debug = prefs.getBoolean("debug", false);
int colorAccent = Helper.resolveColor(context, R.attr.colorAccent);
int dp3 = Helper.dp2pixels(context, 3);
int dp6 = Helper.dp2pixels(context, 6);
int dp24 = Helper.dp2pixels(context, 24);
final int colorPrimary = Helper.resolveColor(context, R.attr.colorPrimary);
final int colorAccent = Helper.resolveColor(context, R.attr.colorAccent);
final int dp3 = Helper.dp2pixels(context, 3);
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
NodeTraversor.traverse(new NodeVisitor() {
@ -1897,7 +1898,12 @@ public class HtmlHelper {
case "blockquote":
if (start > 0 && ssb.charAt(start - 1) != '\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')
ssb.append("\n");
break;

View File

@ -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);
}
}