diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5c0f5148..31fc43d1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,12 +1,16 @@
# Changelog
-# 4.3.1-SNAPSHOT
+# $nap;
* Fix DexGuard optimization issue ([#216])
Thanks [@francescocervone]
* module `images`: `GifSupport` and `SvgSupport` use `Class.forName` instead access to full qualified class name
+* `ext-table`: fix links in tables ([#224])
+* `ext-table`: proper borders (equal for all sides)
[#216]: https://github.com/noties/Markwon/pull/216
+[#224]: https://github.com/noties/Markwon/issues/224
[@francescocervone]: https://github.com/francescocervone
+
# 4.3.0
* add `MarkwonInlineParserPlugin` in `inline-parser` module
* `JLatexMathPlugin` now supports inline LaTeX structures via `MarkwonInlineParserPlugin`
diff --git a/app/src/debug/java/io/noties/markwon/debug/ColorBlendView.java b/app/src/debug/java/io/noties/markwon/debug/ColorBlendView.java
new file mode 100644
index 00000000..baf5e92b
--- /dev/null
+++ b/app/src/debug/java/io/noties/markwon/debug/ColorBlendView.java
@@ -0,0 +1,59 @@
+package io.noties.markwon.debug;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.view.View;
+
+import androidx.annotation.Nullable;
+
+import io.noties.markwon.app.R;
+import io.noties.markwon.utils.ColorUtils;
+
+public class ColorBlendView extends View {
+
+ private final Rect rect = new Rect();
+ private final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
+
+ private int background;
+ private int foreground;
+
+ public ColorBlendView(Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+
+ if (attrs != null) {
+ final TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.ColorBlendView);
+ try {
+ background = array.getColor(R.styleable.ColorBlendView_cbv_background, 0);
+ foreground = array.getColor(R.styleable.ColorBlendView_cbv_foreground, 0);
+ } finally {
+ array.recycle();
+ }
+ }
+
+ paint.setStyle(Paint.Style.FILL);
+
+ setWillNotDraw(false);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+
+ final int side = getWidth() / 11;
+
+ rect.set(0, 0, side, getHeight());
+
+ canvas.translate(getPaddingLeft(), 0F);
+
+ for (int i = 0; i < 11; i++) {
+ final float alpha = i / 10F;
+ paint.setColor(ColorUtils.blend(foreground, background, alpha));
+ canvas.drawRect(rect, paint);
+ canvas.translate(side, 0F);
+ }
+ }
+}
diff --git a/app/src/debug/res/layout/debug_color_blend.xml b/app/src/debug/res/layout/debug_color_blend.xml
new file mode 100644
index 00000000..cacc73fa
--- /dev/null
+++ b/app/src/debug/res/layout/debug_color_blend.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/debug/res/values/attrs.xml b/app/src/debug/res/values/attrs.xml
index 161f7806..0636e107 100644
--- a/app/src/debug/res/values/attrs.xml
+++ b/app/src/debug/res/values/attrs.xml
@@ -8,4 +8,9 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/markwon-core/src/main/java/io/noties/markwon/utils/ColorUtils.java b/markwon-core/src/main/java/io/noties/markwon/utils/ColorUtils.java
index d2a8bc6e..d5d9703d 100644
--- a/markwon-core/src/main/java/io/noties/markwon/utils/ColorUtils.java
+++ b/markwon-core/src/main/java/io/noties/markwon/utils/ColorUtils.java
@@ -1,11 +1,33 @@
package io.noties.markwon.utils;
+import android.graphics.Color;
+
+import androidx.annotation.ColorInt;
+import androidx.annotation.FloatRange;
+import androidx.annotation.IntRange;
+
public abstract class ColorUtils {
- public static int applyAlpha(int color, int alpha) {
+ @ColorInt
+ public static int applyAlpha(
+ @ColorInt int color,
+ @IntRange(from = 0, to = 255) int alpha) {
return (color & 0x00FFFFFF) | (alpha << 24);
}
+ // blend two colors w/ specified ratio, resulting color won't have alpha channel
+ @ColorInt
+ public static int blend(
+ @ColorInt int foreground,
+ @ColorInt int background,
+ @FloatRange(from = 0.0F, to = 1.0F) float ratio) {
+ return Color.rgb(
+ (int) (((1F - ratio) * Color.red(foreground)) + (ratio * Color.red(background))),
+ (int) (((1F - ratio) * Color.green(foreground)) + (ratio * Color.green(background))),
+ (int) (((1F - ratio) * Color.blue(foreground)) + (ratio * Color.blue(background)))
+ );
+ }
+
private ColorUtils() {
}
}
diff --git a/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TablePlugin.java b/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TablePlugin.java
index 93dccd83..8e624e01 100644
--- a/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TablePlugin.java
+++ b/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TablePlugin.java
@@ -123,8 +123,13 @@ public class TablePlugin extends AbstractMarkwonPlugin {
visitor.blockStart(tableBlock);
+ final int length = visitor.length();
+
visitor.visitChildren(tableBlock);
+ // @since $nap; apply table span for the full table
+ visitor.setSpans(length, new TableSpan());
+
visitor.blockEnd(tableBlock);
}
})
diff --git a/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TableRowSpan.java b/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TableRowSpan.java
index a90818fb..f6653cf8 100644
--- a/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TableRowSpan.java
+++ b/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TableRowSpan.java
@@ -5,6 +5,7 @@ import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.text.Layout;
+import android.text.Spanned;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.text.style.ReplacementSpan;
@@ -19,6 +20,8 @@ import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
+import io.noties.markwon.utils.LeadingMarginUtils;
+
public class TableRowSpan extends ReplacementSpan {
public static final int ALIGN_LEFT = 0;
@@ -139,16 +142,16 @@ public class TableRowSpan extends ReplacementSpan {
int top,
int y,
int bottom,
- @NonNull Paint paint) {
+ @NonNull Paint p) {
if (recreateLayouts(canvas.getWidth())) {
width = canvas.getWidth();
// @since $nap; it's important to cast to TextPaint in order to display links, etc
- if (paint instanceof TextPaint) {
+ if (p instanceof TextPaint) {
// there must be a reason why this method receives Paint instead of TextPaint...
- textPaint.set((TextPaint) paint);
+ textPaint.set((TextPaint) p);
} else {
- textPaint.set(paint);
+ textPaint.set(p);
}
makeNewLayouts();
}
@@ -161,28 +164,25 @@ public class TableRowSpan extends ReplacementSpan {
final int w = width / size;
- // feels like magic...
- final int heightDiff = (bottom - top - height) / 4;
-
// @since 1.1.1
// draw backgrounds
{
if (header) {
- theme.applyTableHeaderRowStyle(this.paint);
+ theme.applyTableHeaderRowStyle(paint);
} else if (odd) {
- theme.applyTableOddRowStyle(this.paint);
+ theme.applyTableOddRowStyle(paint);
} else {
// even
- theme.applyTableEvenRowStyle(this.paint);
+ theme.applyTableEvenRowStyle(paint);
}
// if present (0 is transparent)
- if (this.paint.getColor() != 0) {
+ if (paint.getColor() != 0) {
final int save = canvas.save();
try {
rect.set(0, 0, width, bottom - top);
- canvas.translate(x, top - heightDiff);
- canvas.drawRect(rect, this.paint);
+ canvas.translate(x, top);
+ canvas.drawRect(rect, paint);
} finally {
canvas.restoreToCount(save);
}
@@ -192,25 +192,73 @@ public class TableRowSpan extends ReplacementSpan {
// @since 1.1.1 reset after applying background color
// as background changes color attribute and if not specific tableBorderColor
// is specified then after this row all borders will have color of this row (plus alpha)
- this.paint.set(paint);
- theme.applyTableBorderStyle(this.paint);
+ paint.set(p);
+ theme.applyTableBorderStyle(paint);
final int borderWidth = theme.tableBorderWidth(paint);
final boolean drawBorder = borderWidth > 0;
+
+ // why divided by 4 gives a more or less good result is still not clear (shouldn't it be 2?)
+ final int heightDiff = (bottom - top - height) / 4;
+
+ // required for borderTop calculation
+ final boolean isFirstTableRow;
+
+ // @since $nap;
if (drawBorder) {
- rect.set(0, 0, w, bottom - top);
+ boolean first = false;
+ // only if first draw the line
+ {
+ final Spanned spanned = (Spanned) text;
+ final TableSpan[] spans = spanned.getSpans(start, end, TableSpan.class);
+ if (spans != null && spans.length > 0) {
+ final TableSpan span = spans[0];
+ if (LeadingMarginUtils.selfStart(start, text, span)) {
+ first = true;
+ rect.set((int) x, top, width, top + borderWidth);
+ canvas.drawRect(rect, paint);
+ }
+ }
+ }
+
+ // draw the line at the bottom
+ rect.set((int) x, bottom - borderWidth, width, bottom);
+ canvas.drawRect(rect, paint);
+
+ isFirstTableRow = first;
+ } else {
+ isFirstTableRow = false;
}
+ final int borderWidthHalf = borderWidth / 2;
+
+ // to NOT overlap borders inset top and bottom
+ final int borderTop = isFirstTableRow ? borderWidth : 0;
+ final int borderBottom = bottom - top - borderWidth;
+
StaticLayout layout;
for (int i = 0; i < size; i++) {
layout = layouts.get(i);
final int save = canvas.save();
try {
- canvas.translate(x + (i * w), top - heightDiff);
+ canvas.translate(x + (i * w), top);
+ // @since $nap;
if (drawBorder) {
- canvas.drawRect(rect, this.paint);
+ // first vertical border will have full width (it cannot exceed canvas)
+ if (i == 0) {
+ rect.set(0, borderTop, borderWidth, borderBottom);
+ } else {
+ rect.set(-borderWidthHalf, borderTop, borderWidthHalf, borderBottom);
+ }
+
+ canvas.drawRect(rect, paint);
+
+ if (i == (size - 1)) {
+ rect.set(w - borderWidth, borderTop, w, borderBottom);
+ canvas.drawRect(rect, paint);
+ }
}
canvas.translate(padding, padding + heightDiff);
diff --git a/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TableSpan.java b/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TableSpan.java
new file mode 100644
index 00000000..bba40d76
--- /dev/null
+++ b/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TableSpan.java
@@ -0,0 +1,7 @@
+package io.noties.markwon.ext.tables;
+
+/**
+ * @since $nap;
+ */
+public class TableSpan {
+}
diff --git a/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TableTheme.java b/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TableTheme.java
index f4a1c5cc..48655220 100644
--- a/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TableTheme.java
+++ b/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TableTheme.java
@@ -10,6 +10,7 @@ import androidx.annotation.Px;
import io.noties.markwon.utils.ColorUtils;
import io.noties.markwon.utils.Dip;
+@SuppressWarnings("WeakerAccess")
public class TableTheme {
@NonNull
@@ -101,7 +102,8 @@ public class TableTheme {
}
paint.setColor(color);
- paint.setStyle(Paint.Style.STROKE);
+ // @since $nap; before it was STROKE... change to FILL as we draw border differently
+ paint.setStyle(Paint.Style.FILL);
}
public void applyTableOddRowStyle(@NonNull Paint paint) {
diff --git a/sample/src/main/java/io/noties/markwon/sample/table/TableActivity.java b/sample/src/main/java/io/noties/markwon/sample/table/TableActivity.java
index a47a13e2..d7153ec6 100644
--- a/sample/src/main/java/io/noties/markwon/sample/table/TableActivity.java
+++ b/sample/src/main/java/io/noties/markwon/sample/table/TableActivity.java
@@ -1,17 +1,22 @@
package io.noties.markwon.sample.table;
+import android.graphics.Color;
import android.os.Bundle;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import io.noties.debug.Debug;
import io.noties.markwon.Markwon;
import io.noties.markwon.ext.tables.TablePlugin;
+import io.noties.markwon.ext.tables.TableTheme;
import io.noties.markwon.linkify.LinkifyPlugin;
import io.noties.markwon.sample.ActivityWithMenuOptions;
import io.noties.markwon.sample.MenuOptions;
import io.noties.markwon.sample.R;
+import io.noties.markwon.utils.ColorUtils;
+import io.noties.markwon.utils.Dip;
public class TableActivity extends ActivityWithMenuOptions {
@@ -19,6 +24,7 @@ public class TableActivity extends ActivityWithMenuOptions {
@Override
public MenuOptions menuOptions() {
return MenuOptions.create()
+ .add("customize", this::customize)
.add("tableAndLinkify", this::tableAndLinkify);
}
@@ -33,6 +39,32 @@ public class TableActivity extends ActivityWithMenuOptions {
tableAndLinkify();
}
+ private void customize() {
+ final String md = "" +
+ "| HEADER | HEADER | HEADER |\n" +
+ "|:----:|:----:|:----:|\n" +
+ "| 测试 | 测试 | 测试 |\n" +
+ "| 测试 | 测试 | 测测测12345试测试测试 |\n" +
+ "| 测试 | 测试 | 123445 |\n" +
+ "| 测试 | 测试 | (650) 555-1212 |\n" +
+ "| 测试 | 测试 | [link](#) |\n";
+
+ final Markwon markwon = Markwon.builder(this)
+ .usePlugin(TablePlugin.create(builder -> {
+ final Dip dip = Dip.create(this);
+ builder
+ .tableBorderWidth(dip.toPx(2))
+ .tableBorderColor(Color.YELLOW)
+ .tableCellPadding(dip.toPx(4))
+ .tableHeaderRowBackgroundColor(ColorUtils.applyAlpha(Color.RED, 80))
+ .tableEvenRowBackgroundColor(ColorUtils.applyAlpha(Color.GREEN, 80))
+ .tableOddRowBackgroundColor(ColorUtils.applyAlpha(Color.BLUE, 80));
+ }))
+ .build();
+
+ markwon.setMarkdown(textView, md);
+ }
+
private void tableAndLinkify() {
final String md = "" +
"| HEADER | HEADER | HEADER |\n" +
@@ -45,7 +77,7 @@ public class TableActivity extends ActivityWithMenuOptions {
"\n" +
"测试\n" +
"\n" +
- "[https://www.baidu.com](https://www.baidu.com)";
+ "[link link](https://link.link)";
final Markwon markwon = Markwon.builder(this)
.usePlugin(LinkifyPlugin.create())