Added ability to load from assets
This commit is contained in:
parent
261f289329
commit
97f13926e0
34
README.md
34
README.md
@ -1,3 +1,5 @@
|
|||||||
|

|
||||||
|
|
||||||
# Markwon
|
# Markwon
|
||||||
|
|
||||||
[](http://search.maven.org/#search|ga|1|g%3A%22ru.noties%22%20AND%20a%3A%markwon%22)
|
[](http://search.maven.org/#search|ga|1|g%3A%22ru.noties%22%20AND%20a%3A%markwon%22)
|
||||||
@ -40,6 +42,9 @@ compile 'ru.noties:markwon-image-loader:1.0.0' // optional
|
|||||||
* other inline html is rendered via (`Html.fromHtml(...)`)
|
* other inline html is rendered via (`Html.fromHtml(...)`)
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
### Emphasis
|
### Emphasis
|
||||||
|
|
||||||
*Lorem ipsum dolor sit amet*
|
*Lorem ipsum dolor sit amet*
|
||||||
@ -55,6 +60,9 @@ _Lorem ipsum dolor sit amet_
|
|||||||
<dfn>Lorem ipsum dolor sit amet</dfn>
|
<dfn>Lorem ipsum dolor sit amet</dfn>
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
### Strong emphasis
|
### Strong emphasis
|
||||||
|
|
||||||
**Lorem ipsum dolor sit amet**
|
**Lorem ipsum dolor sit amet**
|
||||||
@ -66,6 +74,9 @@ __Lorem ipsum dolor sit amet__
|
|||||||
<strong>Lorem ipsum dolor sit amet</strong>
|
<strong>Lorem ipsum dolor sit amet</strong>
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
### Strike-through
|
### Strike-through
|
||||||
|
|
||||||
~~Lorem ipsum dolor sit amet~~
|
~~Lorem ipsum dolor sit amet~~
|
||||||
@ -97,9 +108,7 @@ __Lorem ipsum dolor sit amet__
|
|||||||
|
|
||||||
<a href="https://github.com">click me</a>
|
<a href="https://github.com">click me</a>
|
||||||
|
|
||||||
|
---
|
||||||
### Images
|
|
||||||
// todo, normal ones & svg & gif
|
|
||||||
|
|
||||||
|
|
||||||
### Thematic break
|
### Thematic break
|
||||||
@ -114,6 +123,9 @@ ___
|
|||||||
>>> Lorem ipsum dolor sit amet
|
>>> Lorem ipsum dolor sit amet
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
### Ordered lists
|
### Ordered lists
|
||||||
1. Lorem ipsum dolor sit amet
|
1. Lorem ipsum dolor sit amet
|
||||||
2. Lorem ipsum dolor sit amet
|
2. Lorem ipsum dolor sit amet
|
||||||
@ -123,6 +135,9 @@ ___
|
|||||||
3. Lorem ipsum dolor sit amet
|
3. Lorem ipsum dolor sit amet
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
### Non-ordered lists
|
### Non-ordered lists
|
||||||
* Lorem ipsum dolor sit amet
|
* Lorem ipsum dolor sit amet
|
||||||
* Lorem ipsum dolor sit amet
|
* Lorem ipsum dolor sit amet
|
||||||
@ -132,6 +147,9 @@ ___
|
|||||||
* Lorem ipsum dolor sit amet
|
* Lorem ipsum dolor sit amet
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
### Inline code
|
### Inline code
|
||||||
`Lorem` ipsum dolor sit amet
|
`Lorem` ipsum dolor sit amet
|
||||||
Lorem `ipsum` dolor sit amet
|
Lorem `ipsum` dolor sit amet
|
||||||
@ -142,6 +160,9 @@ Lorem ipsum dolor sit `amet`
|
|||||||
`Lorem ipsum dolor sit amet`
|
`Lorem ipsum dolor sit amet`
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
### Code block
|
### Code block
|
||||||
```
|
```
|
||||||
Lorem ipsum dolor sit amet
|
Lorem ipsum dolor sit amet
|
||||||
@ -149,11 +170,16 @@ Lorem ipsum dolor sit amet
|
|||||||
Lorem ipsum dolor sit amet
|
Lorem ipsum dolor sit amet
|
||||||
```
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
### H.T.M.L.
|
### H.T.M.L.
|
||||||
<b>O</b><i>K<s>A</s><sup>42<sup>43<sub><b>42</b></sub></sup></sup><u>Y</u></i>
|
<b>O</b><i>K<s>A</s><sup>42<sup>43<sub><b>42</b></sub></sup></sup><u>Y</u></i>
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
### Tables
|
### Tables
|
||||||
Header #1 | Header #2 | Header #3
|
Header #1 | Header #2 | Header #3
|
||||||
---: | :---: | :---
|
---: | :---: | :---
|
||||||
@ -173,4 +199,4 @@ long long long skjfs fgjsdfhj sf `dfk df` | sdsd,fklsdfklsdfklsdfkl sdfkl dsfjks
|
|||||||
[github]: https://github.com
|
[github]: https://github.com
|
||||||
|
|
||||||
[commonmark-java]: https://github.com/atlassian/commonmark-java/blob/master/README.md
|
[commonmark-java]: https://github.com/atlassian/commonmark-java/blob/master/README.md
|
||||||
[library]: https://github.com/noties/Markwon/blob/master/README.md
|
[library]: https://github.com/noties/Markwon/blob/master/library/README.md
|
1
app/src/main/assets/art/markwon_logo.png
Symbolic link
1
app/src/main/assets/art/markwon_logo.png
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../../../../../art/markwon_logo.png
|
@ -42,6 +42,7 @@ class AppModule {
|
|||||||
return new OkHttpClient.Builder()
|
return new OkHttpClient.Builder()
|
||||||
.cache(new Cache(app.getCacheDir(), 1024L * 20))
|
.cache(new Cache(app.getCacheDir(), 1024L * 20))
|
||||||
.followRedirects(true)
|
.followRedirects(true)
|
||||||
|
.retryOnConnectionFailure(true)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,17 +6,11 @@ import android.os.Handler;
|
|||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
import org.commonmark.ext.gfm.strikethrough.StrikethroughExtension;
|
|
||||||
import org.commonmark.node.Node;
|
|
||||||
import org.commonmark.parser.Parser;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import ru.noties.markwon.renderer.SpannableRenderer;
|
|
||||||
import ru.noties.markwon.spans.AsyncDrawable;
|
import ru.noties.markwon.spans.AsyncDrawable;
|
||||||
|
|
||||||
@ActivityScope
|
@ActivityScope
|
||||||
@ -53,7 +47,7 @@ public class MarkdownRenderer {
|
|||||||
|
|
||||||
final UrlProcessor urlProcessor;
|
final UrlProcessor urlProcessor;
|
||||||
if (uri == null) {
|
if (uri == null) {
|
||||||
urlProcessor = null;
|
urlProcessor = new UrlProcessorAndroidAssets();
|
||||||
} else {
|
} else {
|
||||||
urlProcessor = new UrlProcessorRelativeToAbsolute(uri.toString());
|
urlProcessor = new UrlProcessorRelativeToAbsolute(uri.toString());
|
||||||
}
|
}
|
||||||
|
BIN
art/markwon_logo.png
Normal file
BIN
art/markwon_logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
@ -14,7 +14,6 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
|
||||||
compile project(':library')
|
compile project(':library')
|
||||||
compile ANDROID_SVG
|
compile ANDROID_SVG
|
||||||
compile ANDROID_GIF
|
compile ANDROID_GIF
|
||||||
|
@ -6,6 +6,7 @@ import android.graphics.BitmapFactory;
|
|||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.drawable.BitmapDrawable;
|
import android.graphics.drawable.BitmapDrawable;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
@ -14,7 +15,11 @@ import android.text.TextUtils;
|
|||||||
import com.caverock.androidsvg.SVG;
|
import com.caverock.androidsvg.SVG;
|
||||||
import com.caverock.androidsvg.SVGParseException;
|
import com.caverock.androidsvg.SVGParseException;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
@ -46,6 +51,8 @@ public class AsyncDrawableLoader implements AsyncDrawable.Loader {
|
|||||||
private static final String CONTENT_TYPE_SVG = "image/svg+xml";
|
private static final String CONTENT_TYPE_SVG = "image/svg+xml";
|
||||||
private static final String CONTENT_TYPE_GIF = "image/gif";
|
private static final String CONTENT_TYPE_GIF = "image/gif";
|
||||||
|
|
||||||
|
private static final String FILE_ANDROID_ASSETS = "android_asset";
|
||||||
|
|
||||||
private final OkHttpClient client;
|
private final OkHttpClient client;
|
||||||
private final Resources resources;
|
private final Resources resources;
|
||||||
private final ExecutorService executorService;
|
private final ExecutorService executorService;
|
||||||
@ -97,47 +104,32 @@ public class AsyncDrawableLoader implements AsyncDrawable.Loader {
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
|
||||||
final Request request = new Request.Builder()
|
final Item item;
|
||||||
.url(destination)
|
|
||||||
.tag(destination)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
Response response = null;
|
final Uri uri = Uri.parse(destination);
|
||||||
try {
|
if ("file".equals(uri.getScheme())) {
|
||||||
response = client.newCall(request).execute();
|
item = fromFile(uri);
|
||||||
} catch (IOException e) {
|
} else {
|
||||||
e.printStackTrace();
|
item = fromNetwork(destination);
|
||||||
}
|
}
|
||||||
|
|
||||||
Drawable result = null;
|
Drawable result = null;
|
||||||
|
|
||||||
if (response != null) {
|
if (item != null
|
||||||
|
&& item.inputStream != null) {
|
||||||
final ResponseBody body = response.body();
|
try {
|
||||||
if (body != null) {
|
if (CONTENT_TYPE_SVG.equals(item.type)) {
|
||||||
final InputStream inputStream = body.byteStream();
|
result = handleSvg(item.inputStream);
|
||||||
if (inputStream != null) {
|
} else if (CONTENT_TYPE_GIF.equals(item.type)) {
|
||||||
final String contentType = response.header(HEADER_CONTENT_TYPE);
|
result = handleGif(item.inputStream);
|
||||||
try {
|
} else {
|
||||||
// svg can have `image/svg+xml;charset=...`
|
result = handleSimple(item.inputStream);
|
||||||
if (CONTENT_TYPE_SVG.equals(contentType)
|
}
|
||||||
|| (!TextUtils.isEmpty(contentType) && contentType.startsWith(CONTENT_TYPE_SVG))) {
|
} finally {
|
||||||
// handle SVG
|
try {
|
||||||
result = handleSvg(inputStream);
|
item.inputStream.close();
|
||||||
} else if (CONTENT_TYPE_GIF.equals(contentType)) {
|
} catch (IOException e) {
|
||||||
// handle gif
|
// no op
|
||||||
result = handleGif(inputStream);
|
|
||||||
} else {
|
|
||||||
result = handleSimple(inputStream);
|
|
||||||
// just try to decode whatever it is
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
inputStream.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
// no op
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -165,6 +157,102 @@ public class AsyncDrawableLoader implements AsyncDrawable.Loader {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Item fromFile(Uri uri) {
|
||||||
|
|
||||||
|
final List<String> segments = uri.getPathSegments();
|
||||||
|
if (segments == null
|
||||||
|
|| segments.size() == 0) {
|
||||||
|
// pointing to file & having no path segments is no use
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Item out;
|
||||||
|
final String type;
|
||||||
|
final InputStream inputStream;
|
||||||
|
|
||||||
|
final boolean assets = FILE_ANDROID_ASSETS.equals(segments.get(0));
|
||||||
|
final String lastSegment = uri.getLastPathSegment();
|
||||||
|
|
||||||
|
if (lastSegment.endsWith(".svg")) {
|
||||||
|
type = CONTENT_TYPE_SVG;
|
||||||
|
} else if (lastSegment.endsWith(".gif")) {
|
||||||
|
type = CONTENT_TYPE_GIF;
|
||||||
|
} else {
|
||||||
|
type = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (assets) {
|
||||||
|
final StringBuilder path = new StringBuilder();
|
||||||
|
for (int i = 1, size = segments.size(); i < size; i++) {
|
||||||
|
if (i != 1) {
|
||||||
|
path.append('/');
|
||||||
|
}
|
||||||
|
path.append(segments.get(i));
|
||||||
|
}
|
||||||
|
// load assets
|
||||||
|
InputStream inner = null;
|
||||||
|
try {
|
||||||
|
inner = resources.getAssets().open(path.toString());
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
inputStream = inner;
|
||||||
|
} else {
|
||||||
|
InputStream inner = null;
|
||||||
|
try {
|
||||||
|
inner = new BufferedInputStream(new FileInputStream(new File(uri.getPath())));
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
inputStream = inner;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inputStream != null) {
|
||||||
|
out = new Item(type, inputStream);
|
||||||
|
} else {
|
||||||
|
out = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Item fromNetwork(String destination) {
|
||||||
|
|
||||||
|
Item out = null;
|
||||||
|
|
||||||
|
final Request request = new Request.Builder()
|
||||||
|
.url(destination)
|
||||||
|
.tag(destination)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Response response = null;
|
||||||
|
try {
|
||||||
|
response = client.newCall(request).execute();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response != null) {
|
||||||
|
final ResponseBody body = response.body();
|
||||||
|
if (body != null) {
|
||||||
|
final InputStream inputStream = body.byteStream();
|
||||||
|
if (inputStream != null) {
|
||||||
|
final String type;
|
||||||
|
final String contentType = response.header(HEADER_CONTENT_TYPE);
|
||||||
|
if (!TextUtils.isEmpty(contentType)
|
||||||
|
&& contentType.startsWith(CONTENT_TYPE_SVG)) {
|
||||||
|
type = CONTENT_TYPE_SVG;
|
||||||
|
} else {
|
||||||
|
type = contentType;
|
||||||
|
}
|
||||||
|
out = new Item(type, inputStream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
private Drawable handleSvg(InputStream stream) {
|
private Drawable handleSvg(InputStream stream) {
|
||||||
|
|
||||||
final Drawable out;
|
final Drawable out;
|
||||||
@ -292,4 +380,14 @@ public class AsyncDrawableLoader implements AsyncDrawable.Loader {
|
|||||||
return new AsyncDrawableLoader(this);
|
return new AsyncDrawableLoader(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class Item {
|
||||||
|
final String type;
|
||||||
|
final InputStream inputStream;
|
||||||
|
|
||||||
|
Item(String type, InputStream inputStream) {
|
||||||
|
this.type = type;
|
||||||
|
this.inputStream = inputStream;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,8 +18,6 @@ dependencies {
|
|||||||
compile COMMON_MARK
|
compile COMMON_MARK
|
||||||
compile COMMON_MARK_STRIKETHROUGHT
|
compile COMMON_MARK_STRIKETHROUGHT
|
||||||
compile COMMON_MARK_TABLE
|
compile COMMON_MARK_TABLE
|
||||||
|
|
||||||
compile 'ru.noties:debug:3.0.0@jar'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (project.hasProperty('release')) {
|
if (project.hasProperty('release')) {
|
||||||
|
@ -0,0 +1,39 @@
|
|||||||
|
package ru.noties.markwon;
|
||||||
|
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
|
||||||
|
public class UrlProcessorAndroidAssets implements UrlProcessor {
|
||||||
|
|
||||||
|
private final UrlProcessorRelativeToAbsolute assetsProcessor
|
||||||
|
= new UrlProcessorRelativeToAbsolute("file:///android_asset/");
|
||||||
|
|
||||||
|
private final UrlProcessor processor;
|
||||||
|
|
||||||
|
public UrlProcessorAndroidAssets() {
|
||||||
|
this(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UrlProcessorAndroidAssets(@Nullable UrlProcessor parent) {
|
||||||
|
this.processor = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public String process(@NonNull String destination) {
|
||||||
|
final String out;
|
||||||
|
final Uri uri = Uri.parse(destination);
|
||||||
|
if (TextUtils.isEmpty(uri.getScheme())) {
|
||||||
|
out = assetsProcessor.process(destination);
|
||||||
|
} else {
|
||||||
|
if (processor != null) {
|
||||||
|
out = processor.process(destination);
|
||||||
|
} else {
|
||||||
|
out = destination;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
}
|
@ -38,7 +38,6 @@ import java.util.ArrayList;
|
|||||||
import java.util.Deque;
|
import java.util.Deque;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import ru.noties.debug.Debug;
|
|
||||||
import ru.noties.markwon.SpannableConfiguration;
|
import ru.noties.markwon.SpannableConfiguration;
|
||||||
import ru.noties.markwon.renderer.html.SpannableHtmlParser;
|
import ru.noties.markwon.renderer.html.SpannableHtmlParser;
|
||||||
import ru.noties.markwon.spans.AsyncDrawable;
|
import ru.noties.markwon.spans.AsyncDrawable;
|
||||||
@ -273,8 +272,6 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
|
|||||||
@Override
|
@Override
|
||||||
public void visit(CustomNode customNode) {
|
public void visit(CustomNode customNode) {
|
||||||
|
|
||||||
// Log.e(null, String.valueOf(customNode));
|
|
||||||
|
|
||||||
if (customNode instanceof Strikethrough) {
|
if (customNode instanceof Strikethrough) {
|
||||||
|
|
||||||
final int length = builder.length();
|
final int length = builder.length();
|
||||||
@ -290,8 +287,6 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
|
|||||||
|
|
||||||
final boolean handled;
|
final boolean handled;
|
||||||
|
|
||||||
Debug.i(node);
|
|
||||||
|
|
||||||
if (node instanceof TableBody) {
|
if (node instanceof TableBody) {
|
||||||
visitChildren(node);
|
visitChildren(node);
|
||||||
tableRows = 0;
|
tableRows = 0;
|
||||||
@ -306,8 +301,6 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
|
|||||||
if (pendingTableRow != null) {
|
if (pendingTableRow != null) {
|
||||||
builder.append(' ');
|
builder.append(' ');
|
||||||
|
|
||||||
Debug.i("adding a row: %d", tableRows);
|
|
||||||
|
|
||||||
final TableRowSpan span = new TableRowSpan(
|
final TableRowSpan span = new TableRowSpan(
|
||||||
configuration.theme(),
|
configuration.theme(),
|
||||||
pendingTableRow,
|
pendingTableRow,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user