diff --git a/README.md b/README.md
index 25518070..dd397986 100644
--- a/README.md
+++ b/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_
Lorem ipsum dolor sit amet
+---
+
+
### Strong emphasis
**Lorem ipsum dolor sit amet**
@@ -66,6 +74,9 @@ __Lorem ipsum dolor sit amet__
Lorem ipsum dolor sit amet
+---
+
+
### Strike-through
~~Lorem ipsum dolor sit amet~~
@@ -97,9 +108,7 @@ __Lorem ipsum dolor sit amet__
click me
-
-### 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.
OKA424342Y
+---
+
+
### 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
\ No newline at end of file
+[library]: https://github.com/noties/Markwon/blob/master/library/README.md
\ No newline at end of file
diff --git a/app/src/main/assets/art/markwon_logo.png b/app/src/main/assets/art/markwon_logo.png
new file mode 120000
index 00000000..16f26621
--- /dev/null
+++ b/app/src/main/assets/art/markwon_logo.png
@@ -0,0 +1 @@
+../../../../../art/markwon_logo.png
\ No newline at end of file
diff --git a/app/src/main/java/ru/noties/markwon/AppModule.java b/app/src/main/java/ru/noties/markwon/AppModule.java
index 7d04a4db..09c5e230 100644
--- a/app/src/main/java/ru/noties/markwon/AppModule.java
+++ b/app/src/main/java/ru/noties/markwon/AppModule.java
@@ -42,6 +42,7 @@ class AppModule {
return new OkHttpClient.Builder()
.cache(new Cache(app.getCacheDir(), 1024L * 20))
.followRedirects(true)
+ .retryOnConnectionFailure(true)
.build();
}
diff --git a/app/src/main/java/ru/noties/markwon/MarkdownRenderer.java b/app/src/main/java/ru/noties/markwon/MarkdownRenderer.java
index 1d0c4dc5..dbbe368a 100644
--- a/app/src/main/java/ru/noties/markwon/MarkdownRenderer.java
+++ b/app/src/main/java/ru/noties/markwon/MarkdownRenderer.java
@@ -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());
}
diff --git a/art/markwon_logo.png b/art/markwon_logo.png
new file mode 100644
index 00000000..817bacb4
Binary files /dev/null and b/art/markwon_logo.png differ
diff --git a/library-image-loader/build.gradle b/library-image-loader/build.gradle
index 68bfa8f1..847ef752 100644
--- a/library-image-loader/build.gradle
+++ b/library-image-loader/build.gradle
@@ -14,7 +14,6 @@ android {
}
dependencies {
-
compile project(':library')
compile ANDROID_SVG
compile ANDROID_GIF
diff --git a/library-image-loader/src/main/java/ru/noties/markwon/il/AsyncDrawableLoader.java b/library-image-loader/src/main/java/ru/noties/markwon/il/AsyncDrawableLoader.java
index c890baae..a9574d13 100644
--- a/library-image-loader/src/main/java/ru/noties/markwon/il/AsyncDrawableLoader.java
+++ b/library-image-loader/src/main/java/ru/noties/markwon/il/AsyncDrawableLoader.java
@@ -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 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;
+ }
+ }
}
diff --git a/library/build.gradle b/library/build.gradle
index 043d931e..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 'ru.noties:debug:3.0.0@jar'
}
if (project.hasProperty('release')) {
diff --git a/library/src/main/java/ru/noties/markwon/UrlProcessorAndroidAssets.java b/library/src/main/java/ru/noties/markwon/UrlProcessorAndroidAssets.java
new file mode 100644
index 00000000..82faf4e2
--- /dev/null
+++ b/library/src/main/java/ru/noties/markwon/UrlProcessorAndroidAssets.java
@@ -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;
+ }
+}
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 8ac89cb0..757f735f 100644
--- a/library/src/main/java/ru/noties/markwon/renderer/SpannableMarkdownVisitor.java
+++ b/library/src/main/java/ru/noties/markwon/renderer/SpannableMarkdownVisitor.java
@@ -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,