Working with readmes

This commit is contained in:
Dimitry Ivanov 2017-05-26 17:42:17 +03:00
parent 0f1b6c4cf7
commit 261f289329
5 changed files with 208 additions and 48 deletions

View File

@ -13,6 +13,10 @@ compile 'ru.noties:markwon-image-loader:1.0.0' // optional
--- ---
**Please note, that this file is created for demonstration purposes. Please refer to `library` module [README][library] instead**
---
## Supported markdown features: ## Supported markdown features:
* Emphasis (`*`, `_`) * Emphasis (`*`, `_`)
* Strong emphasis (`**`, `__`) * Strong emphasis (`**`, `__`)
@ -167,4 +171,6 @@ long long long skjfs fgjsdfhj sf `dfk df` | sdsd,fklsdfklsdfklsdfkl sdfkl dsfjks
[1]: https://github.com [1]: https://github.com
[github]: https://github.com [github]: https://github.com
[commonmark-java]: https://github.com/atlassian/commonmark-java
[commonmark-java]: https://github.com/atlassian/commonmark-java/blob/master/README.md
[library]: https://github.com/noties/Markwon/blob/master/README.md

View File

@ -17,6 +17,142 @@ The most basic example would be:
Markwon.setMarkdown(textView, "**Hello *there*!!**") Markwon.setMarkdown(textView, "**Hello *there*!!**")
``` ```
Please note, that this library depends on [commonmark-java][commonmark-java] (and some extensions):
```groovy
compile 'com.atlassian.commonmark:commonmark:0.9.0'
compile 'com.atlassian.commonmark:commonmark-ext-gfm-strikethrough:0.9.0'
compile 'com.atlassian.commonmark:commonmark-ext-gfm-tables:0.9.0'
```
## Configuration
In order to render correctly markdown, this library need a `SpannableConfiguration` instance. It has 2 factory methods:
```java
// creates default instance
SpannableConfiguration.create(Context);
// returns configurable Builder
SpannableConfiguration.builder(Context);
```
`SpannableConfiguration.Builder` class has these configurable properties (which are described in more detail further):
```java
public Builder theme(SpannableTheme theme);
public Builder asyncDrawableLoader(AsyncDrawable.Loader asyncDrawableLoader);
public Builder syntaxHighlight(SyntaxHighlight syntaxHighlight);
public Builder linkResolver(LinkSpan.Resolver linkResolver);
public Builder urlProcessor(UrlProcessor urlProcessor);
public Builder htmlParser(SpannableHtmlParser htmlParser);
// and obviously:
public SpannableConfiguration build();
```
## Theme
`SpannableTheme` controlls the appearance of rendered markdown. It has pretty reasonable defaults, which are established based on style of a TextView to which it is applied. It has some factory methods:
```java
// creates ready-to-use SpannableThemeObject
SpannableTheme.create(Context);
// can be used to tweak default appearance
SpannableTheme.builderWithDefaults(Context);
// returns empty builder (no default values are set)
SpannableTheme.builder();
// returns a builder that is instantiated with all values from specified SpannableTheme
SpannableTheme.builder(SpannableTheme copyFrom);
```
`SpannableTheme.Builder` have these configurations:
#### Link
```java
public Builder linkColor(@ColorInt int linkColor);
```
#### Block
```java
// left margin for: lists & quotes (text is shifted)
public Builder blockMargin(@Dimension int blockMargin);
```
#### Quote
```java
// width of quote indication (the `|`)
public Builder blockQuoteWidth(@Dimension int blockQuoteWidth);
// color of `|` quote indication
public Builder blockQuoteColor(@ColorInt int blockQuoteColor);
```
#### Lists
```java
// color of list item bullets(●, ○, ■)/numbers
public Builder listItemColor(@ColorInt int listItemColor);
// stroke width for list bullet (2nd level - `○`)
public Builder bulletListItemStrokeWidth(@Dimension int bulletListItemStrokeWidth);
// width of list bullet (●, ○, ■)
public Builder bulletWidth(@Dimension int bulletWidth);
```
#### Code
```java
// text color for `code` blocks
public Builder codeTextColor(@ColorInt int codeTextColor);
// background color for `code` blocks
public Builder codeBackgroundColor(@ColorInt int codeBackgroundColor);
// left margin for multiline `code` blocks
public Builder codeMultilineMargin(@Dimension int codeMultilineMargin);
// typeface of `code` block
public Builder codeTypeface(@NonNull Typeface codeTypeface);
// text size for `code` block
public Builder codeTextSize(@Dimension int codeTextSize);
```
#### Headings
```java
// height of the `break` line under h1 & h2
public Builder headingBreakHeight(@Dimension int headingBreakHeight);
// color of the `break` line under h1 & h2
public Builder headingBreakColor(@ColorInt int headingBreakColor);
```
#### SuperScript & SupScript
```java
// ratio for <sup> & <sub> text size (calculated based on TextView text size)
public Builder scriptTextSizeRatio(@FloatRange(from = .0F, to = Float.MAX_VALUE) float scriptTextSizeRatio);
```
#### Thematic break
```java
// the `---` thematic break color
public Builder thematicBreakColor(@ColorInt int thematicBreakColor);
// the `---` thematic break height
public Builder thematicBreakHeight(@Dimension int thematicBreakHeight);
```
#### Tables
```java
// padding inside a table cell
public Builder tableCellPadding(@Dimension int tableCellPadding);
// color of table borders
public Builder tableBorderColor(@ColorInt int tableBorderColor);
// the `stroke` width of table border
public Builder tableBorderWidth(@Dimension int tableBorderWidth);
// the background of odd table rows
public Builder tableOddRowBackgroundColor(@ColorInt int tableOddRowBackgroundColor);
```
## Images ## Images
By default this library does not render any of the images. It's done to simplify rendering of text-based markdown. But if images must be supported, then the `AsyncDrawable.Loader` can be specified whilst building a `SpannableConfiguration` instance: By default this library does not render any of the images. It's done to simplify rendering of text-based markdown. But if images must be supported, then the `AsyncDrawable.Loader` can be specified whilst building a `SpannableConfiguration` instance:
@ -29,6 +165,8 @@ final AsyncDrawable.Loader loader = new AsyncDrawable.Loader() {
download(destination, new Callback() { download(destination, new Callback() {
@Override @Override
public void onDownloaded(Drawable d) { public void onDownloaded(Drawable d) {
// additionally we can call `drawable.isAttached()`
// to ensure if AsyncDrawable is in layout
drawable.setResult(d); drawable.setResult(d);
} }
}); });
@ -55,7 +193,7 @@ Tables are supported but with some limitations. First of all: table will always
## Syntax highlight ## Syntax highlight
This library does not provide ready-to-be-used implementation of syntax highlight, but it can be easily added via `SyntaxHighlight` interface whilst building `SpannableConfiguration`: This library does not provide ready-to-be-used implementation of syntax highlight, but it can be added via `SyntaxHighlight` interface whilst building `SpannableConfiguration`:
```java ```java
final SyntaxHighlight syntaxHighlight = new SyntaxHighlight() { final SyntaxHighlight syntaxHighlight = new SyntaxHighlight() {
@ -93,5 +231,21 @@ The primary goal of additing this abstraction is to give ability to convert rela
final UrlProcessor urlProcessor = new UrlProcessorRelativeToAbsolute("https://this-is-base.org"); final UrlProcessor urlProcessor = new UrlProcessorRelativeToAbsolute("https://this-is-base.org");
``` ```
## Link resolver
Link resolver is used to navigate to clicked link. By default `LinkResolverDef` is used and it just constructs an `Intent` and launches activity that can handle it, or silently fails if activity cannot be resolved. The main interface:
```java
public interface Resolver {
void resolve(View view, @NonNull String link);
}
```
## HTML parser
As markdown supports HTML to be inlined, we need to introduce another entity that does (limited) parsing. Obtain an instance of `SpannableHtmlParser` via one of these factory methods:
```java
SpannableHtmlParser.create(SpannableTheme, AsyncDrawable.Loader)
SpannableHtmlParser.create(SpannableTheme, AsyncDrawable.Loader, UrlProcessor, LinkSpan.Resolver)
```
[commonmark-java]: https://github.com/atlassian/commonmark-java
[mil-README]: https://github.com/noties/Markwon/blob/master/library-image-loader/README.md [mil-README]: https://github.com/noties/Markwon/blob/master/library-image-loader/README.md

View File

@ -70,7 +70,7 @@ public class SpannableConfiguration {
private UrlProcessor urlProcessor; private UrlProcessor urlProcessor;
private SpannableHtmlParser htmlParser; private SpannableHtmlParser htmlParser;
public Builder(Context context) { Builder(Context context) {
this.context = context; this.context = context;
} }

View File

@ -163,7 +163,7 @@ public class SpannableHtmlParser {
private ImageProvider imageProvider; private ImageProvider imageProvider;
private HtmlParser parser; private HtmlParser parser;
public Builder simpleTag(@NonNull String tag, @NonNull SpanProvider provider) { Builder simpleTag(@NonNull String tag, @NonNull SpanProvider provider) {
simpleTags.put(tag, provider); simpleTags.put(tag, provider);
return this; return this;
} }

View File

@ -5,23 +5,25 @@ import android.content.res.TypedArray;
import android.graphics.Paint; import android.graphics.Paint;
import android.graphics.Typeface; import android.graphics.Typeface;
import android.support.annotation.AttrRes; import android.support.annotation.AttrRes;
import android.support.annotation.ColorInt;
import android.support.annotation.Dimension;
import android.support.annotation.FloatRange;
import android.support.annotation.IntRange; import android.support.annotation.IntRange;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.text.TextPaint; import android.text.TextPaint;
import android.util.TypedValue; import android.util.TypedValue;
import android.widget.TextView;
@SuppressWarnings("WeakerAccess") @SuppressWarnings("WeakerAccess")
public class SpannableTheme { public class SpannableTheme {
//
// this method should be used if TextView is known beforehand // // this method should be used if TextView is known beforehand
// it will correctly measure the `space` char and set it as `codeMultilineMargin` // // it will correctly measure the `space` char and set it as `codeMultilineMargin`
// otherwise this value must be set explicitly // // otherwise this value must be set explicitly
public static SpannableTheme create(@NonNull TextView textView) { // public static SpannableTheme create(@NonNull TextView textView) {
return builderWithDefaults(textView.getContext()) // return builderWithDefaults(textView.getContext())
.codeMultilineMargin((int) (textView.getPaint().measureText("\u00a0") + .5F)) // .codeMultilineMargin((int) (textView.getPaint().measureText("\u00a0") + .5F))
.build(); // .build();
} // }
// this create default theme (except for `codeMultilineMargin` property) // this create default theme (except for `codeMultilineMargin` property)
public static SpannableTheme create(@NonNull Context context) { public static SpannableTheme create(@NonNull Context context) {
@ -37,16 +39,16 @@ public class SpannableTheme {
} }
public static Builder builderWithDefaults(@NonNull Context context) { public static Builder builderWithDefaults(@NonNull Context context) {
final Px px = new Px(context); final Dip dip = new Dip(context);
return new Builder() return new Builder()
.linkColor(resolve(context, android.R.attr.textColorLink)) .linkColor(resolve(context, android.R.attr.textColorLink))
.codeMultilineMargin(px.px(8)) .codeMultilineMargin(dip.toPx(8))
.blockMargin(px.px(24)) .blockMargin(dip.toPx(24))
.bulletListItemStrokeWidth(px.px(1)) .bulletListItemStrokeWidth(dip.toPx(1))
.headingBreakHeight(px.px(1)) .headingBreakHeight(dip.toPx(1))
.thematicBreakHeight(px.px(2)) .thematicBreakHeight(dip.toPx(2))
.tableCellPadding(px.px(4)) .tableCellPadding(dip.toPx(4))
.tableBorderWidth(px.px(1)); .tableBorderWidth(dip.toPx(1));
} }
private static int resolve(Context context, @AttrRes int attr) { private static int resolve(Context context, @AttrRes int attr) {
@ -385,11 +387,9 @@ public class SpannableTheme {
private int tableOddRowBackgroundColor; private int tableOddRowBackgroundColor;
Builder() { Builder() {
} }
Builder(@NonNull SpannableTheme theme) { Builder(@NonNull SpannableTheme theme) {
this.linkColor = theme.linkColor; this.linkColor = theme.linkColor;
this.blockMargin = theme.blockMargin; this.blockMargin = theme.blockMargin;
this.blockQuoteWidth = theme.blockQuoteWidth; this.blockQuoteWidth = theme.blockQuoteWidth;
@ -413,107 +413,107 @@ public class SpannableTheme {
this.tableOddRowBackgroundColor = theme.tableOddRowBackgroundColor; this.tableOddRowBackgroundColor = theme.tableOddRowBackgroundColor;
} }
public Builder linkColor(int linkColor) { public Builder linkColor(@ColorInt int linkColor) {
this.linkColor = linkColor; this.linkColor = linkColor;
return this; return this;
} }
public Builder blockMargin(int blockMargin) { public Builder blockMargin(@Dimension int blockMargin) {
this.blockMargin = blockMargin; this.blockMargin = blockMargin;
return this; return this;
} }
public Builder blockQuoteWidth(int blockQuoteWidth) { public Builder blockQuoteWidth(@Dimension int blockQuoteWidth) {
this.blockQuoteWidth = blockQuoteWidth; this.blockQuoteWidth = blockQuoteWidth;
return this; return this;
} }
public Builder blockQuoteColor(int blockQuoteColor) { public Builder blockQuoteColor(@ColorInt int blockQuoteColor) {
this.blockQuoteColor = blockQuoteColor; this.blockQuoteColor = blockQuoteColor;
return this; return this;
} }
public Builder listItemColor(int listItemColor) { public Builder listItemColor(@ColorInt int listItemColor) {
this.listItemColor = listItemColor; this.listItemColor = listItemColor;
return this; return this;
} }
public Builder bulletListItemStrokeWidth(int bulletListItemStrokeWidth) { public Builder bulletListItemStrokeWidth(@Dimension int bulletListItemStrokeWidth) {
this.bulletListItemStrokeWidth = bulletListItemStrokeWidth; this.bulletListItemStrokeWidth = bulletListItemStrokeWidth;
return this; return this;
} }
public Builder bulletWidth(int bulletWidth) { public Builder bulletWidth(@Dimension int bulletWidth) {
this.bulletWidth = bulletWidth; this.bulletWidth = bulletWidth;
return this; return this;
} }
public Builder codeTextColor(int codeTextColor) { public Builder codeTextColor(@ColorInt int codeTextColor) {
this.codeTextColor = codeTextColor; this.codeTextColor = codeTextColor;
return this; return this;
} }
public Builder codeBackgroundColor(int codeBackgroundColor) { public Builder codeBackgroundColor(@ColorInt int codeBackgroundColor) {
this.codeBackgroundColor = codeBackgroundColor; this.codeBackgroundColor = codeBackgroundColor;
return this; return this;
} }
public Builder codeMultilineMargin(int codeMultilineMargin) { public Builder codeMultilineMargin(@Dimension int codeMultilineMargin) {
this.codeMultilineMargin = codeMultilineMargin; this.codeMultilineMargin = codeMultilineMargin;
return this; return this;
} }
public Builder codeTypeface(Typeface codeTypeface) { public Builder codeTypeface(@NonNull Typeface codeTypeface) {
this.codeTypeface = codeTypeface; this.codeTypeface = codeTypeface;
return this; return this;
} }
public Builder codeTextSize(int codeTextSize) { public Builder codeTextSize(@Dimension int codeTextSize) {
this.codeTextSize = codeTextSize; this.codeTextSize = codeTextSize;
return this; return this;
} }
public Builder headingBreakHeight(int headingBreakHeight) { public Builder headingBreakHeight(@Dimension int headingBreakHeight) {
this.headingBreakHeight = headingBreakHeight; this.headingBreakHeight = headingBreakHeight;
return this; return this;
} }
public Builder headingBreakColor(int headingBreakColor) { public Builder headingBreakColor(@ColorInt int headingBreakColor) {
this.headingBreakColor = headingBreakColor; this.headingBreakColor = headingBreakColor;
return this; return this;
} }
public Builder scriptTextSizeRatio(float scriptTextSizeRatio) { public Builder scriptTextSizeRatio(@FloatRange(from = .0F, to = Float.MAX_VALUE) float scriptTextSizeRatio) {
this.scriptTextSizeRatio = scriptTextSizeRatio; this.scriptTextSizeRatio = scriptTextSizeRatio;
return this; return this;
} }
public Builder thematicBreakColor(int thematicBreakColor) { public Builder thematicBreakColor(@ColorInt int thematicBreakColor) {
this.thematicBreakColor = thematicBreakColor; this.thematicBreakColor = thematicBreakColor;
return this; return this;
} }
public Builder thematicBreakHeight(int thematicBreakHeight) { public Builder thematicBreakHeight(@Dimension int thematicBreakHeight) {
this.thematicBreakHeight = thematicBreakHeight; this.thematicBreakHeight = thematicBreakHeight;
return this; return this;
} }
public Builder tableCellPadding(int tableCellPadding) { public Builder tableCellPadding(@Dimension int tableCellPadding) {
this.tableCellPadding = tableCellPadding; this.tableCellPadding = tableCellPadding;
return this; return this;
} }
public Builder tableBorderColor(int tableBorderColor) { public Builder tableBorderColor(@ColorInt int tableBorderColor) {
this.tableBorderColor = tableBorderColor; this.tableBorderColor = tableBorderColor;
return this; return this;
} }
public Builder tableBorderWidth(int tableBorderWidth) { public Builder tableBorderWidth(@Dimension int tableBorderWidth) {
this.tableBorderWidth = tableBorderWidth; this.tableBorderWidth = tableBorderWidth;
return this; return this;
} }
public Builder tableOddRowBackgroundColor(int tableOddRowBackgroundColor) { public Builder tableOddRowBackgroundColor(@ColorInt int tableOddRowBackgroundColor) {
this.tableOddRowBackgroundColor = tableOddRowBackgroundColor; this.tableOddRowBackgroundColor = tableOddRowBackgroundColor;
return this; return this;
} }
@ -523,14 +523,14 @@ public class SpannableTheme {
} }
} }
private static class Px { private static class Dip {
private final float density; private final float density;
Px(@NonNull Context context) { Dip(@NonNull Context context) {
this.density = context.getResources().getDisplayMetrics().density; this.density = context.getResources().getDisplayMetrics().density;
} }
int px(int dp) { int toPx(int dp) {
return (int) (dp * density + .5F); return (int) (dp * density + .5F);
} }
} }