Added ability to load from assets

This commit is contained in:
Dimitry Ivanov 2017-05-27 14:12:21 +03:00
parent 261f289329
commit 97f13926e0
10 changed files with 206 additions and 57 deletions

View File

@ -1,3 +1,5 @@
![logo](./art/markwon_logo.png)
# Markwon # Markwon
[![maven|markwon](https://img.shields.io/maven-central/v/ru.noties/markwon.svg?label=maven%7Cmarkwon)](http://search.maven.org/#search|ga|1|g%3A%22ru.noties%22%20AND%20a%3A%markwon%22) [![maven|markwon](https://img.shields.io/maven-central/v/ru.noties/markwon.svg?label=maven%7Cmarkwon)](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

View File

@ -0,0 +1 @@
../../../../../art/markwon_logo.png

View File

@ -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();
} }

View File

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -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

View File

@ -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,50 +104,35 @@ 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();
if (body != null) {
final InputStream inputStream = body.byteStream();
if (inputStream != null) {
final String contentType = response.header(HEADER_CONTENT_TYPE);
try { try {
// svg can have `image/svg+xml;charset=...` if (CONTENT_TYPE_SVG.equals(item.type)) {
if (CONTENT_TYPE_SVG.equals(contentType) result = handleSvg(item.inputStream);
|| (!TextUtils.isEmpty(contentType) && contentType.startsWith(CONTENT_TYPE_SVG))) { } else if (CONTENT_TYPE_GIF.equals(item.type)) {
// handle SVG result = handleGif(item.inputStream);
result = handleSvg(inputStream);
} else if (CONTENT_TYPE_GIF.equals(contentType)) {
// handle gif
result = handleGif(inputStream);
} else { } else {
result = handleSimple(inputStream); result = handleSimple(item.inputStream);
// just try to decode whatever it is
} }
} finally { } finally {
try { try {
inputStream.close(); item.inputStream.close();
} catch (IOException e) { } catch (IOException e) {
// no op // no op
} }
} }
} }
}
}
// if result is null, we assume it's an error // if result is null, we assume it's an error
if (result == null) { if (result == null) {
@ -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;
}
}
} }

View File

@ -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')) {

View File

@ -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;
}
}

View File

@ -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,