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
|
||||
|
||||
[](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(...)`)
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
### Emphasis
|
||||
|
||||
*Lorem ipsum dolor sit amet*
|
||||
@ -55,6 +60,9 @@ _Lorem ipsum dolor sit amet_
|
||||
<dfn>Lorem ipsum dolor sit amet</dfn>
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
### Strong emphasis
|
||||
|
||||
**Lorem ipsum dolor sit amet**
|
||||
@ -66,6 +74,9 @@ __Lorem ipsum dolor sit amet__
|
||||
<strong>Lorem ipsum dolor sit amet</strong>
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
### Strike-through
|
||||
|
||||
~~Lorem ipsum dolor sit amet~~
|
||||
@ -97,9 +108,7 @@ __Lorem ipsum dolor sit amet__
|
||||
|
||||
<a href="https://github.com">click me</a>
|
||||
|
||||
|
||||
### Images
|
||||
// todo, normal ones & svg & gif
|
||||
---
|
||||
|
||||
|
||||
### Thematic break
|
||||
@ -114,6 +123,9 @@ ___
|
||||
>>> Lorem ipsum dolor sit amet
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
### Ordered lists
|
||||
1. Lorem ipsum dolor sit amet
|
||||
2. Lorem ipsum dolor sit amet
|
||||
@ -123,6 +135,9 @@ ___
|
||||
3. Lorem ipsum dolor sit amet
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
### Non-ordered lists
|
||||
* Lorem ipsum dolor sit amet
|
||||
* Lorem ipsum dolor sit amet
|
||||
@ -132,6 +147,9 @@ ___
|
||||
* Lorem ipsum dolor sit amet
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
### Inline code
|
||||
`Lorem` ipsum dolor sit amet
|
||||
Lorem `ipsum` dolor sit amet
|
||||
@ -142,6 +160,9 @@ Lorem ipsum dolor sit `amet`
|
||||
`Lorem ipsum dolor sit amet`
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
### Code block
|
||||
```
|
||||
Lorem ipsum dolor sit amet
|
||||
@ -149,11 +170,16 @@ Lorem ipsum dolor sit amet
|
||||
Lorem ipsum dolor sit amet
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
### 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>
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
### Tables
|
||||
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
|
||||
|
||||
[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()
|
||||
.cache(new Cache(app.getCacheDir(), 1024L * 20))
|
||||
.followRedirects(true)
|
||||
.retryOnConnectionFailure(true)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
@ -6,17 +6,11 @@ import android.os.Handler;
|
||||
import android.support.annotation.NonNull;
|
||||
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.Future;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import ru.noties.markwon.renderer.SpannableRenderer;
|
||||
import ru.noties.markwon.spans.AsyncDrawable;
|
||||
|
||||
@ActivityScope
|
||||
@ -53,7 +47,7 @@ public class MarkdownRenderer {
|
||||
|
||||
final UrlProcessor urlProcessor;
|
||||
if (uri == null) {
|
||||
urlProcessor = null;
|
||||
urlProcessor = new UrlProcessorAndroidAssets();
|
||||
} else {
|
||||
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 {
|
||||
|
||||
compile project(':library')
|
||||
compile ANDROID_SVG
|
||||
compile ANDROID_GIF
|
||||
|
@ -6,6 +6,7 @@ import android.graphics.BitmapFactory;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.support.annotation.NonNull;
|
||||
@ -14,7 +15,11 @@ import android.text.TextUtils;
|
||||
import com.caverock.androidsvg.SVG;
|
||||
import com.caverock.androidsvg.SVGParseException;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
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_GIF = "image/gif";
|
||||
|
||||
private static final String FILE_ANDROID_ASSETS = "android_asset";
|
||||
|
||||
private final OkHttpClient client;
|
||||
private final Resources resources;
|
||||
private final ExecutorService executorService;
|
||||
@ -97,47 +104,32 @@ public class AsyncDrawableLoader implements AsyncDrawable.Loader {
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
final Request request = new Request.Builder()
|
||||
.url(destination)
|
||||
.tag(destination)
|
||||
.build();
|
||||
final Item item;
|
||||
|
||||
Response response = null;
|
||||
try {
|
||||
response = client.newCall(request).execute();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
final Uri uri = Uri.parse(destination);
|
||||
if ("file".equals(uri.getScheme())) {
|
||||
item = fromFile(uri);
|
||||
} else {
|
||||
item = fromNetwork(destination);
|
||||
}
|
||||
|
||||
Drawable result = null;
|
||||
|
||||
if (response != 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 {
|
||||
// svg can have `image/svg+xml;charset=...`
|
||||
if (CONTENT_TYPE_SVG.equals(contentType)
|
||||
|| (!TextUtils.isEmpty(contentType) && contentType.startsWith(CONTENT_TYPE_SVG))) {
|
||||
// handle SVG
|
||||
result = handleSvg(inputStream);
|
||||
} else if (CONTENT_TYPE_GIF.equals(contentType)) {
|
||||
// handle gif
|
||||
result = handleGif(inputStream);
|
||||
} else {
|
||||
result = handleSimple(inputStream);
|
||||
// just try to decode whatever it is
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
inputStream.close();
|
||||
} catch (IOException e) {
|
||||
// no op
|
||||
}
|
||||
}
|
||||
if (item != null
|
||||
&& item.inputStream != null) {
|
||||
try {
|
||||
if (CONTENT_TYPE_SVG.equals(item.type)) {
|
||||
result = handleSvg(item.inputStream);
|
||||
} else if (CONTENT_TYPE_GIF.equals(item.type)) {
|
||||
result = handleGif(item.inputStream);
|
||||
} else {
|
||||
result = handleSimple(item.inputStream);
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
item.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) {
|
||||
|
||||
final Drawable out;
|
||||
@ -292,4 +380,14 @@ public class AsyncDrawableLoader implements AsyncDrawable.Loader {
|
||||
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_STRIKETHROUGHT
|
||||
compile COMMON_MARK_TABLE
|
||||
|
||||
compile 'ru.noties:debug:3.0.0@jar'
|
||||
}
|
||||
|
||||
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.List;
|
||||
|
||||
import ru.noties.debug.Debug;
|
||||
import ru.noties.markwon.SpannableConfiguration;
|
||||
import ru.noties.markwon.renderer.html.SpannableHtmlParser;
|
||||
import ru.noties.markwon.spans.AsyncDrawable;
|
||||
@ -273,8 +272,6 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
|
||||
@Override
|
||||
public void visit(CustomNode customNode) {
|
||||
|
||||
// Log.e(null, String.valueOf(customNode));
|
||||
|
||||
if (customNode instanceof Strikethrough) {
|
||||
|
||||
final int length = builder.length();
|
||||
@ -290,8 +287,6 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
|
||||
|
||||
final boolean handled;
|
||||
|
||||
Debug.i(node);
|
||||
|
||||
if (node instanceof TableBody) {
|
||||
visitChildren(node);
|
||||
tableRows = 0;
|
||||
@ -306,8 +301,6 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
|
||||
if (pendingTableRow != null) {
|
||||
builder.append(' ');
|
||||
|
||||
Debug.i("adding a row: %d", tableRows);
|
||||
|
||||
final TableRowSpan span = new TableRowSpan(
|
||||
configuration.theme(),
|
||||
pendingTableRow,
|
||||
|
Loading…
x
Reference in New Issue
Block a user