From 0a965e4cbc9c498cc5e04cc159966c3963ff7b5a Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Sat, 2 Mar 2019 14:41:01 +0300 Subject: [PATCH] Split code and codeBlock spans and factories --- docs/docs/theme.md | 2 +- docs/docs/v3/core/theme.md | 2 +- .../ru/noties/markwon/core/MarkwonTheme.java | 149 +++++++++++++----- .../core/factory/CodeBlockSpanFactory.java | 4 +- .../markwon/core/factory/CodeSpanFactory.java | 2 +- .../markwon/core/spans/CodeBlockSpan.java | 66 ++++++++ .../noties/markwon/core/spans/CodeSpan.java | 52 +----- .../sample/recycler/RecyclerActivity.java | 34 ---- 8 files changed, 191 insertions(+), 120 deletions(-) create mode 100644 markwon-core/src/main/java/ru/noties/markwon/core/spans/CodeBlockSpan.java diff --git a/docs/docs/theme.md b/docs/docs/theme.md index 4612a63d..4baf954c 100644 --- a/docs/docs/theme.md +++ b/docs/docs/theme.md @@ -116,7 +116,7 @@ The color of background of code block text Leading margin for the block code content - + ### Code typeface diff --git a/docs/docs/v3/core/theme.md b/docs/docs/v3/core/theme.md index 93c31e85..bfb2b71d 100644 --- a/docs/docs/v3/core/theme.md +++ b/docs/docs/v3/core/theme.md @@ -120,7 +120,7 @@ The color of background of code block text Leading margin for the block code content - + ### Code typeface diff --git a/markwon-core/src/main/java/ru/noties/markwon/core/MarkwonTheme.java b/markwon-core/src/main/java/ru/noties/markwon/core/MarkwonTheme.java index fc97875a..43848d75 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/core/MarkwonTheme.java +++ b/markwon-core/src/main/java/ru/noties/markwon/core/MarkwonTheme.java @@ -108,7 +108,7 @@ public class MarkwonTheme { final Dip dip = Dip.create(context); return new Builder() - .codeMultilineMargin(dip.toPx(8)) + .codeBlockMargin(dip.toPx(8)) .blockMargin(dip.toPx(24)) .blockQuoteWidth(dip.toPx(4)) .bulletListItemStrokeWidth(dip.toPx(1)) @@ -165,15 +165,19 @@ public class MarkwonTheme { // by default `width` of a space char... it's fun and games, but span doesn't have access to paint in `getLeadingMargin` // so, we need to set this value explicitly (think of an utility method, that takes TextView/TextPaint and measures space char) - protected final int codeMultilineMargin; + protected final int codeBlockMargin; // by default Typeface.MONOSPACE protected final Typeface codeTypeface; + protected final Typeface codeBlockTypeface; + // by default a bit (how much?!) smaller than normal text // applied ONLY if default typeface was used, otherwise, not applied protected final int codeTextSize; + protected final int codeBlockTextSize; + // by default paint.getStrokeWidth protected final int headingBreakHeight; @@ -207,9 +211,11 @@ public class MarkwonTheme { this.codeBlockTextColor = builder.codeBlockTextColor; this.codeBackgroundColor = builder.codeBackgroundColor; this.codeBlockBackgroundColor = builder.codeBlockBackgroundColor; - this.codeMultilineMargin = builder.codeMultilineMargin; + this.codeBlockMargin = builder.codeBlockMargin; this.codeTypeface = builder.codeTypeface; + this.codeBlockTypeface = builder.codeBlockTypeface; this.codeTextSize = builder.codeTextSize; + this.codeBlockTextSize = builder.codeBlockTextSize; this.headingBreakHeight = builder.headingBreakHeight; this.headingBreakColor = builder.headingBreakColor; this.headingTypeface = builder.headingTypeface; @@ -301,66 +307,117 @@ public class MarkwonTheme { } /** - * Modified in 1.0.5 to accept `multiline` argument + * @since 3.0.0 */ - public void applyCodeTextStyle(@NonNull Paint paint, boolean multiline) { + public void applyCodeTextStyle(@NonNull Paint paint) { - // @since 1.0.5 added handling of multiline code blocks - if (multiline - && codeBlockTextColor != 0) { - paint.setColor(codeBlockTextColor); - } else if (codeTextColor != 0) { + if (codeTextColor != 0) { paint.setColor(codeTextColor); } - // custom typeface was set if (codeTypeface != null) { paint.setTypeface(codeTypeface); - // please note that we won't be calculating textSize - // (like we do when no Typeface is provided), if it's some specific typeface - // we would confuse users about textSize - if (codeTextSize != 0) { + if (codeTextSize > 0) { paint.setTextSize(codeTextSize); } } else { + paint.setTypeface(Typeface.MONOSPACE); - final float textSize; - if (codeTextSize != 0) { - textSize = codeTextSize; + + if (codeTextSize > 0) { + paint.setTextSize(codeTextSize); } else { - textSize = paint.getTextSize() * CODE_DEF_TEXT_SIZE_RATIO; + paint.setTextSize(paint.getTextSize() * CODE_DEF_TEXT_SIZE_RATIO); } - paint.setTextSize(textSize); } } - public int getCodeMultilineMargin() { - return codeMultilineMargin; + /** + * @since 3.0.0 + */ + public void applyCodeBlockTextStyle(@NonNull Paint paint) { + + // apply text color, first check for block specific value, + // then check for code (inline), else do nothing (keep original color of text) + final int textColor = codeBlockTextColor != 0 + ? codeBlockTextColor + : codeTextColor; + + if (textColor != 0) { + paint.setColor(textColor); + } + + final Typeface typeface = codeBlockTypeface != null + ? codeBlockTypeface + : codeTypeface; + + if (typeface != null) { + + paint.setTypeface(typeface); + + // please note that we won't be calculating textSize + // (like we do when no Typeface is provided), if it's some specific typeface + // we would confuse users about textSize + final int textSize = codeBlockTextSize > 0 + ? codeBlockTextSize + : codeTextSize; + + if (textSize > 0) { + paint.setTextSize(textSize); + } + } else { + + // by default use monospace + paint.setTypeface(Typeface.MONOSPACE); + + final int textSize = codeBlockTextSize > 0 + ? codeBlockTextSize + : codeTextSize; + + if (textSize > 0) { + paint.setTextSize(textSize); + } else { + // calculate default value + paint.setTextSize(paint.getTextSize() * CODE_DEF_TEXT_SIZE_RATIO); + } + } + } + + + public int getCodeBlockMargin() { + return codeBlockMargin; } /** - * Modified in 1.0.5 to accept `multiline` argument + * @since 3.0.0 */ - public int getCodeBackgroundColor(@NonNull Paint paint, boolean multiline) { - + public int getCodeBackgroundColor(@NonNull Paint paint) { final int color; - - // @since 1.0.5 added handling of multiline code blocks - if (multiline - && codeBlockBackgroundColor != 0) { - color = codeBlockBackgroundColor; - } else if (codeBackgroundColor != 0) { + if (codeBackgroundColor != 0) { color = codeBackgroundColor; } else { color = ColorUtils.applyAlpha(paint.getColor(), CODE_DEF_BACKGROUND_COLOR_ALPHA); } - return color; } + /** + * @since 3.0.0 + */ + public int getCodeBlockBackgroundColor(@NonNull Paint paint) { + + final int color = codeBlockBackgroundColor != 0 + ? codeBlockBackgroundColor + : codeBackgroundColor; + + return color != 0 + ? color + : ColorUtils.applyAlpha(paint.getColor(), CODE_DEF_BACKGROUND_COLOR_ALPHA); + } + public void applyHeadingTextStyle(@NonNull Paint paint, @IntRange(from = 1, to = 6) int level) { if (headingTypeface == null) { paint.setFakeBoldText(true); @@ -426,9 +483,11 @@ public class MarkwonTheme { private int codeBlockTextColor; // @since 1.0.5 private int codeBackgroundColor; private int codeBlockBackgroundColor; // @since 1.0.5 - private int codeMultilineMargin; + private int codeBlockMargin; private Typeface codeTypeface; + private Typeface codeBlockTypeface; // @since 3.0.0 private int codeTextSize; + private int codeBlockTextSize; // @since 3.0.0 private int headingBreakHeight = -1; private int headingBreakColor; private Typeface headingTypeface; @@ -451,7 +510,7 @@ public class MarkwonTheme { this.codeBlockTextColor = theme.codeBlockTextColor; this.codeBackgroundColor = theme.codeBackgroundColor; this.codeBlockBackgroundColor = theme.codeBlockBackgroundColor; - this.codeMultilineMargin = theme.codeMultilineMargin; + this.codeBlockMargin = theme.codeBlockMargin; this.codeTypeface = theme.codeTypeface; this.codeTextSize = theme.codeTextSize; this.headingBreakHeight = theme.headingBreakHeight; @@ -537,8 +596,8 @@ public class MarkwonTheme { } @NonNull - public Builder codeMultilineMargin(@Px int codeMultilineMargin) { - this.codeMultilineMargin = codeMultilineMargin; + public Builder codeBlockMargin(@Px int codeBlockMargin) { + this.codeBlockMargin = codeBlockMargin; return this; } @@ -548,12 +607,30 @@ public class MarkwonTheme { return this; } + /** + * @since 3.0.0 + */ + @NonNull + public Builder codeBlockTypeface(@NonNull Typeface typeface) { + this.codeBlockTypeface = typeface; + return this; + } + @NonNull public Builder codeTextSize(@Px int codeTextSize) { this.codeTextSize = codeTextSize; return this; } + /** + * @since 3.0.0 + */ + @NonNull + public Builder codeBlockTextSize(@Px int codeTextSize) { + this.codeBlockTextSize = codeTextSize; + return this; + } + @NonNull public Builder headingBreakHeight(@Px int headingBreakHeight) { this.headingBreakHeight = headingBreakHeight; diff --git a/markwon-core/src/main/java/ru/noties/markwon/core/factory/CodeBlockSpanFactory.java b/markwon-core/src/main/java/ru/noties/markwon/core/factory/CodeBlockSpanFactory.java index 4fd07685..2bf9383e 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/core/factory/CodeBlockSpanFactory.java +++ b/markwon-core/src/main/java/ru/noties/markwon/core/factory/CodeBlockSpanFactory.java @@ -6,12 +6,12 @@ import android.support.annotation.Nullable; import ru.noties.markwon.MarkwonConfiguration; import ru.noties.markwon.RenderProps; import ru.noties.markwon.SpanFactory; -import ru.noties.markwon.core.spans.CodeSpan; +import ru.noties.markwon.core.spans.CodeBlockSpan; public class CodeBlockSpanFactory implements SpanFactory { @Nullable @Override public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) { - return new CodeSpan(configuration.theme(), true); + return new CodeBlockSpan(configuration.theme()); } } diff --git a/markwon-core/src/main/java/ru/noties/markwon/core/factory/CodeSpanFactory.java b/markwon-core/src/main/java/ru/noties/markwon/core/factory/CodeSpanFactory.java index 7726bc02..944556fb 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/core/factory/CodeSpanFactory.java +++ b/markwon-core/src/main/java/ru/noties/markwon/core/factory/CodeSpanFactory.java @@ -12,6 +12,6 @@ public class CodeSpanFactory implements SpanFactory { @Nullable @Override public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) { - return new CodeSpan(configuration.theme(), false); + return new CodeSpan(configuration.theme()); } } diff --git a/markwon-core/src/main/java/ru/noties/markwon/core/spans/CodeBlockSpan.java b/markwon-core/src/main/java/ru/noties/markwon/core/spans/CodeBlockSpan.java new file mode 100644 index 00000000..00109766 --- /dev/null +++ b/markwon-core/src/main/java/ru/noties/markwon/core/spans/CodeBlockSpan.java @@ -0,0 +1,66 @@ +package ru.noties.markwon.core.spans; + +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.support.annotation.NonNull; +import android.text.Layout; +import android.text.TextPaint; +import android.text.style.LeadingMarginSpan; +import android.text.style.MetricAffectingSpan; + +import ru.noties.markwon.core.MarkwonTheme; + +/** + * @since 3.0.0 split inline and block spans + */ +public class CodeBlockSpan extends MetricAffectingSpan implements LeadingMarginSpan { + + private final MarkwonTheme theme; + private final Rect rect = ObjectsPool.rect(); + private final Paint paint = ObjectsPool.paint(); + + public CodeBlockSpan(@NonNull MarkwonTheme theme) { + this.theme = theme; + } + + @Override + public void updateMeasureState(TextPaint p) { + apply(p); + } + + @Override + public void updateDrawState(TextPaint ds) { + apply(ds); + } + + private void apply(TextPaint p) { + theme.applyCodeBlockTextStyle(p); + } + + @Override + public int getLeadingMargin(boolean first) { + return theme.getCodeBlockMargin(); + } + + @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) { + + paint.setStyle(Paint.Style.FILL); + paint.setColor(theme.getCodeBlockBackgroundColor(p)); + + final int left; + final int right; + if (dir > 0) { + left = x; + right = c.getWidth(); + } else { + left = x - c.getWidth(); + right = x; + } + + rect.set(left, top, right, bottom); + + c.drawRect(rect, paint); + } +} diff --git a/markwon-core/src/main/java/ru/noties/markwon/core/spans/CodeSpan.java b/markwon-core/src/main/java/ru/noties/markwon/core/spans/CodeSpan.java index dc233538..856d5807 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/core/spans/CodeSpan.java +++ b/markwon-core/src/main/java/ru/noties/markwon/core/spans/CodeSpan.java @@ -1,27 +1,20 @@ package ru.noties.markwon.core.spans; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.Rect; import android.support.annotation.NonNull; -import android.text.Layout; import android.text.TextPaint; -import android.text.style.LeadingMarginSpan; import android.text.style.MetricAffectingSpan; import ru.noties.markwon.core.MarkwonTheme; -public class CodeSpan extends MetricAffectingSpan implements LeadingMarginSpan { +/** + * @since 3.0.0 split inline and block spans + */ +public class CodeSpan extends MetricAffectingSpan { private final MarkwonTheme theme; - private final Rect rect = ObjectsPool.rect(); - private final Paint paint = ObjectsPool.paint(); - private final boolean multiline; - - public CodeSpan(@NonNull MarkwonTheme theme, boolean multiline) { + public CodeSpan(@NonNull MarkwonTheme theme) { this.theme = theme; - this.multiline = multiline; } @Override @@ -32,41 +25,10 @@ public class CodeSpan extends MetricAffectingSpan implements LeadingMarginSpan { @Override public void updateDrawState(TextPaint ds) { apply(ds); - if (!multiline) { - ds.bgColor = theme.getCodeBackgroundColor(ds, false); - } + ds.bgColor = theme.getCodeBackgroundColor(ds); } private void apply(TextPaint p) { - theme.applyCodeTextStyle(p, multiline); - } - - @Override - public int getLeadingMargin(boolean first) { - return multiline ? theme.getCodeMultilineMargin() : 0; - } - - @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 (multiline) { - - paint.setStyle(Paint.Style.FILL); - paint.setColor(theme.getCodeBackgroundColor(p, true)); - - final int left; - final int right; - if (dir > 0) { - left = x; - right = c.getWidth(); - } else { - left = x - c.getWidth(); - right = x; - } - - rect.set(left, top, right, bottom); - - c.drawRect(rect, paint); - } + theme.applyCodeTextStyle(p); } } diff --git a/sample/src/main/java/ru/noties/markwon/sample/recycler/RecyclerActivity.java b/sample/src/main/java/ru/noties/markwon/sample/recycler/RecyclerActivity.java index d366a64e..c230aa6c 100644 --- a/sample/src/main/java/ru/noties/markwon/sample/recycler/RecyclerActivity.java +++ b/sample/src/main/java/ru/noties/markwon/sample/recycler/RecyclerActivity.java @@ -13,8 +13,6 @@ import android.text.TextUtils; import org.commonmark.ext.gfm.tables.TableBlock; import org.commonmark.ext.gfm.tables.TablesExtension; import org.commonmark.node.FencedCodeBlock; -import org.commonmark.node.Heading; -import org.commonmark.node.SoftLineBreak; import org.commonmark.parser.Parser; import java.io.BufferedReader; @@ -29,9 +27,7 @@ import ru.noties.markwon.AbstractMarkwonPlugin; import ru.noties.markwon.Markwon; import ru.noties.markwon.MarkwonConfiguration; import ru.noties.markwon.MarkwonVisitor; -import ru.noties.markwon.SpanFactory; import ru.noties.markwon.core.CorePlugin; -import ru.noties.markwon.core.CoreProps; import ru.noties.markwon.html.HtmlPlugin; import ru.noties.markwon.image.ImagesPlugin; import ru.noties.markwon.image.svg.SvgPlugin; @@ -52,36 +48,6 @@ public class RecyclerActivity extends Activity { super.onCreate(savedInstanceState); setContentView(R.layout.activity_recycler); - { -final Markwon markwon = Markwon.builder(contex) - .usePlugin(new AbstractMarkwonPlugin() { -@Override -public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) { - builder.on(Heading.class, new MarkwonVisitor.NodeVisitor() { - @Override - public void visit(@NonNull MarkwonVisitor visitor, @NonNull Heading heading) { - - // or just `visitor.length()` - final int start = visitor.builder().length(); - - visitor.visitChildren(heading); - - // or just `visitor.setSpansForNodeOptional(heading, start)` - final SpanFactory factory = visitor.configuration().spansFactory().get(heading.getClass()); - if (factory != null) { - visitor.setSpans(start, factory.getSpans(visitor.configuration(), visitor.renderProps())); - } - - if (visitor.hasNext(heading)) { - visitor.ensureNewLine(); - visitor.forceNewLine(); - } - } - }); -} - }); - } - // create MarkwonAdapter and register two blocks that will be rendered differently // * fenced code block (can also specify the same Entry for indended code block) // * table block