diff --git a/README.md b/README.md
index 3e0d5383..1e33a9f4 100644
--- a/README.md
+++ b/README.md
@@ -6,9 +6,6 @@
[](http://search.maven.org/#search|ga|1|g%3A%22ru.noties%22%20AND%20a%3A%markwon-image-loader%22)
[](http://search.maven.org/#search|ga|1|g%3A%22ru.noties%22%20AND%20a%3A%markwon-view%22)
-- [ ] one **one** _one_
-- [X] ~~two~~
-
**Markwon** is a library for Android that renders markdown as system-native Spannables. It gives ability to display markdown in all TextView widgets (**TextView**, **Button**, **Switch**, **CheckBox**, etc), **Notifications**, **Toasts**, etc. **No WebView is required**. Library provides reasonable defaults for display style of markdown but also gives all the means to tweak the appearance if desired. All markdown features are supported (including limited support for inlined HTML code, markdown tables and images).
**This file is displayed by default in the [sample-apk] application. Which is a generic markdown viewer with support to display markdown via `http`, `https` & `file` schemes and 2 themes included: Light & Dark*
@@ -41,6 +38,11 @@ compile 'ru.noties:markwon-view:1.0.0' // optional
* * Underline (``)
* * Strike-through (``, ``, ``)
* other inline html is rendered via (`Html.fromHtml(...)`)
+* Task lists:
+
+- [ ] Not _done_
+ - [X] **Done** with `X`
+ - [x] ~~and~~ **or** small `x`
---
diff --git a/docs/SpannableTheme.md b/docs/SpannableTheme.md
index 4096ce34..b4fd7dee 100644
--- a/docs/SpannableTheme.md
+++ b/docs/SpannableTheme.md
@@ -105,6 +105,16 @@ public Builder tableBorderWidth(@Dimension int tableBorderWidth);
public Builder tableOddRowBackgroundColor(@ColorInt int tableOddRowBackgroundColor);
```
+#### Task lists
+
+Task lists are supported but with some limitations. First of all, task list cannot be nested
+(in a list, quote, etc). By default (if used factory method `builderWithDefaults`) TaskListDrawable
+will be used with `linkColor` as the primary color and `windowBackground` as the checkMarkColor.
+
+```java
+public Builder taskListDrawable(@NonNull Drawable taskListDrawable);
+```
+
### Contents
diff --git a/library-task-list/build.gradle b/library-task-list/build.gradle
deleted file mode 100644
index 094d9248..00000000
--- a/library-task-list/build.gradle
+++ /dev/null
@@ -1,10 +0,0 @@
-apply plugin: 'java'
-
-sourceCompatibility = "1.7"
-targetCompatibility = "1.7"
-
-dependencies {
- compile SUPPORT_ANNOTATIONS
- compile COMMON_MARK
- compile 'ru.noties:debug:3.0.0@jar'
-}
diff --git a/library/build.gradle b/library/build.gradle
index aba4fc62..c384c1b6 100644
--- a/library/build.gradle
+++ b/library/build.gradle
@@ -18,8 +18,6 @@ dependencies {
compile COMMON_MARK
compile COMMON_MARK_STRIKETHROUGHT
compile COMMON_MARK_TABLE
-
- compile project(':library-task-list')
}
if (project.hasProperty('release')) {
diff --git a/library/src/main/java/ru/noties/markwon/Markwon.java b/library/src/main/java/ru/noties/markwon/Markwon.java
index 9f74ebbd..f2daf964 100644
--- a/library/src/main/java/ru/noties/markwon/Markwon.java
+++ b/library/src/main/java/ru/noties/markwon/Markwon.java
@@ -17,7 +17,7 @@ import java.util.Arrays;
import ru.noties.markwon.renderer.SpannableRenderer;
import ru.noties.markwon.tasklist.TaskListExtension;
-@SuppressWarnings("WeakerAccess")
+@SuppressWarnings({"WeakerAccess", "unused"})
public abstract class Markwon {
/**
diff --git a/library/src/main/java/ru/noties/markwon/renderer/SpannableMarkdownVisitor.java b/library/src/main/java/ru/noties/markwon/renderer/SpannableMarkdownVisitor.java
index a9c00690..146769bc 100644
--- a/library/src/main/java/ru/noties/markwon/renderer/SpannableMarkdownVisitor.java
+++ b/library/src/main/java/ru/noties/markwon/renderer/SpannableMarkdownVisitor.java
@@ -299,11 +299,25 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
if (customNode instanceof TaskListItem) {
+ final TaskListItem listItem = (TaskListItem) customNode;
+
final int length = builder.length();
+
+ blockQuoteIndent += listItem.indent();
+
visitChildren(customNode);
- setSpan(length, new TaskListSpan(configuration.theme(), blockQuoteIndent, length, ((TaskListItem) customNode).done()));
+
+ setSpan(length, new TaskListSpan(
+ configuration.theme(),
+ blockQuoteIndent,
+ length,
+ listItem.done()
+ ));
+
newLine();
+ blockQuoteIndent -= listItem.indent();
+
} else {
super.visit(customNode);
}
diff --git a/library/src/main/java/ru/noties/markwon/renderer/SpannableRenderer.java b/library/src/main/java/ru/noties/markwon/renderer/SpannableRenderer.java
index e20d0b63..25073964 100644
--- a/library/src/main/java/ru/noties/markwon/renderer/SpannableRenderer.java
+++ b/library/src/main/java/ru/noties/markwon/renderer/SpannableRenderer.java
@@ -8,16 +8,9 @@ import org.commonmark.node.Node;
import ru.noties.markwon.SpannableConfiguration;
-// please note that this class does not implement Renderer in order to return CharSequence (instead of String)
public class SpannableRenderer {
- // todo
- // * LinkDrawableSpan, that draws link whilst image is still loading (it must be clickable...)
- // * Common interface for images (in markdown & inline-html)
- // * util method to properly copy markdown (with lists/links, etc)
- // * util to apply empty line height
- // * transform relative urls to absolute ones...
-
+ @Nullable
public CharSequence render(@NonNull SpannableConfiguration configuration, @Nullable Node node) {
final CharSequence out;
if (node == null) {
diff --git a/library/src/main/java/ru/noties/markwon/spans/SpannableTheme.java b/library/src/main/java/ru/noties/markwon/spans/SpannableTheme.java
index 63d8b69b..8801ce8f 100644
--- a/library/src/main/java/ru/noties/markwon/spans/SpannableTheme.java
+++ b/library/src/main/java/ru/noties/markwon/spans/SpannableTheme.java
@@ -11,22 +11,13 @@ import android.support.annotation.Dimension;
import android.support.annotation.FloatRange;
import android.support.annotation.IntRange;
import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import android.text.TextPaint;
import android.util.TypedValue;
@SuppressWarnings("WeakerAccess")
public class SpannableTheme {
-//
-// // this method should be used if TextView is known beforehand
-// // it will correctly measure the `space` char and set it as `codeMultilineMargin`
-// // otherwise this value must be set explicitly
-// public static SpannableTheme create(@NonNull TextView textView) {
-// return builderWithDefaults(textView.getContext())
-// .codeMultilineMargin((int) (textView.getPaint().measureText("\u00a0") + .5F))
-// .build();
-// }
- // this create default theme (except for `codeMultilineMargin` property)
public static SpannableTheme create(@NonNull Context context) {
return builderWithDefaults(context).build();
}
@@ -41,6 +32,8 @@ public class SpannableTheme {
public static Builder builderWithDefaults(@NonNull Context context) {
+ // by default we will be using link color for the checkbox color
+ // & window background as a checkMark color
final int linkColor = resolve(context, android.R.attr.textColorLink);
final int backgroundColor = resolve(context, android.R.attr.colorBackground);
@@ -153,6 +146,8 @@ public class SpannableTheme {
// by default paint.color * TABLE_ODD_ROW_DEF_ALPHA
protected final int tableOddRowBackgroundColor;
+ // drawable that will be used to render checkbox (should be stateful)
+ // TaskListDrawable can be used
protected final Drawable taskListDrawable;
protected SpannableTheme(@NonNull Builder builder) {
@@ -252,10 +247,16 @@ public class SpannableTheme {
// 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) {
paint.setTextSize(codeTextSize);
}
+
} else {
paint.setTypeface(Typeface.MONOSPACE);
final float textSize;
@@ -372,7 +373,7 @@ public class SpannableTheme {
paint.setStyle(Paint.Style.FILL);
}
- @NonNull
+ @Nullable
public Drawable getTaskListDrawable() {
return taskListDrawable;
}
@@ -546,6 +547,7 @@ public class SpannableTheme {
}
private static class Dip {
+
private final float density;
Dip(@NonNull Context context) {
diff --git a/library/src/main/java/ru/noties/markwon/spans/TaskListDrawable.java b/library/src/main/java/ru/noties/markwon/spans/TaskListDrawable.java
index f53931a1..78834aac 100644
--- a/library/src/main/java/ru/noties/markwon/spans/TaskListDrawable.java
+++ b/library/src/main/java/ru/noties/markwon/spans/TaskListDrawable.java
@@ -46,7 +46,7 @@ public class TaskListDrawable extends Drawable {
protected void onBoundsChange(Rect bounds) {
super.onBoundsChange(bounds);
- // we should exclude stroke with from final bounds (half of the strokeWidth from both sides)
+ // we should exclude stroke with from final bounds (half of the strokeWidth from all sides)
// we should have square shape
final float min = Math.min(bounds.width(), bounds.height());
diff --git a/library/src/main/java/ru/noties/markwon/spans/TaskListSpan.java b/library/src/main/java/ru/noties/markwon/spans/TaskListSpan.java
index af647558..3af7e297 100644
--- a/library/src/main/java/ru/noties/markwon/spans/TaskListSpan.java
+++ b/library/src/main/java/ru/noties/markwon/spans/TaskListSpan.java
@@ -23,7 +23,7 @@ public class TaskListSpan implements LeadingMarginSpan {
@Override
public int getLeadingMargin(boolean first) {
- return theme.getBlockMargin();
+ return theme.getBlockMargin() * blockIndent;
}
@Override
@@ -33,14 +33,17 @@ public class TaskListSpan implements LeadingMarginSpan {
return;
}
+ final Drawable drawable = theme.getTaskListDrawable();
+ if (drawable == null) {
+ return;
+ }
+
final int save = c.save();
try {
final int width = theme.getBlockMargin();
final int height = bottom - top;
- final Drawable drawable = theme.getTaskListDrawable();
-
final int w = (int) (width * .75F + .5F);
final int h = (int) (height * .75F + .5F);
diff --git a/library-task-list/src/main/java/ru/noties/markwon/tasklist/TaskListBlock.java b/library/src/main/java/ru/noties/markwon/tasklist/TaskListBlock.java
similarity index 100%
rename from library-task-list/src/main/java/ru/noties/markwon/tasklist/TaskListBlock.java
rename to library/src/main/java/ru/noties/markwon/tasklist/TaskListBlock.java
diff --git a/library-task-list/src/main/java/ru/noties/markwon/tasklist/TaskListBlockParser.java b/library/src/main/java/ru/noties/markwon/tasklist/TaskListBlockParser.java
similarity index 61%
rename from library-task-list/src/main/java/ru/noties/markwon/tasklist/TaskListBlockParser.java
rename to library/src/main/java/ru/noties/markwon/tasklist/TaskListBlockParser.java
index f6942fe5..27752168 100644
--- a/library-task-list/src/main/java/ru/noties/markwon/tasklist/TaskListBlockParser.java
+++ b/library/src/main/java/ru/noties/markwon/tasklist/TaskListBlockParser.java
@@ -17,20 +17,20 @@ import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import ru.noties.debug.Debug;
-
+@SuppressWarnings("WeakerAccess")
class TaskListBlockParser extends AbstractBlockParser {
private static final Pattern PATTERN = Pattern.compile("\\s*-\\s+\\[(x|X|\\s)\\]\\s+(.*)");
-// private static final Pattern PATTERN_2 = Pattern.compile("^\\s*-\\s+\\[(x|X|\\s)\\]\\s+(.*)");
private final TaskListBlock block = new TaskListBlock();
- private final List lines;
+ private final List- items = new ArrayList<>(3);
- TaskListBlockParser(@NonNull String startLine) {
- this.lines = new ArrayList<>(3);
- this.lines.add(startLine);
+ private int indent = 0;
+
+ TaskListBlockParser(@NonNull String startLine, int startIndent) {
+ items.add(new Item(startLine, startIndent));
+ indent = startIndent;
}
@Override
@@ -45,16 +45,18 @@ class TaskListBlockParser extends AbstractBlockParser {
final String line = line(parserState);
-// Debug.i("line: %s, find: %s", line, PATTERN.matcher(line).find());
- Debug.i("isBlank: %s, line: `%s`", parserState.isBlank(), line);
+ final int currentIndent = parserState.getIndent();
+ if (currentIndent > indent) {
+ indent += 2;
+ } else if (currentIndent < indent && indent > 1) {
+ indent -= 2;
+ }
if (line != null
&& line.length() > 0
&& PATTERN.matcher(line).matches()) {
- Debug.e();
blockContinue = BlockContinue.atIndex(parserState.getIndex());
} else {
- Debug.e();
blockContinue = BlockContinue.finished();
}
@@ -63,54 +65,29 @@ class TaskListBlockParser extends AbstractBlockParser {
@Override
public void addLine(CharSequence line) {
- Debug.i("line: %s", line);
- if (line != null
- && line.length() > 0) {
- lines.add(line.toString());
+ if (length(line) > 0) {
+ items.add(new Item(line.toString(), indent));
}
}
@Override
public void parseInlines(InlineParser inlineParser) {
- Debug.i(lines);
-
Matcher matcher;
- TaskListItem item;
-
- for (String line : lines) {
-
- matcher = PATTERN.matcher(line);
+ TaskListItem listItem;
+ for (Item item : items) {
+ matcher = PATTERN.matcher(item.line);
if (!matcher.matches()) {
continue;
}
-
- item = new TaskListItem().done(isDone(matcher.group(1)));
-
- inlineParser.parse(matcher.group(2), item);
-
- block.appendChild(item);
+ listItem = new TaskListItem()
+ .done(isDone(matcher.group(1)))
+ .indent(item.indent / 2);
+ inlineParser.parse(matcher.group(2), listItem);
+ block.appendChild(listItem);
}
-
- }
-
- @Override
- public boolean isContainer() {
- return false;
- }
-
- @Override
- public boolean canContain(Block block) {
- Debug.i("block: %s", block);
- return false;
- }
-
- @Override
- public void closeBlock() {
- Debug.e(block);
- Debug.trace();
}
static class Factory extends AbstractBlockParserFactory {
@@ -124,8 +101,14 @@ class TaskListBlockParser extends AbstractBlockParser {
&& line.length() > 0
&& PATTERN.matcher(line).matches()) {
- return BlockStart.of(new TaskListBlockParser(line))
- .atIndex(state.getIndex() + line.length());
+ final int length = line.length();
+ final int index = state.getIndex();
+ final int atIndex = index != 0
+ ? index + (length - index)
+ : length;
+
+ return BlockStart.of(new TaskListBlockParser(line, state.getIndent()))
+ .atIndex(atIndex);
}
return BlockStart.none();
@@ -140,8 +123,25 @@ class TaskListBlockParser extends AbstractBlockParser {
: null;
}
+ private static int length(@Nullable CharSequence text) {
+ return text != null
+ ? text.length()
+ : 0;
+ }
+
private static boolean isDone(@NonNull String value) {
return "X".equals(value)
|| "x".equals(value);
}
+
+ private static class Item {
+
+ final String line;
+ final int indent;
+
+ Item(@NonNull String line, int indent) {
+ this.line = line;
+ this.indent = indent;
+ }
+ }
}
diff --git a/library-task-list/src/main/java/ru/noties/markwon/tasklist/TaskListExtension.java b/library/src/main/java/ru/noties/markwon/tasklist/TaskListExtension.java
similarity index 100%
rename from library-task-list/src/main/java/ru/noties/markwon/tasklist/TaskListExtension.java
rename to library/src/main/java/ru/noties/markwon/tasklist/TaskListExtension.java
diff --git a/library-task-list/src/main/java/ru/noties/markwon/tasklist/TaskListItem.java b/library/src/main/java/ru/noties/markwon/tasklist/TaskListItem.java
similarity index 58%
rename from library-task-list/src/main/java/ru/noties/markwon/tasklist/TaskListItem.java
rename to library/src/main/java/ru/noties/markwon/tasklist/TaskListItem.java
index cef9fcff..9904ee76 100644
--- a/library-task-list/src/main/java/ru/noties/markwon/tasklist/TaskListItem.java
+++ b/library/src/main/java/ru/noties/markwon/tasklist/TaskListItem.java
@@ -2,9 +2,11 @@ package ru.noties.markwon.tasklist;
import org.commonmark.node.CustomNode;
+@SuppressWarnings("WeakerAccess")
public class TaskListItem extends CustomNode {
private boolean done;
+ private int indent;
public boolean done() {
return done;
@@ -14,4 +16,13 @@ public class TaskListItem extends CustomNode {
this.done = done;
return this;
}
+
+ public int indent() {
+ return indent;
+ }
+
+ public TaskListItem indent(int indent) {
+ this.indent = indent;
+ return this;
+ }
}
diff --git a/settings.gradle b/settings.gradle
index 4baa558b..59f2e834 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1 +1 @@
-include ':app', ':library', ':library-image-loader', ':library-view', ':library-task-list'
+include ':app', ':library', ':library-image-loader', ':library-view'