From 453880bd62315a66f88e56e95866f40522f43183 Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Thu, 23 May 2019 14:54:30 +0300 Subject: [PATCH 01/42] AsyncDrawableLoader improvements (multiple images with the same source) --- gradle.properties | 2 +- .../noties/markwon/image/AsyncDrawable.java | 45 +++- .../markwon/image/AsyncDrawableLoader.java | 32 ++- .../image/AsyncDrawableLoaderImpl.java | 200 +++++++++++++++--- .../image/AsyncDrawableLoaderNoOp.java | 4 +- 5 files changed, 246 insertions(+), 37 deletions(-) diff --git a/gradle.properties b/gradle.properties index cb90cb8f..abdc2b60 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,7 +6,7 @@ org.gradle.configureondemand=true android.enableBuildCache=true android.buildCacheDir=build/pre-dex-cache -VERSION_NAME=3.0.1 +VERSION_NAME=3.1.0-SNAPSHOT GROUP=ru.noties.markwon POM_DESCRIPTION=Markwon markdown for Android diff --git a/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawable.java b/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawable.java index 25cf6363..5db212fd 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawable.java +++ b/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawable.java @@ -32,7 +32,7 @@ public class AsyncDrawable extends Drawable { public AsyncDrawable( @NonNull String destination, @NonNull AsyncDrawableLoader loader, - @Nullable ImageSizeResolver imageSizeResolver, + @NonNull ImageSizeResolver imageSizeResolver, @Nullable ImageSize imageSize ) { this.destination = destination; @@ -51,6 +51,45 @@ public class AsyncDrawable extends Drawable { return destination; } + /** + * @since 3.1.0-SNAPSHOT + */ + @Nullable + public ImageSize getImageSize() { + return imageSize; + } + + /** + * @since 3.1.0-SNAPSHOT + */ + @NonNull + public ImageSizeResolver getImageSizeResolver() { + return imageSizeResolver; + } + + /** + * @since 3.1.0-SNAPSHOT + */ + public boolean hasKnownDimentions() { + return canvasWidth > 0; + } + + /** + * @see #hasKnownDimentions() + * @since 3.1.0-SNAPSHOT + */ + public int getLastKnownCanvasWidth() { + return canvasWidth; + } + + /** + * @see #hasKnownDimentions() + * @since 3.1.0-SNAPSHOT + */ + public float getLastKnowTextSize() { + return textSize; + } + public Drawable getResult() { return result; } @@ -80,7 +119,7 @@ public class AsyncDrawable extends Drawable { result.setCallback(callback); } - loader.load(destination, this); + loader.load(this); } else { if (result != null) { @@ -91,7 +130,7 @@ public class AsyncDrawable extends Drawable { ((Animatable) result).stop(); } } - loader.cancel(destination); + loader.cancel(this); } } diff --git a/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableLoader.java b/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableLoader.java index 8b76acc5..3eba33ca 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableLoader.java +++ b/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableLoader.java @@ -3,6 +3,7 @@ package ru.noties.markwon.image; import android.graphics.drawable.Drawable; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.util.Log; import java.util.Collection; import java.util.HashMap; @@ -36,10 +37,37 @@ public abstract class AsyncDrawableLoader { return new AsyncDrawableLoaderNoOp(); } + /** + * @since 3.1.0-SNAPSHOT + */ + public abstract void load(@NonNull AsyncDrawable drawable); - public abstract void load(@NonNull String destination, @NonNull AsyncDrawable drawable); + /** + * @since 3.1.0-SNAPSHOT + */ + public abstract void cancel(@NonNull AsyncDrawable drawable); - public abstract void cancel(@NonNull String destination); + /** + * @see #load(AsyncDrawable) + * @deprecated 3.1.0-SNAPSHOT + */ + @Deprecated + public void load(@NonNull String destination, @NonNull AsyncDrawable drawable) { + load(drawable); + } + + /** + * Method is deprecated because cancellation won\'t work for markdown input + * with multiple images with the same source + * + * @deprecated 3.1.0-SNAPSHOT + */ + @Deprecated + public void cancel(@NonNull String destination) { + Log.e("MARKWON-IL", "Image loading cancellation must be triggered " + + "by AsyncDrawable, please use #cancel(AsyncDrawable) method instead. " + + "No op, nothing is cancelled for destination: " + destination); + } @Nullable public abstract Drawable placeholder(); diff --git a/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderImpl.java b/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderImpl.java index fd7c3ad1..711508c2 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderImpl.java +++ b/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderImpl.java @@ -11,6 +11,7 @@ import java.io.IOException; import java.io.InputStream; import java.lang.ref.WeakReference; import java.util.HashMap; +import java.util.Iterator; import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; @@ -26,7 +27,9 @@ class AsyncDrawableLoaderImpl extends AsyncDrawableLoader { private final Handler mainThread; - private final Map> requests = new HashMap<>(2); + // @since 3.1.0-SNAPSHOT use a hash-map with a weak AsyncDrawable as key for multiple requests + // for the same destination + private final Map, Future> requests = new HashMap<>(2); AsyncDrawableLoaderImpl(@NonNull Builder builder) { this.executorService = builder.executorService; @@ -39,19 +42,139 @@ class AsyncDrawableLoaderImpl extends AsyncDrawableLoader { } @Override - public void load(@NonNull String destination, @NonNull AsyncDrawable drawable) { - // if drawable is not a link -> show loading placeholder... - requests.put(destination, execute(destination, drawable)); + public void load(@NonNull final AsyncDrawable drawable) { + + // primitive synchronization via main-thread + if (!isMainThread()) { + mainThread.post(new Runnable() { + @Override + public void run() { + load(drawable); + } + }); + return; + } + + // okay, if by some chance requested drawable already has a future associated -> no-op + // as AsyncDrawable cannot change `destination` (immutable field) + // @since 3.1.0-SNAPSHOT + if (hasTaskAssociated(drawable)) { + return; + } + + final WeakReference reference = new WeakReference<>(drawable); + requests.put(reference, execute(drawable.getDestination(), reference)); } @Override - public void cancel(@NonNull String destination) { - final Future request = requests.remove(destination); - if (request != null) { - request.cancel(true); + public void cancel(@NonNull final AsyncDrawable drawable) { + + if (!isMainThread()) { + mainThread.post(new Runnable() { + @Override + public void run() { + cancel(drawable); + } + }); + return; + } + + final Iterator, Future>> iterator = + requests.entrySet().iterator(); + + AsyncDrawable key; + Map.Entry, Future> entry; + + while (iterator.hasNext()) { + + entry = iterator.next(); + key = entry.getKey().get(); + + // if key is null or it contains requested AsyncDrawable -> cancel + if (shouldCleanUp(key) || key == drawable) { + entry.getValue().cancel(true); + iterator.remove(); + } } } + private boolean hasTaskAssociated(@NonNull AsyncDrawable drawable) { + + final Iterator, Future>> iterator = + requests.entrySet().iterator(); + + boolean result = false; + + AsyncDrawable key; + Map.Entry, Future> entry; + + while (iterator.hasNext()) { + + entry = iterator.next(); + key = entry.getKey().get(); + + // clean-up + if (shouldCleanUp(key)) { + entry.getValue().cancel(true); + iterator.remove(); + } else if (key == drawable) { + result = true; + // do not break, let iteration continue to possibly clean-up the rest references + } + } + + return result; + } + + private void cleanUp() { + + final Iterator, Future>> iterator = + requests.entrySet().iterator(); + + AsyncDrawable key; + Map.Entry, Future> entry; + + while (iterator.hasNext()) { + + entry = iterator.next(); + key = entry.getKey().get(); + + // clean-up of already referenced or detached drawables + if (shouldCleanUp(key)) { + entry.getValue().cancel(true); + iterator.remove(); + } + } + } + +// @Override +// public void load(@NonNull String destination, @NonNull AsyncDrawable drawable) { +// +// // todo: we cannot reliably identify request by the destination, as if +// // markdown input has multiple images with the same destination as source +// // we will be tracking only one of them (the one appears the last). We should +// // move to AsyncDrawable based identification. This method also _maybe_ +// // should include the ImageSize (comment @since 3.1.0-SNAPSHOT) +// +// requests.put(destination, execute(destination, drawable)); +// } +// +// @Override +// public void cancel(@NonNull String destination) { +// +// // todo: as we are moving away from a single request for a destination, +// // we should re-evaluate this cancellation logic, as if there are multiple images +// // in markdown input all of them will be cancelled (won't delivered), even if +// // only a single drawable is detached. Cancellation must also take +// // the AsyncDrawable argument (comment @since 3.1.0-SNAPSHOT) +// +// // +// final Future request = requests.remove(destination); +// if (request != null) { +// request.cancel(true); +// } +// } + @Nullable @Override public Drawable placeholder() { @@ -60,12 +183,7 @@ class AsyncDrawableLoaderImpl extends AsyncDrawableLoader { : null; } - private Future execute(@NonNull final String destination, @NonNull AsyncDrawable drawable) { - - final WeakReference reference = new WeakReference(drawable); - - // todo: should we cancel pending request for the same destination? - // we _could_ but there is possibility that one resource is request in multiple places + private Future execute(@NonNull final String destination, @NonNull final WeakReference reference) { // todo: error handing (simply applying errorDrawable is not a good solution // as reason for an error is unclear (no scheme handler, no input data, error decoding, etc) @@ -125,24 +243,48 @@ class AsyncDrawableLoaderImpl extends AsyncDrawableLoader { : null; } - if (result != null) { - final Drawable out = result; - mainThread.post(new Runnable() { - @Override - public void run() { - final boolean canDeliver = requests.remove(destination) != null; - if (canDeliver) { - final AsyncDrawable asyncDrawable = reference.get(); - if (asyncDrawable != null && asyncDrawable.isAttached()) { - asyncDrawable.setResult(out); - } + final Drawable out = result; + + mainThread.post(new Runnable() { + @Override + public void run() { + + if (out != null) { + + // this doesn't work with markdown input with multiple images with the + // same source (comment @since 3.1.0-SNAPSHOT) +// final boolean canDeliver = requests.remove(destination) != null; +// if (canDeliver) { +// final AsyncDrawable asyncDrawable = reference.get(); +// if (asyncDrawable != null && asyncDrawable.isAttached()) { +// asyncDrawable.setResult(out); +// } +// } + + // todo: AsyncDrawable cannot change destination, so if it's + // attached and not garbage-collected, we can deliver the result. + // Note that there is no cache, so attach/detach of drawables + // will always request a new entry.. (comment @since 3.1.0-SNAPSHOT) + final AsyncDrawable asyncDrawable = reference.get(); + if (asyncDrawable != null && asyncDrawable.isAttached()) { + asyncDrawable.setResult(out); } } - }); - } else { - requests.remove(destination); - } + + requests.remove(reference); + cleanUp(); + } + }); } }); } + + private static boolean shouldCleanUp(@Nullable AsyncDrawable drawable) { + return drawable == null || !drawable.isAttached(); + } + + @SuppressWarnings("BooleanMethodIsAlwaysInverted") + private static boolean isMainThread() { + return Looper.myLooper() == Looper.getMainLooper(); + } } diff --git a/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderNoOp.java b/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderNoOp.java index 74520fb2..330abe94 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderNoOp.java +++ b/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderNoOp.java @@ -6,12 +6,12 @@ import android.support.annotation.Nullable; class AsyncDrawableLoaderNoOp extends AsyncDrawableLoader { @Override - public void load(@NonNull String destination, @NonNull AsyncDrawable drawable) { + public void load(@NonNull AsyncDrawable drawable) { } @Override - public void cancel(@NonNull String destination) { + public void cancel(@NonNull AsyncDrawable drawable) { } From 661f72da0f93579bcfb8d490a267b83d0f461a90 Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Tue, 28 May 2019 16:15:25 +0300 Subject: [PATCH 02/42] Moving image loading functionality to standalone module --- .../noties/markwon/AbstractMarkwonPlugin.java | 17 +- .../main/java/ru/noties/markwon/Markwon.java | 15 +- .../ru/noties/markwon/MarkwonBuilderImpl.java | 162 +++++----- .../noties/markwon/MarkwonConfiguration.java | 16 +- .../java/ru/noties/markwon/MarkwonPlugin.java | 47 +-- .../ru/noties/markwon/core/CorePlugin.java | 6 - .../markwon/image/AsyncDrawableLoader.java | 135 -------- .../ru/noties/markwon/image/ImageItem.java | 63 +++- .../ru/noties/markwon/priority/Priority.java | 1 + markwon-image/build.gradle | 27 ++ markwon-image/gradle.properties | 4 + markwon-image/src/main/AndroidManifest.xml | 1 + .../image/AsyncDrawableLoaderBuilder.java | 110 +++++++ .../image/AsyncDrawableLoaderImpl.java | 290 ++++++++++++++++++ .../ru/noties/markwon/image/ImageItem.java | 154 ++++++++++ .../ru/noties/markwon/image/ImagesPlugin.java | 135 ++++++++ .../ru/noties/markwon/image/MediaDecoder.java | 29 ++ .../noties/markwon/image/SchemeHandler.java | 24 ++ .../ru/noties/markwon/image/data/DataUri.java | 60 ++++ .../markwon/image/data/DataUriDecoder.java | 39 +++ .../markwon/image/data/DataUriParser.java | 79 +++++ .../image/data/DataUriSchemeHandler.java | 64 ++++ .../markwon/image/file/FileSchemeHandler.java | 114 +++++++ .../markwon/image/gif/GifMediaDecoder.java | 77 +++++ .../image/network/NetworkSchemeHandler.java | 73 +++++ .../network/OkHttpNetworkSchemeHandler.java | 75 +++++ .../markwon/image/svg/SvgMediaDecoder.java | 74 +++++ settings.gradle | 1 + 28 files changed, 1637 insertions(+), 255 deletions(-) create mode 100644 markwon-image/build.gradle create mode 100644 markwon-image/gradle.properties create mode 100644 markwon-image/src/main/AndroidManifest.xml create mode 100644 markwon-image/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderBuilder.java create mode 100644 markwon-image/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderImpl.java create mode 100644 markwon-image/src/main/java/ru/noties/markwon/image/ImageItem.java create mode 100644 markwon-image/src/main/java/ru/noties/markwon/image/ImagesPlugin.java create mode 100644 markwon-image/src/main/java/ru/noties/markwon/image/MediaDecoder.java create mode 100644 markwon-image/src/main/java/ru/noties/markwon/image/SchemeHandler.java create mode 100644 markwon-image/src/main/java/ru/noties/markwon/image/data/DataUri.java create mode 100644 markwon-image/src/main/java/ru/noties/markwon/image/data/DataUriDecoder.java create mode 100644 markwon-image/src/main/java/ru/noties/markwon/image/data/DataUriParser.java create mode 100644 markwon-image/src/main/java/ru/noties/markwon/image/data/DataUriSchemeHandler.java create mode 100644 markwon-image/src/main/java/ru/noties/markwon/image/file/FileSchemeHandler.java create mode 100644 markwon-image/src/main/java/ru/noties/markwon/image/gif/GifMediaDecoder.java create mode 100644 markwon-image/src/main/java/ru/noties/markwon/image/network/NetworkSchemeHandler.java create mode 100644 markwon-image/src/main/java/ru/noties/markwon/image/network/OkHttpNetworkSchemeHandler.java create mode 100644 markwon-image/src/main/java/ru/noties/markwon/image/svg/SvgMediaDecoder.java diff --git a/markwon-core/src/main/java/ru/noties/markwon/AbstractMarkwonPlugin.java b/markwon-core/src/main/java/ru/noties/markwon/AbstractMarkwonPlugin.java index 5492d4d0..3bf54029 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/AbstractMarkwonPlugin.java +++ b/markwon-core/src/main/java/ru/noties/markwon/AbstractMarkwonPlugin.java @@ -22,6 +22,11 @@ import ru.noties.markwon.priority.Priority; */ public abstract class AbstractMarkwonPlugin implements MarkwonPlugin { + @Override + public void configure(@NonNull Registry registry) { + + } + @Override public void configureParser(@NonNull Parser.Builder builder) { @@ -32,11 +37,6 @@ public abstract class AbstractMarkwonPlugin implements MarkwonPlugin { } - @Override - public void configureImages(@NonNull AsyncDrawableLoader.Builder builder) { - - } - @Override public void configureConfiguration(@NonNull MarkwonConfiguration.Builder builder) { @@ -57,13 +57,6 @@ public abstract class AbstractMarkwonPlugin implements MarkwonPlugin { } - @NonNull - @Override - public Priority priority() { - // by default all come after CorePlugin - return Priority.after(CorePlugin.class); - } - @NonNull @Override public String processMarkdown(@NonNull String markdown) { diff --git a/markwon-core/src/main/java/ru/noties/markwon/Markwon.java b/markwon-core/src/main/java/ru/noties/markwon/Markwon.java index 0ac110ff..17f4af24 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/Markwon.java +++ b/markwon-core/src/main/java/ru/noties/markwon/Markwon.java @@ -37,13 +37,26 @@ public abstract class Markwon { } /** - * Factory method to obtain an instance of {@link Builder}. + * Factory method to obtain an instance of {@link Builder} with {@link CorePlugin} added. * * @see Builder + * @see #builderNoCore(Context) * @since 3.0.0 */ @NonNull public static Builder builder(@NonNull Context context) { + return new MarkwonBuilderImpl(context) + // @since 4.0.0-SNAPSHOT add CorePlugin + .usePlugin(CorePlugin.create()); + } + + /** + * Factory method to obtain an instance of {@link Builder} without {@link CorePlugin}. + * + * @since 4.0.0-SNAPSHOT + */ + @NonNull + public static Builder builderNoCore(@NonNull Context context) { return new MarkwonBuilderImpl(context); } diff --git a/markwon-core/src/main/java/ru/noties/markwon/MarkwonBuilderImpl.java b/markwon-core/src/main/java/ru/noties/markwon/MarkwonBuilderImpl.java index a390c46e..b650ff1b 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/MarkwonBuilderImpl.java +++ b/markwon-core/src/main/java/ru/noties/markwon/MarkwonBuilderImpl.java @@ -2,6 +2,7 @@ package ru.noties.markwon; import android.content.Context; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.support.annotation.VisibleForTesting; import android.widget.TextView; @@ -9,19 +10,17 @@ import org.commonmark.parser.Parser; import java.util.ArrayList; import java.util.Collections; +import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Set; -import ru.noties.markwon.core.CorePlugin; import ru.noties.markwon.core.MarkwonTheme; import ru.noties.markwon.html.MarkwonHtmlRenderer; -import ru.noties.markwon.image.AsyncDrawableLoader; -import ru.noties.markwon.priority.PriorityProcessor; /** * @since 3.0.0 */ -@SuppressWarnings("WeakerAccess") class MarkwonBuilderImpl implements Markwon.Builder { private final Context context; @@ -30,8 +29,6 @@ class MarkwonBuilderImpl implements Markwon.Builder { private TextView.BufferType bufferType = TextView.BufferType.SPANNABLE; - private PriorityProcessor priorityProcessor; - MarkwonBuilderImpl(@NonNull Context context) { this.context = context; } @@ -69,13 +66,6 @@ class MarkwonBuilderImpl implements Markwon.Builder { return this; } - @SuppressWarnings("UnusedReturnValue") - @NonNull - public MarkwonBuilderImpl priorityProcessor(@NonNull PriorityProcessor priorityProcessor) { - this.priorityProcessor = priorityProcessor; - return this; - } - @NonNull @Override public Markwon build() { @@ -85,21 +75,12 @@ class MarkwonBuilderImpl implements Markwon.Builder { "method to add them"); } - // this class will sort plugins to match a priority/dependency graph that we have - PriorityProcessor priorityProcessor = this.priorityProcessor; - if (priorityProcessor == null) { - // strictly speaking we do not need updating this field - // as we are not building this class to be reused between multiple `build` calls - priorityProcessor = this.priorityProcessor = PriorityProcessor.create(); - } - // please note that this method must not modify supplied collection // if nothing should be done -> the same collection can be returned - final List plugins = preparePlugins(priorityProcessor, this.plugins); + final List plugins = preparePlugins(this.plugins); final Parser.Builder parserBuilder = new Parser.Builder(); final MarkwonTheme.Builder themeBuilder = MarkwonTheme.builderWithDefaults(context); - final AsyncDrawableLoader.Builder asyncDrawableLoaderBuilder = new AsyncDrawableLoader.Builder(); final MarkwonConfiguration.Builder configurationBuilder = new MarkwonConfiguration.Builder(); final MarkwonVisitor.Builder visitorBuilder = new MarkwonVisitorImpl.BuilderImpl(); final MarkwonSpansFactory.Builder spanFactoryBuilder = new MarkwonSpansFactoryImpl.BuilderImpl(); @@ -108,7 +89,6 @@ class MarkwonBuilderImpl implements Markwon.Builder { for (MarkwonPlugin plugin : plugins) { plugin.configureParser(parserBuilder); plugin.configureTheme(themeBuilder); - plugin.configureImages(asyncDrawableLoaderBuilder); plugin.configureConfiguration(configurationBuilder); plugin.configureVisitor(visitorBuilder); plugin.configureSpansFactory(spanFactoryBuilder); @@ -117,7 +97,6 @@ class MarkwonBuilderImpl implements Markwon.Builder { final MarkwonConfiguration configuration = configurationBuilder.build( themeBuilder.build(), - asyncDrawableLoaderBuilder.build(), htmlRendererBuilder.build(), spanFactoryBuilder.build()); @@ -133,62 +112,107 @@ class MarkwonBuilderImpl implements Markwon.Builder { @VisibleForTesting @NonNull - static List preparePlugins( - @NonNull PriorityProcessor priorityProcessor, - @NonNull List plugins) { - - // with this method we will ensure that CorePlugin is added IF and ONLY IF - // there are plugins that depend on it. If CorePlugin is added, or there are - // no plugins that require it, CorePlugin won't be added - final List out = ensureImplicitCoreIfHasDependents(plugins); - - return priorityProcessor.process(out); + static List preparePlugins(@NonNull List plugins) { + return new RegistryImpl(plugins).process(); } - // this method will _implicitly_ add CorePlugin if there is at least one plugin - // that depends on CorePlugin - @VisibleForTesting - @NonNull - static List ensureImplicitCoreIfHasDependents(@NonNull List plugins) { - // loop over plugins -> if CorePlugin is found -> break; - // iterate over all plugins and check if CorePlugin is requested + // @since 4.0.0-SNAPSHOT + private static class RegistryImpl implements MarkwonPlugin.Registry { - boolean hasCore = false; - boolean hasCoreDependents = false; + private final List origin; + private final List plugins; + private final Set pending; - for (MarkwonPlugin plugin : plugins) { + RegistryImpl(@NonNull List origin) { + this.origin = origin; + this.plugins = new ArrayList<>(origin.size()); + this.pending = new HashSet<>(3); + } - // here we do not check for exact match (a user could've subclasses CorePlugin - // and supplied it. In this case we DO NOT implicitly add CorePlugin - // - // if core is present already we do not need to iterate anymore -> as nothing - // will be changed (and we actually do not care if there are any dependents of Core - // as it's present anyway) - if (CorePlugin.class.isAssignableFrom(plugin.getClass())) { - hasCore = true; - break; + @NonNull + @Override + public

P require(@NonNull Class

plugin) { + return get(plugin); + } + + @Override + public

void require( + @NonNull Class

plugin, + @NonNull MarkwonPlugin.Action action) { + action.apply(get(plugin)); + } + + @NonNull + List process() { + for (MarkwonPlugin plugin : origin) { + configure(plugin); } + return plugins; + } - // if plugin has CorePlugin in dependencies -> mark for addition - if (!hasCoreDependents) { - // here we check for direct CorePlugin, if it's not CorePlugin (exact, not a subclass - // or something -> ignore) - if (plugin.priority().after().contains(CorePlugin.class)) { - hasCoreDependents = true; + private void configure(@NonNull MarkwonPlugin plugin) { + + // important -> check if it's in plugins + // if it is -> no need to configure (already configured) + + if (!plugins.contains(plugin)) { + + if (pending.contains(plugin)) { + throw new IllegalStateException("Cyclic dependency chain found: " + pending); + } + + // start tracking plugins that are pending for configuration + pending.add(plugin); + + plugin.configure(this); + + // stop pending tracking + pending.remove(plugin); + + // check again if it's included (a child might've configured it already) + // add to out-collection if not already present + // this is a bit different from `find` method as it does check for exact instance + // and not a sub-type + if (!plugins.contains(plugin)) { + plugins.add(plugin); } } } - // important thing here is to check if corePlugin is added - // add it _only_ if it's not present - if (hasCoreDependents && !hasCore) { - final List out = new ArrayList<>(plugins.size() + 1); - // add default instance of CorePlugin - out.add(CorePlugin.create()); - out.addAll(plugins); - return out; + @NonNull + private

P get(@NonNull Class

type) { + + // check if present already in plugins + // find in origin, if not found -> throw, else add to out-plugins + + P plugin = find(plugins, type); + + if (plugin == null) { + + plugin = find(origin, type); + + if (plugin == null) { + throw new IllegalStateException("Requested plugin is not added: " + + "" + type.getName() + ", plugins: " + origin); + } + + configure(plugin); + } + + return plugin; } - return plugins; + @Nullable + private static

P find( + @NonNull List plugins, + @NonNull Class

type) { + for (MarkwonPlugin plugin : plugins) { + if (type.isAssignableFrom(plugin.getClass())) { + //noinspection unchecked + return (P) plugin; + } + } + return null; + } } } diff --git a/markwon-core/src/main/java/ru/noties/markwon/MarkwonConfiguration.java b/markwon-core/src/main/java/ru/noties/markwon/MarkwonConfiguration.java index af481ee8..af65fdb4 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/MarkwonConfiguration.java +++ b/markwon-core/src/main/java/ru/noties/markwon/MarkwonConfiguration.java @@ -113,6 +113,15 @@ public class MarkwonConfiguration { Builder() { } + /** + * @since 4.0.0-SNAPSHOT + */ + @NonNull + public Builder asyncDrawableLoader(@NonNull AsyncDrawableLoader asyncDrawableLoader) { + this.asyncDrawableLoader = asyncDrawableLoader; + return this; + } + @NonNull public Builder syntaxHighlight(@NonNull SyntaxHighlight syntaxHighlight) { this.syntaxHighlight = syntaxHighlight; @@ -149,15 +158,18 @@ public class MarkwonConfiguration { @NonNull public MarkwonConfiguration build( @NonNull MarkwonTheme theme, - @NonNull AsyncDrawableLoader asyncDrawableLoader, @NonNull MarkwonHtmlRenderer htmlRenderer, @NonNull MarkwonSpansFactory spansFactory) { this.theme = theme; - this.asyncDrawableLoader = asyncDrawableLoader; this.htmlRenderer = htmlRenderer; this.spansFactory = spansFactory; + // @since 4.0.0-SNAPSHOT + if (asyncDrawableLoader == null) { + asyncDrawableLoader = AsyncDrawableLoader.noOp(); + } + if (syntaxHighlight == null) { syntaxHighlight = new SyntaxHighlightNoOp(); } diff --git a/markwon-core/src/main/java/ru/noties/markwon/MarkwonPlugin.java b/markwon-core/src/main/java/ru/noties/markwon/MarkwonPlugin.java index 0804848b..8bc4dc8d 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/MarkwonPlugin.java +++ b/markwon-core/src/main/java/ru/noties/markwon/MarkwonPlugin.java @@ -9,10 +9,6 @@ import org.commonmark.parser.Parser; import ru.noties.markwon.core.MarkwonTheme; import ru.noties.markwon.html.MarkwonHtmlRenderer; -import ru.noties.markwon.image.AsyncDrawableLoader; -import ru.noties.markwon.image.MediaDecoder; -import ru.noties.markwon.image.SchemeHandler; -import ru.noties.markwon.priority.Priority; /** * Class represents a plugin (extension) to Markwon to configure how parsing and rendering @@ -25,6 +21,35 @@ import ru.noties.markwon.priority.Priority; */ public interface MarkwonPlugin { + /** + * @see Registry#require(Class, Action) + * @since 4.0.0-SNAPSHOT + */ + interface Action

{ + void apply(@NonNull P p); + } + + /** + * @see #configure(Registry) + * @since 4.0.0-SNAPSHOT + */ + interface Registry { + + @NonNull +

P require(@NonNull Class

plugin); + +

void require( + @NonNull Class

plugin, + @NonNull Action action); + } + + /** + * This method will be called before any other during {@link Markwon} instance construction. + * + * @since 4.0.0-SNAPSHOT + */ + void configure(@NonNull Registry registry); + /** * Method to configure org.commonmark.parser.Parser (for example register custom * extension, etc). @@ -39,17 +64,6 @@ public interface MarkwonPlugin { */ void configureTheme(@NonNull MarkwonTheme.Builder builder); - /** - * Configure image loading functionality. For example add new content-types - * {@link AsyncDrawableLoader.Builder#addMediaDecoder(String, MediaDecoder)}, a transport - * layer (network, file, etc) {@link AsyncDrawableLoader.Builder#addSchemeHandler(String, SchemeHandler)} - * or modify existing properties. - * - * @see AsyncDrawableLoader - * @see AsyncDrawableLoader.Builder - */ - void configureImages(@NonNull AsyncDrawableLoader.Builder builder); - /** * Configure {@link MarkwonConfiguration} * @@ -82,9 +96,6 @@ public interface MarkwonPlugin { */ void configureHtmlRenderer(@NonNull MarkwonHtmlRenderer.Builder builder); - @NonNull - Priority priority(); - /** * Process input markdown and return new string to be used in parsing stage further. * Can be described as pre-processing of markdown String. diff --git a/markwon-core/src/main/java/ru/noties/markwon/core/CorePlugin.java b/markwon-core/src/main/java/ru/noties/markwon/core/CorePlugin.java index 77fa3653..39436839 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/core/CorePlugin.java +++ b/markwon-core/src/main/java/ru/noties/markwon/core/CorePlugin.java @@ -95,12 +95,6 @@ public class CorePlugin extends AbstractMarkwonPlugin { .setFactory(ThematicBreak.class, new ThematicBreakSpanFactory()); } - @NonNull - @Override - public Priority priority() { - return Priority.none(); - } - @Override public void beforeSetText(@NonNull TextView textView, @NonNull Spanned markdown) { OrderedListItemSpan.measure(textView, markdown); diff --git a/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableLoader.java b/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableLoader.java index 3eba33ca..7e297bf3 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableLoader.java +++ b/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableLoader.java @@ -13,22 +13,6 @@ import java.util.concurrent.Executors; public abstract class AsyncDrawableLoader { - /** - * @since 3.0.0 - */ - public interface DrawableProvider { - @Nullable - Drawable provide(); - } - - /** - * @since 3.0.0 - */ - @NonNull - public static Builder builder() { - return new Builder(); - } - /** * @since 3.0.0 */ @@ -71,123 +55,4 @@ public abstract class AsyncDrawableLoader { @Nullable public abstract Drawable placeholder(); - - public static class Builder { - - ExecutorService executorService; - final Map schemeHandlers = new HashMap<>(3); - final Map mediaDecoders = new HashMap<>(3); - MediaDecoder defaultMediaDecoder; - DrawableProvider placeholderDrawableProvider; - DrawableProvider errorDrawableProvider; - - AsyncDrawableLoader implementation; - - @NonNull - public Builder executorService(@NonNull ExecutorService executorService) { - this.executorService = executorService; - return this; - } - - @NonNull - public Builder addSchemeHandler(@NonNull String scheme, @NonNull SchemeHandler schemeHandler) { - schemeHandlers.put(scheme, schemeHandler); - return this; - } - - @NonNull - public Builder addSchemeHandler(@NonNull Collection schemes, @NonNull SchemeHandler schemeHandler) { - for (String scheme : schemes) { - schemeHandlers.put(scheme, schemeHandler); - } - return this; - } - - @NonNull - public Builder addMediaDecoder(@NonNull String contentType, @NonNull MediaDecoder mediaDecoder) { - mediaDecoders.put(contentType, mediaDecoder); - return this; - } - - @NonNull - public Builder addMediaDecoder(@NonNull Collection contentTypes, @NonNull MediaDecoder mediaDecoder) { - for (String contentType : contentTypes) { - mediaDecoders.put(contentType, mediaDecoder); - } - return this; - } - - @NonNull - public Builder removeSchemeHandler(@NonNull String scheme) { - schemeHandlers.remove(scheme); - return this; - } - - @NonNull - public Builder removeMediaDecoder(@NonNull String contentType) { - mediaDecoders.remove(contentType); - return this; - } - - @NonNull - public Builder defaultMediaDecoder(@Nullable MediaDecoder mediaDecoder) { - this.defaultMediaDecoder = mediaDecoder; - return this; - } - - /** - * @since 3.0.0 - */ - @NonNull - public Builder placeholderDrawableProvider(@NonNull DrawableProvider placeholderDrawableProvider) { - this.placeholderDrawableProvider = placeholderDrawableProvider; - return this; - } - - /** - * @since 3.0.0 - */ - @NonNull - public Builder errorDrawableProvider(@NonNull DrawableProvider errorDrawableProvider) { - this.errorDrawableProvider = errorDrawableProvider; - return this; - } - - /** - * Please note that if implementation is supplied, all configuration properties - * (scheme-handlers, media-decoders, placeholder, etc) of this builder instance - * will be ignored. - * - * @param implementation {@link AsyncDrawableLoader} implementation to be used. - * @since 3.0.1 - */ - @NonNull - public Builder implementation(@NonNull AsyncDrawableLoader implementation) { - this.implementation = implementation; - return this; - } - - @NonNull - public AsyncDrawableLoader build() { - - // NB, all other configuration properties will be ignored if - // implementation is specified - if (implementation != null) { - return implementation; - } - - // if we have no schemeHandlers -> we cannot show anything - // OR if we have no media decoders - if (schemeHandlers.size() == 0 - || (mediaDecoders.size() == 0 && defaultMediaDecoder == null)) { - return new AsyncDrawableLoaderNoOp(); - } - - if (executorService == null) { - executorService = Executors.newCachedThreadPool(); - } - - return new AsyncDrawableLoaderImpl(this); - } - } } diff --git a/markwon-core/src/main/java/ru/noties/markwon/image/ImageItem.java b/markwon-core/src/main/java/ru/noties/markwon/image/ImageItem.java index 2dc4b729..a6e9f72e 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/image/ImageItem.java +++ b/markwon-core/src/main/java/ru/noties/markwon/image/ImageItem.java @@ -1,5 +1,7 @@ package ru.noties.markwon.image; +import android.graphics.drawable.Drawable; +import android.support.annotation.NonNull; import android.support.annotation.Nullable; import java.io.InputStream; @@ -7,25 +9,62 @@ import java.io.InputStream; /** * @since 2.0.0 */ -public class ImageItem { +public abstract class ImageItem { - private final String contentType; - private final InputStream inputStream; + /** + * Create an {@link ImageItem} with result, so no further decoding is required. + * + * @since 4.0.0-SNAPSHOT + */ + @NonNull + public static ImageItem withResult(@Nullable Drawable drawable) { + return new WithResult(drawable); + } - public ImageItem( + @NonNull + public static ImageItem withDecodingNeeded( @Nullable String contentType, @Nullable InputStream inputStream) { - this.contentType = contentType; - this.inputStream = inputStream; + return new WithDecodingNeeded(contentType, inputStream); } - @Nullable - public String contentType() { - return contentType; + private ImageItem() { } - @Nullable - public InputStream inputStream() { - return inputStream; + public static class WithResult extends ImageItem { + + private final Drawable result; + + WithResult(@Nullable Drawable drawable) { + result = drawable; + } + + @Nullable + public Drawable result() { + return result; + } + } + + public static class WithDecodingNeeded extends ImageItem { + + private final String contentType; + private final InputStream inputStream; + + WithDecodingNeeded( + @Nullable String contentType, + @Nullable InputStream inputStream) { + this.contentType = contentType; + this.inputStream = inputStream; + } + + @Nullable + public String contentType() { + return contentType; + } + + @Nullable + public InputStream inputStream() { + return inputStream; + } } } diff --git a/markwon-core/src/main/java/ru/noties/markwon/priority/Priority.java b/markwon-core/src/main/java/ru/noties/markwon/priority/Priority.java index 5582ff72..e10faf2a 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/priority/Priority.java +++ b/markwon-core/src/main/java/ru/noties/markwon/priority/Priority.java @@ -17,6 +17,7 @@ import ru.noties.markwon.MarkwonPlugin; * @see MarkwonPlugin#priority() * @since 3.0.0 */ +@Deprecated public abstract class Priority { @NonNull diff --git a/markwon-image/build.gradle b/markwon-image/build.gradle new file mode 100644 index 00000000..86fac312 --- /dev/null +++ b/markwon-image/build.gradle @@ -0,0 +1,27 @@ +apply plugin: 'com.android.library' + +android { + + compileSdkVersion config['compile-sdk'] + buildToolsVersion config['build-tools'] + + defaultConfig { + minSdkVersion config['min-sdk'] + targetSdkVersion config['target-sdk'] + versionCode 1 + versionName version + } +} + +dependencies { + + api project(':markwon-core') + + deps.with { + compileOnly it['android-gif'] + compileOnly it['android-svg'] + compileOnly it['okhttp'] + } +} + +registerArtifact(this) \ No newline at end of file diff --git a/markwon-image/gradle.properties b/markwon-image/gradle.properties new file mode 100644 index 00000000..a845eebf --- /dev/null +++ b/markwon-image/gradle.properties @@ -0,0 +1,4 @@ +POM_NAME=Image +POM_ARTIFACT_ID=image +POM_DESCRIPTION=Markwon image loading module (with GIF and SVG support) +POM_PACKAGING=aar \ No newline at end of file diff --git a/markwon-image/src/main/AndroidManifest.xml b/markwon-image/src/main/AndroidManifest.xml new file mode 100644 index 00000000..e8b1253d --- /dev/null +++ b/markwon-image/src/main/AndroidManifest.xml @@ -0,0 +1 @@ + diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderBuilder.java b/markwon-image/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderBuilder.java new file mode 100644 index 00000000..47c91146 --- /dev/null +++ b/markwon-image/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderBuilder.java @@ -0,0 +1,110 @@ +package ru.noties.markwon.image; + +import android.graphics.drawable.Drawable; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +public class AsyncDrawableLoaderBuilder { + + ExecutorService executorService; + final Map schemeHandlers = new HashMap<>(3); + final Map mediaDecoders = new HashMap<>(3); + MediaDecoder defaultMediaDecoder; + DrawableProvider placeholderDrawableProvider; + DrawableProvider errorDrawableProvider; + + @NonNull + public AsyncDrawableLoaderBuilder executorService(@NonNull ExecutorService executorService) { + this.executorService = executorService; + return this; + } + + @NonNull + public AsyncDrawableLoaderBuilder addSchemeHandler(@NonNull String scheme, @NonNull SchemeHandler schemeHandler) { + schemeHandlers.put(scheme, schemeHandler); + return this; + } + + @NonNull + public AsyncDrawableLoaderBuilder addSchemeHandler(@NonNull Collection schemes, @NonNull SchemeHandler schemeHandler) { + for (String scheme : schemes) { + schemeHandlers.put(scheme, schemeHandler); + } + return this; + } + + @NonNull + public AsyncDrawableLoaderBuilder addMediaDecoder(@NonNull String contentType, @NonNull MediaDecoder mediaDecoder) { + mediaDecoders.put(contentType, mediaDecoder); + return this; + } + + @NonNull + public AsyncDrawableLoaderBuilder addMediaDecoder(@NonNull Collection contentTypes, @NonNull MediaDecoder mediaDecoder) { + for (String contentType : contentTypes) { + mediaDecoders.put(contentType, mediaDecoder); + } + return this; + } + + @NonNull + public AsyncDrawableLoaderBuilder removeSchemeHandler(@NonNull String scheme) { + schemeHandlers.remove(scheme); + return this; + } + + @NonNull + public AsyncDrawableLoaderBuilder removeMediaDecoder(@NonNull String contentType) { + mediaDecoders.remove(contentType); + return this; + } + + @NonNull + public AsyncDrawableLoaderBuilder defaultMediaDecoder(@Nullable MediaDecoder mediaDecoder) { + this.defaultMediaDecoder = mediaDecoder; + return this; + } + + /** + * @since 3.0.0 + */ + @NonNull + public AsyncDrawableLoaderBuilder placeholderDrawableProvider(@NonNull DrawableProvider placeholderDrawableProvider) { + this.placeholderDrawableProvider = placeholderDrawableProvider; + return this; + } + + /** + * @since 3.0.0 + */ + @NonNull + public AsyncDrawableLoaderBuilder errorDrawableProvider(@NonNull DrawableProvider errorDrawableProvider) { + this.errorDrawableProvider = errorDrawableProvider; + return this; + } + + + @NonNull + public AsyncDrawableLoader build() { + + // if we have no schemeHandlers -> we cannot show anything + // OR if we have no media decoders + if (schemeHandlers.size() == 0 + || (mediaDecoders.size() == 0 && defaultMediaDecoder == null)) { + return new AsyncDrawableLoaderNoOp(); + } + + if (executorService == null) { + executorService = Executors.newCachedThreadPool(); + } + + return new AsyncDrawableLoaderImpl(this); + } + +} diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderImpl.java b/markwon-image/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderImpl.java new file mode 100644 index 00000000..711508c2 --- /dev/null +++ b/markwon-image/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderImpl.java @@ -0,0 +1,290 @@ +package ru.noties.markwon.image; + +import android.graphics.drawable.Drawable; +import android.net.Uri; +import android.os.Handler; +import android.os.Looper; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import java.io.IOException; +import java.io.InputStream; +import java.lang.ref.WeakReference; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; + +class AsyncDrawableLoaderImpl extends AsyncDrawableLoader { + + private final ExecutorService executorService; + private final Map schemeHandlers; + private final Map mediaDecoders; + private final MediaDecoder defaultMediaDecoder; + private final DrawableProvider placeholderDrawableProvider; + private final DrawableProvider errorDrawableProvider; + + private final Handler mainThread; + + // @since 3.1.0-SNAPSHOT use a hash-map with a weak AsyncDrawable as key for multiple requests + // for the same destination + private final Map, Future> requests = new HashMap<>(2); + + AsyncDrawableLoaderImpl(@NonNull Builder builder) { + this.executorService = builder.executorService; + this.schemeHandlers = builder.schemeHandlers; + this.mediaDecoders = builder.mediaDecoders; + this.defaultMediaDecoder = builder.defaultMediaDecoder; + this.placeholderDrawableProvider = builder.placeholderDrawableProvider; + this.errorDrawableProvider = builder.errorDrawableProvider; + this.mainThread = new Handler(Looper.getMainLooper()); + } + + @Override + public void load(@NonNull final AsyncDrawable drawable) { + + // primitive synchronization via main-thread + if (!isMainThread()) { + mainThread.post(new Runnable() { + @Override + public void run() { + load(drawable); + } + }); + return; + } + + // okay, if by some chance requested drawable already has a future associated -> no-op + // as AsyncDrawable cannot change `destination` (immutable field) + // @since 3.1.0-SNAPSHOT + if (hasTaskAssociated(drawable)) { + return; + } + + final WeakReference reference = new WeakReference<>(drawable); + requests.put(reference, execute(drawable.getDestination(), reference)); + } + + @Override + public void cancel(@NonNull final AsyncDrawable drawable) { + + if (!isMainThread()) { + mainThread.post(new Runnable() { + @Override + public void run() { + cancel(drawable); + } + }); + return; + } + + final Iterator, Future>> iterator = + requests.entrySet().iterator(); + + AsyncDrawable key; + Map.Entry, Future> entry; + + while (iterator.hasNext()) { + + entry = iterator.next(); + key = entry.getKey().get(); + + // if key is null or it contains requested AsyncDrawable -> cancel + if (shouldCleanUp(key) || key == drawable) { + entry.getValue().cancel(true); + iterator.remove(); + } + } + } + + private boolean hasTaskAssociated(@NonNull AsyncDrawable drawable) { + + final Iterator, Future>> iterator = + requests.entrySet().iterator(); + + boolean result = false; + + AsyncDrawable key; + Map.Entry, Future> entry; + + while (iterator.hasNext()) { + + entry = iterator.next(); + key = entry.getKey().get(); + + // clean-up + if (shouldCleanUp(key)) { + entry.getValue().cancel(true); + iterator.remove(); + } else if (key == drawable) { + result = true; + // do not break, let iteration continue to possibly clean-up the rest references + } + } + + return result; + } + + private void cleanUp() { + + final Iterator, Future>> iterator = + requests.entrySet().iterator(); + + AsyncDrawable key; + Map.Entry, Future> entry; + + while (iterator.hasNext()) { + + entry = iterator.next(); + key = entry.getKey().get(); + + // clean-up of already referenced or detached drawables + if (shouldCleanUp(key)) { + entry.getValue().cancel(true); + iterator.remove(); + } + } + } + +// @Override +// public void load(@NonNull String destination, @NonNull AsyncDrawable drawable) { +// +// // todo: we cannot reliably identify request by the destination, as if +// // markdown input has multiple images with the same destination as source +// // we will be tracking only one of them (the one appears the last). We should +// // move to AsyncDrawable based identification. This method also _maybe_ +// // should include the ImageSize (comment @since 3.1.0-SNAPSHOT) +// +// requests.put(destination, execute(destination, drawable)); +// } +// +// @Override +// public void cancel(@NonNull String destination) { +// +// // todo: as we are moving away from a single request for a destination, +// // we should re-evaluate this cancellation logic, as if there are multiple images +// // in markdown input all of them will be cancelled (won't delivered), even if +// // only a single drawable is detached. Cancellation must also take +// // the AsyncDrawable argument (comment @since 3.1.0-SNAPSHOT) +// +// // +// final Future request = requests.remove(destination); +// if (request != null) { +// request.cancel(true); +// } +// } + + @Nullable + @Override + public Drawable placeholder() { + return placeholderDrawableProvider != null + ? placeholderDrawableProvider.provide() + : null; + } + + private Future execute(@NonNull final String destination, @NonNull final WeakReference reference) { + + // todo: error handing (simply applying errorDrawable is not a good solution + // as reason for an error is unclear (no scheme handler, no input data, error decoding, etc) + + // todo: more efficient ImageMediaDecoder... BitmapFactory.decodeStream is a bit not optimal + // for big images for sure. We _could_ introduce internal Drawable that will check for + // image bounds (but we will need to cache inputStream in order to inspect and optimize + // input image...) + + return executorService.submit(new Runnable() { + @Override + public void run() { + + final ImageItem item; + + final Uri uri = Uri.parse(destination); + + final SchemeHandler schemeHandler = schemeHandlers.get(uri.getScheme()); + + if (schemeHandler != null) { + item = schemeHandler.handle(destination, uri); + } else { + item = null; + } + + final InputStream inputStream = item != null + ? item.inputStream() + : null; + + Drawable result = null; + + if (inputStream != null) { + try { + + MediaDecoder mediaDecoder = mediaDecoders.get(item.contentType()); + if (mediaDecoder == null) { + mediaDecoder = defaultMediaDecoder; + } + + if (mediaDecoder != null) { + result = mediaDecoder.decode(inputStream); + } + + } finally { + try { + inputStream.close(); + } catch (IOException e) { + // ignored + } + } + } + + // if result is null, we assume it's an error + if (result == null) { + result = errorDrawableProvider != null + ? errorDrawableProvider.provide() + : null; + } + + final Drawable out = result; + + mainThread.post(new Runnable() { + @Override + public void run() { + + if (out != null) { + + // this doesn't work with markdown input with multiple images with the + // same source (comment @since 3.1.0-SNAPSHOT) +// final boolean canDeliver = requests.remove(destination) != null; +// if (canDeliver) { +// final AsyncDrawable asyncDrawable = reference.get(); +// if (asyncDrawable != null && asyncDrawable.isAttached()) { +// asyncDrawable.setResult(out); +// } +// } + + // todo: AsyncDrawable cannot change destination, so if it's + // attached and not garbage-collected, we can deliver the result. + // Note that there is no cache, so attach/detach of drawables + // will always request a new entry.. (comment @since 3.1.0-SNAPSHOT) + final AsyncDrawable asyncDrawable = reference.get(); + if (asyncDrawable != null && asyncDrawable.isAttached()) { + asyncDrawable.setResult(out); + } + } + + requests.remove(reference); + cleanUp(); + } + }); + } + }); + } + + private static boolean shouldCleanUp(@Nullable AsyncDrawable drawable) { + return drawable == null || !drawable.isAttached(); + } + + @SuppressWarnings("BooleanMethodIsAlwaysInverted") + private static boolean isMainThread() { + return Looper.myLooper() == Looper.getMainLooper(); + } +} diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/ImageItem.java b/markwon-image/src/main/java/ru/noties/markwon/image/ImageItem.java new file mode 100644 index 00000000..df07e768 --- /dev/null +++ b/markwon-image/src/main/java/ru/noties/markwon/image/ImageItem.java @@ -0,0 +1,154 @@ +package ru.noties.markwon.image; + +import android.graphics.drawable.Drawable; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import java.io.InputStream; + +/** + * @since 2.0.0 + */ +public abstract class ImageItem { + + /** + * Create an {@link ImageItem} with result, so no further decoding is required. + * + * @see #withDecodingNeeded(String, InputStream) + * @see WithResult + * @since 4.0.0-SNAPSHOT + */ + @NonNull + public static ImageItem withResult(@NonNull Drawable drawable) { + return new WithResult(drawable); + } + + /** + * Create an {@link ImageItem} that requires further decoding of InputStream. + * + * @see #withResult(Drawable) + * @see WithDecodingNeeded + * @since 4.0.0-SNAPSHOT + */ + @NonNull + public static ImageItem withDecodingNeeded( + @Nullable String contentType, + @NonNull InputStream inputStream) { + return new WithDecodingNeeded(contentType, inputStream); + } + + + private ImageItem() { + } + + /** + * @since 4.0.0-SNAPSHOT + */ + public abstract boolean hasResult(); + + /** + * @since 4.0.0-SNAPSHOT + */ + public abstract boolean hasDecodingNeeded(); + + /** + * @see #hasResult() + * @since 4.0.0-SNAPSHOT + */ + @NonNull + public abstract WithResult getAsWithResult(); + + /** + * @see #hasDecodingNeeded() + * @since 4.0.0-SNAPSHOT + */ + @NonNull + public abstract WithDecodingNeeded getAsWithDecodingNeeded(); + + /** + * @since 4.0.0-SNAPSHOT + */ + public static class WithResult extends ImageItem { + + private final Drawable result; + + private WithResult(@NonNull Drawable drawable) { + result = drawable; + } + + @NonNull + public Drawable result() { + return result; + } + + @Override + public boolean hasResult() { + return true; + } + + @Override + public boolean hasDecodingNeeded() { + return false; + } + + @NonNull + @Override + public WithResult getAsWithResult() { + return this; + } + + @NonNull + @Override + public WithDecodingNeeded getAsWithDecodingNeeded() { + throw new IllegalStateException(); + } + } + + /** + * @since 4.0.0-SNAPSHOT + */ + public static class WithDecodingNeeded extends ImageItem { + + private final String contentType; + private final InputStream inputStream; + + private WithDecodingNeeded( + @Nullable String contentType, + @NonNull InputStream inputStream) { + this.contentType = contentType; + this.inputStream = inputStream; + } + + @Nullable + public String contentType() { + return contentType; + } + + @NonNull + public InputStream inputStream() { + return inputStream; + } + + @Override + public boolean hasResult() { + return false; + } + + @Override + public boolean hasDecodingNeeded() { + return true; + } + + @NonNull + @Override + public WithResult getAsWithResult() { + throw new IllegalStateException(); + } + + @NonNull + @Override + public WithDecodingNeeded getAsWithDecodingNeeded() { + return this; + } + } +} diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/ImagesPlugin.java b/markwon-image/src/main/java/ru/noties/markwon/image/ImagesPlugin.java new file mode 100644 index 00000000..3d441f7b --- /dev/null +++ b/markwon-image/src/main/java/ru/noties/markwon/image/ImagesPlugin.java @@ -0,0 +1,135 @@ +package ru.noties.markwon.image; + +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.text.Spanned; +import android.widget.TextView; + +import org.commonmark.node.Image; +import org.commonmark.node.Link; +import org.commonmark.node.Node; + +import ru.noties.markwon.AbstractMarkwonPlugin; +import ru.noties.markwon.MarkwonConfiguration; +import ru.noties.markwon.MarkwonSpansFactory; +import ru.noties.markwon.MarkwonVisitor; +import ru.noties.markwon.RenderProps; +import ru.noties.markwon.SpanFactory; + +public class ImagesPlugin extends AbstractMarkwonPlugin { + + /** + * @since 4.0.0-SNAPSHOT + */ + public interface DrawableProvider { + @Nullable + Drawable provide(); + } + + + @NonNull + public static ImagesPlugin create(@NonNull Context context) { + return new ImagesPlugin(context, false); + } + + /** + * Special scheme that is used {@code file:///android_asset/} + * + * @param context + * @return + */ + @NonNull + public static ImagesPlugin createWithAssets(@NonNull Context context) { + return new ImagesPlugin(context, true); + } + + private final Context context; + private final boolean useAssets; + + protected ImagesPlugin(Context context, boolean useAssets) { + this.context = context; + this.useAssets = useAssets; + } + + // we must expose scheme handling... so it's available during construction and via `require` + +// @Override +// public void configureImages(@NonNull AsyncDrawableLoader.Builder builder) { +// +// final FileSchemeHandler fileSchemeHandler = useAssets +// ? FileSchemeHandler.createWithAssets(context.getAssets()) +// : FileSchemeHandler.create(); +// +// builder +// .addSchemeHandler(DataUriSchemeHandler.SCHEME, DataUriSchemeHandler.create()) +// .addSchemeHandler(FileSchemeHandler.SCHEME, fileSchemeHandler) +// .addSchemeHandler( +// Arrays.asList( +// NetworkSchemeHandler.SCHEME_HTTP, +// NetworkSchemeHandler.SCHEME_HTTPS), +// NetworkSchemeHandler.create()) +// .defaultMediaDecoder(ImageMediaDecoder.create(context.getResources())); +// } + + @Override + public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) { + builder.setFactory(Image.class, new ImageSpanFactory()); + } + + @Override + public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) { + builder.on(Image.class, new MarkwonVisitor.NodeVisitor() { + @Override + public void visit(@NonNull MarkwonVisitor visitor, @NonNull Image image) { + + // if there is no image spanFactory, ignore + final SpanFactory spanFactory = visitor.configuration().spansFactory().get(Image.class); + if (spanFactory == null) { + visitor.visitChildren(image); + return; + } + + final int length = visitor.length(); + + visitor.visitChildren(image); + + // we must check if anything _was_ added, as we need at least one char to render + if (length == visitor.length()) { + visitor.builder().append('\uFFFC'); + } + + final MarkwonConfiguration configuration = visitor.configuration(); + + final Node parent = image.getParent(); + final boolean link = parent instanceof Link; + + final String destination = configuration + .urlProcessor() + .process(image.getDestination()); + + final RenderProps props = visitor.renderProps(); + + // apply image properties + // Please note that we explicitly set IMAGE_SIZE to null as we do not clear + // properties after we applied span (we could though) + ImageProps.DESTINATION.set(props, destination); + ImageProps.REPLACEMENT_TEXT_IS_LINK.set(props, link); + ImageProps.IMAGE_SIZE.set(props, null); + + visitor.setSpans(length, spanFactory.getSpans(configuration, props)); + } + }); + } + + @Override + public void beforeSetText(@NonNull TextView textView, @NonNull Spanned markdown) { + AsyncDrawableScheduler.unschedule(textView); + } + + @Override + public void afterSetText(@NonNull TextView textView) { + AsyncDrawableScheduler.schedule(textView); + } +} diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/MediaDecoder.java b/markwon-image/src/main/java/ru/noties/markwon/image/MediaDecoder.java new file mode 100644 index 00000000..ecea7a98 --- /dev/null +++ b/markwon-image/src/main/java/ru/noties/markwon/image/MediaDecoder.java @@ -0,0 +1,29 @@ +package ru.noties.markwon.image; + +import android.graphics.drawable.Drawable; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import java.io.InputStream; + +/** + * @since 3.0.0 + */ +public abstract class MediaDecoder { + + /** + * Changes since 4.0.0-SNAPSHOT: + *

    + *
  • Returns `non-null` drawable
  • + *
  • Added `contentType` method parameter
  • + *
  • Added `throws Exception` to method signature
  • + *
+ * + * @throws Exception since 4.0.0-SNAPSHOT + */ + @NonNull + public abstract Drawable decode( + @Nullable String contentType, + @NonNull InputStream inputStream + ) throws Exception; +} diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/SchemeHandler.java b/markwon-image/src/main/java/ru/noties/markwon/image/SchemeHandler.java new file mode 100644 index 00000000..2c5889ed --- /dev/null +++ b/markwon-image/src/main/java/ru/noties/markwon/image/SchemeHandler.java @@ -0,0 +1,24 @@ +package ru.noties.markwon.image; + +import android.net.Uri; +import android.support.annotation.NonNull; + +/** + * @since 3.0.0 + */ +public abstract class SchemeHandler { + + /** + * Changes since 4.0.0-SNAPSHOT: + *
    + *
  • Returns `non-null` image-item
  • + *
  • added `throws Exception` to method signature
  • + *
+ * + * @throws Exception since 4.0.0-SNAPSHOT + * @see ImageItem#withResult(android.graphics.drawable.Drawable) + * @see ImageItem#withDecodingNeeded(String, java.io.InputStream) + */ + @NonNull + public abstract ImageItem handle(@NonNull String raw, @NonNull Uri uri) throws Exception; +} diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/data/DataUri.java b/markwon-image/src/main/java/ru/noties/markwon/image/data/DataUri.java new file mode 100644 index 00000000..6e812c92 --- /dev/null +++ b/markwon-image/src/main/java/ru/noties/markwon/image/data/DataUri.java @@ -0,0 +1,60 @@ +package ru.noties.markwon.image.data; + +import android.support.annotation.Nullable; + +public class DataUri { + + private final String contentType; + private final boolean base64; + private final String data; + + public DataUri(@Nullable String contentType, boolean base64, @Nullable String data) { + this.contentType = contentType; + this.base64 = base64; + this.data = data; + } + + @Nullable + public String contentType() { + return contentType; + } + + public boolean base64() { + return base64; + } + + @Nullable + public String data() { + return data; + } + + @Override + public String toString() { + return "DataUri{" + + "contentType='" + contentType + '\'' + + ", base64=" + base64 + + ", data='" + data + '\'' + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + DataUri dataUri = (DataUri) o; + + if (base64 != dataUri.base64) return false; + if (contentType != null ? !contentType.equals(dataUri.contentType) : dataUri.contentType != null) + return false; + return data != null ? data.equals(dataUri.data) : dataUri.data == null; + } + + @Override + public int hashCode() { + int result = contentType != null ? contentType.hashCode() : 0; + result = 31 * result + (base64 ? 1 : 0); + result = 31 * result + (data != null ? data.hashCode() : 0); + return result; + } +} diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/data/DataUriDecoder.java b/markwon-image/src/main/java/ru/noties/markwon/image/data/DataUriDecoder.java new file mode 100644 index 00000000..929ff47d --- /dev/null +++ b/markwon-image/src/main/java/ru/noties/markwon/image/data/DataUriDecoder.java @@ -0,0 +1,39 @@ +package ru.noties.markwon.image.data; + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.text.TextUtils; +import android.util.Base64; + +public abstract class DataUriDecoder { + + @Nullable + public abstract byte[] decode(@NonNull DataUri dataUri) throws Throwable; + + @NonNull + public static DataUriDecoder create() { + return new Impl(); + } + + static class Impl extends DataUriDecoder { + + private static final String CHARSET = "UTF-8"; + + @Nullable + @Override + public byte[] decode(@NonNull DataUri dataUri) throws Throwable { + + final String data = dataUri.data(); + + if (!TextUtils.isEmpty(data)) { + if (dataUri.base64()) { + return Base64.decode(data.getBytes(CHARSET), Base64.DEFAULT); + } else { + return data.getBytes(CHARSET); + } + } else { + return null; + } + } + } +} diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/data/DataUriParser.java b/markwon-image/src/main/java/ru/noties/markwon/image/data/DataUriParser.java new file mode 100644 index 00000000..0768ee4a --- /dev/null +++ b/markwon-image/src/main/java/ru/noties/markwon/image/data/DataUriParser.java @@ -0,0 +1,79 @@ +package ru.noties.markwon.image.data; + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +public abstract class DataUriParser { + + @Nullable + public abstract DataUri parse(@NonNull String input); + + + @NonNull + public static DataUriParser create() { + return new Impl(); + } + + static class Impl extends DataUriParser { + + @Nullable + @Override + public DataUri parse(@NonNull String input) { + + final int index = input.indexOf(','); + // we expect exactly one comma + if (index < 0) { + return null; + } + + final String contentType; + final boolean base64; + + if (index > 0) { + final String part = input.substring(0, index); + final String[] parts = part.split(";"); + final int length = parts.length; + if (length > 0) { + // if one: either content-type or base64 + if (length == 1) { + final String value = parts[0]; + if ("base64".equals(value)) { + contentType = null; + base64 = true; + } else { + contentType = value.indexOf('/') > -1 + ? value + : null; + base64 = false; + } + } else { + contentType = parts[0].indexOf('/') > -1 + ? parts[0] + : null; + base64 = "base64".equals(parts[length - 1]); + } + } else { + contentType = null; + base64 = false; + } + } else { + contentType = null; + base64 = false; + } + + final String data; + if (index < input.length()) { + final String value = input.substring(index + 1, input.length()).replaceAll("\n", ""); + if (value.length() == 0) { + data = null; + } else { + data = value; + } + } else { + data = null; + } + + return new DataUri(contentType, base64, data); + } + } +} diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/data/DataUriSchemeHandler.java b/markwon-image/src/main/java/ru/noties/markwon/image/data/DataUriSchemeHandler.java new file mode 100644 index 00000000..cd4bd570 --- /dev/null +++ b/markwon-image/src/main/java/ru/noties/markwon/image/data/DataUriSchemeHandler.java @@ -0,0 +1,64 @@ +package ru.noties.markwon.image.data; + +import android.net.Uri; +import android.support.annotation.NonNull; + +import java.io.ByteArrayInputStream; + +import ru.noties.markwon.image.ImageItem; +import ru.noties.markwon.image.SchemeHandler; + +/** + * @since 2.0.0 + */ +public class DataUriSchemeHandler extends SchemeHandler { + + public static final String SCHEME = "data"; + + @NonNull + public static DataUriSchemeHandler create() { + return new DataUriSchemeHandler(DataUriParser.create(), DataUriDecoder.create()); + } + + private static final String START = "data:"; + + private final DataUriParser uriParser; + private final DataUriDecoder uriDecoder; + + @SuppressWarnings("WeakerAccess") + DataUriSchemeHandler(@NonNull DataUriParser uriParser, @NonNull DataUriDecoder uriDecoder) { + this.uriParser = uriParser; + this.uriDecoder = uriDecoder; + } + + @NonNull + @Override + public ImageItem handle(@NonNull String raw, @NonNull Uri uri) { + + if (!raw.startsWith(START)) { + throw new IllegalStateException("Invalid data-uri: " + raw); + } + + final String part = raw.substring(START.length()); + + final DataUri dataUri = uriParser.parse(part); + if (dataUri == null) { + throw new IllegalStateException("Invalid data-uri: " + raw); + } + + final byte[] bytes; + try { + bytes = uriDecoder.decode(dataUri); + } catch (Throwable t) { + throw new IllegalStateException("Cannot decode data-uri: " + raw, t); + } + + if (bytes == null) { + throw new IllegalStateException("Decoding data-uri failed: " + raw); + } + + return ImageItem.withDecodingNeeded( + dataUri.contentType(), + new ByteArrayInputStream(bytes)); + } +} diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/file/FileSchemeHandler.java b/markwon-image/src/main/java/ru/noties/markwon/image/file/FileSchemeHandler.java new file mode 100644 index 00000000..cd5030c1 --- /dev/null +++ b/markwon-image/src/main/java/ru/noties/markwon/image/file/FileSchemeHandler.java @@ -0,0 +1,114 @@ +package ru.noties.markwon.image.file; + +import android.content.res.AssetManager; +import android.net.Uri; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.text.TextUtils; +import android.webkit.MimeTypeMap; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.util.List; + +import ru.noties.markwon.image.ImageItem; +import ru.noties.markwon.image.SchemeHandler; + +/** + * @since 3.0.0 + */ +public class FileSchemeHandler extends SchemeHandler { + + public static final String SCHEME = "file"; + + /** + * @see ru.noties.markwon.urlprocessor.UrlProcessorAndroidAssets + */ + @NonNull + public static FileSchemeHandler createWithAssets(@NonNull AssetManager assetManager) { + return new FileSchemeHandler(assetManager); + } + + @NonNull + public static FileSchemeHandler create() { + return new FileSchemeHandler(null); + } + + private static final String FILE_ANDROID_ASSETS = "android_asset"; + + @Nullable + private final AssetManager assetManager; + + @SuppressWarnings("WeakerAccess") + FileSchemeHandler(@Nullable AssetManager assetManager) { + this.assetManager = assetManager; + } + + @NonNull + @Override + public ImageItem handle(@NonNull String raw, @NonNull Uri uri) { + + final List segments = uri.getPathSegments(); + if (segments == null + || segments.size() == 0) { + // pointing to file & having no path segments is no use + throw new IllegalStateException("Invalid file path: " + raw); + } + + final InputStream inputStream; + + final boolean assets = FILE_ANDROID_ASSETS.equals(segments.get(0)); + final String fileName = uri.getLastPathSegment(); + + if (assets) { + + // no handling of assets here if we have no assetsManager + if (assetManager != null) { + + 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 + + try { + inputStream = assetManager.open(path.toString()); + } catch (IOException e) { + throw new IllegalStateException("Exception obtaining asset file: " + + "" + raw + ", path: " + path.toString(), e); + } + } else { + throw new IllegalStateException("Supplied file path points to assets, " + + "but FileSchemeHandler was not supplied with AssetsManager. " + + "Use `#createWithAssets` factory method to create FileSchemeHandler " + + "that can handle android assets"); + } + + } else { + + final String path = uri.getPath(); + if (TextUtils.isEmpty(path)) { + throw new IllegalStateException("Invalid file path: " + raw + ", " + path); + } + + try { + inputStream = new BufferedInputStream(new FileInputStream(new File(path))); + } catch (FileNotFoundException e) { + throw new IllegalStateException("Exception reading file: " + raw, e); + } + } + + final String contentType = MimeTypeMap + .getSingleton() + .getMimeTypeFromExtension(MimeTypeMap.getFileExtensionFromUrl(fileName)); + + return ImageItem.withDecodingNeeded(contentType, inputStream); + } +} diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/gif/GifMediaDecoder.java b/markwon-image/src/main/java/ru/noties/markwon/image/gif/GifMediaDecoder.java new file mode 100644 index 00000000..4d0cbe32 --- /dev/null +++ b/markwon-image/src/main/java/ru/noties/markwon/image/gif/GifMediaDecoder.java @@ -0,0 +1,77 @@ +package ru.noties.markwon.image.gif; + +import android.graphics.drawable.Drawable; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; + +import pl.droidsonroids.gif.GifDrawable; +import ru.noties.markwon.image.DrawableUtils; +import ru.noties.markwon.image.MediaDecoder; + +/** + * @since 1.1.0 + */ +@SuppressWarnings("WeakerAccess") +public class GifMediaDecoder extends MediaDecoder { + + public static final String CONTENT_TYPE = "image/gif"; + + @NonNull + public static GifMediaDecoder create(boolean autoPlayGif) { + return new GifMediaDecoder(autoPlayGif); + } + + private final boolean autoPlayGif; + + protected GifMediaDecoder(boolean autoPlayGif) { + this.autoPlayGif = autoPlayGif; + } + + @NonNull + @Override + public Drawable decode(@Nullable String contentType, @NonNull InputStream inputStream) { + + final byte[] bytes; + try { + bytes = readBytes(inputStream); + } catch (IOException e) { + throw new IllegalStateException("Cannot read GIF input-stream", e); + } + + final GifDrawable drawable; + try { + drawable = newGifDrawable(bytes); + } catch (IOException e) { + throw new IllegalStateException("Exception creating GifDrawable", e); + } + + DrawableUtils.applyIntrinsicBounds(drawable); + + if (!autoPlayGif) { + drawable.pause(); + } + + return drawable; + } + + @NonNull + protected GifDrawable newGifDrawable(@NonNull byte[] bytes) throws IOException { + return new GifDrawable(bytes); + } + + @NonNull + protected static byte[] readBytes(@NonNull InputStream stream) throws IOException { + final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + final int length = 1024 * 8; + final byte[] buffer = new byte[length]; + int read; + while ((read = stream.read(buffer, 0, length)) != -1) { + outputStream.write(buffer, 0, read); + } + return outputStream.toByteArray(); + } +} diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/network/NetworkSchemeHandler.java b/markwon-image/src/main/java/ru/noties/markwon/image/network/NetworkSchemeHandler.java new file mode 100644 index 00000000..c48d54d3 --- /dev/null +++ b/markwon-image/src/main/java/ru/noties/markwon/image/network/NetworkSchemeHandler.java @@ -0,0 +1,73 @@ +package ru.noties.markwon.image.network; + +import android.net.Uri; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; + +import ru.noties.markwon.image.ImageItem; +import ru.noties.markwon.image.SchemeHandler; + +/** + * A simple network scheme handler that is not dependent on any external libraries. + * + * @see #create() + * @since 3.0.0 + */ +public class NetworkSchemeHandler extends SchemeHandler { + + public static final String SCHEME_HTTP = "http"; + public static final String SCHEME_HTTPS = "https"; + + @NonNull + public static NetworkSchemeHandler create() { + return new NetworkSchemeHandler(); + } + + @NonNull + @Override + public ImageItem handle(@NonNull String raw, @NonNull Uri uri) { + + final ImageItem imageItem; + try { + + final URL url = new URL(raw); + final HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.connect(); + + final int responseCode = connection.getResponseCode(); + if (responseCode >= 200 && responseCode < 300) { + final String contentType = contentType(connection.getHeaderField("Content-Type")); + final InputStream inputStream = new BufferedInputStream(connection.getInputStream()); + imageItem = ImageItem.withDecodingNeeded(contentType, inputStream); + } else { + throw new IOException("Bad response code: " + responseCode + ", url: " + raw); + } + + } catch (IOException e) { + throw new IllegalStateException("Exception obtaining network resource: " + raw, e); + } + + return imageItem; + } + + @Nullable + static String contentType(@Nullable String contentType) { + + if (contentType == null) { + return null; + } + + final int index = contentType.indexOf(';'); + if (index > -1) { + return contentType.substring(0, index); + } + + return contentType; + } +} diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/network/OkHttpNetworkSchemeHandler.java b/markwon-image/src/main/java/ru/noties/markwon/image/network/OkHttpNetworkSchemeHandler.java new file mode 100644 index 00000000..0433fd13 --- /dev/null +++ b/markwon-image/src/main/java/ru/noties/markwon/image/network/OkHttpNetworkSchemeHandler.java @@ -0,0 +1,75 @@ +package ru.noties.markwon.image.network; + +import android.net.Uri; +import android.support.annotation.NonNull; + +import java.io.IOException; +import java.io.InputStream; + +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.ResponseBody; +import ru.noties.markwon.image.ImageItem; +import ru.noties.markwon.image.SchemeHandler; + +/** + * @since 4.0.0-SNAPSHOT + */ +class OkHttpNetworkSchemeHandler extends SchemeHandler { + + /** + * @see #create(OkHttpClient) + */ + @NonNull + public static OkHttpNetworkSchemeHandler create() { + return new OkHttpNetworkSchemeHandler(new OkHttpClient()); + } + + @NonNull + public static OkHttpNetworkSchemeHandler create(@NonNull OkHttpClient client) { + return new OkHttpNetworkSchemeHandler(client); + } + + private static final String HEADER_CONTENT_TYPE = "Content-Type"; + + private final OkHttpClient client; + + OkHttpNetworkSchemeHandler(@NonNull OkHttpClient client) { + this.client = client; + } + + @NonNull + @Override + public ImageItem handle(@NonNull String raw, @NonNull Uri uri) { + + final Request request = new Request.Builder() + .url(raw) + .tag(raw) + .build(); + + final Response response; + try { + response = client.newCall(request).execute(); + } catch (IOException e) { + throw new IllegalStateException("Exception obtaining network resource: " + raw, e); + } + + if (response == null) { + throw new IllegalStateException("Could not obtain network response: " + raw); + } + + final ResponseBody body = response.body(); + final InputStream inputStream = body != null + ? body.byteStream() + : null; + + if (inputStream == null) { + throw new IllegalStateException("Response does not contain body: " + raw); + } + + final String contentType = response.header(HEADER_CONTENT_TYPE); + + return ImageItem.withDecodingNeeded(contentType, inputStream); + } +} diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/svg/SvgMediaDecoder.java b/markwon-image/src/main/java/ru/noties/markwon/image/svg/SvgMediaDecoder.java new file mode 100644 index 00000000..cba9fb39 --- /dev/null +++ b/markwon-image/src/main/java/ru/noties/markwon/image/svg/SvgMediaDecoder.java @@ -0,0 +1,74 @@ +package ru.noties.markwon.image.svg; + +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import com.caverock.androidsvg.SVG; +import com.caverock.androidsvg.SVGParseException; + +import java.io.InputStream; + +import ru.noties.markwon.image.DrawableUtils; +import ru.noties.markwon.image.MediaDecoder; + +/** + * @since 1.1.0 + */ +public class SvgMediaDecoder extends MediaDecoder { + + public static final String CONTENT_TYPE = "image/svg+xml"; + + /** + * @see #create(Resources) + * @since 4.0.0-SNAPSHOT + */ + @NonNull + public static SvgMediaDecoder create() { + return new SvgMediaDecoder(Resources.getSystem()); + } + + @NonNull + public static SvgMediaDecoder create(@NonNull Resources resources) { + return new SvgMediaDecoder(resources); + } + + private final Resources resources; + + @SuppressWarnings("WeakerAccess") + SvgMediaDecoder(Resources resources) { + this.resources = resources; + } + + @NonNull + @Override + public Drawable decode(@Nullable String contentType, @NonNull InputStream inputStream) { + + final SVG svg; + try { + svg = SVG.getFromInputStream(inputStream); + } catch (SVGParseException e) { + throw new IllegalStateException("Exception decoding SVG", e); + } + + final float w = svg.getDocumentWidth(); + final float h = svg.getDocumentHeight(); + final float density = resources.getDisplayMetrics().density; + + final int width = (int) (w * density + .5F); + final int height = (int) (h * density + .5F); + + final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_4444); + final Canvas canvas = new Canvas(bitmap); + canvas.scale(density, density); + svg.renderToCanvas(canvas); + + final Drawable drawable = new BitmapDrawable(resources, bitmap); + DrawableUtils.applyIntrinsicBounds(drawable); + return drawable; + } +} diff --git a/settings.gradle b/settings.gradle index faf09343..258291b4 100644 --- a/settings.gradle +++ b/settings.gradle @@ -6,6 +6,7 @@ include ':app', ':sample', ':markwon-ext-tables', ':markwon-ext-tasklist', ':markwon-html', + ':markwon-image', ':markwon-image-gif', ':markwon-image-okhttp', ':markwon-image-svg', From 5bf21bc9409b5552330b8f459602259594df98ee Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Tue, 28 May 2019 18:50:03 +0300 Subject: [PATCH 03/42] Moved image loading into separate module --- _CHANGES.md | 2 + app/build.gradle | 5 +- .../ru/noties/markwon/MarkdownRenderer.java | 25 +- .../ru/noties/markwon/gif/GifAwarePlugin.java | 8 - .../noties/markwon/AbstractMarkwonPlugin.java | 3 - .../ru/noties/markwon/core/CorePlugin.java | 1 - .../noties/markwon/image/AsyncDrawable.java | 2 +- .../markwon/image/AsyncDrawableLoader.java | 34 +- .../image/AsyncDrawableLoaderImpl.java | 290 ------------------ .../image/AsyncDrawableLoaderNoOp.java | 4 +- .../ru/noties/markwon/image/ImageItem.java | 70 ----- .../markwon/image/ImageMediaDecoder.java | 50 --- .../ru/noties/markwon/image/ImagesPlugin.java | 130 -------- .../ru/noties/markwon/image/MediaDecoder.java | 16 - .../noties/markwon/image/SchemeHandler.java | 14 - .../ru/noties/markwon/image/data/DataUri.java | 60 ---- .../markwon/image/data/DataUriDecoder.java | 41 --- .../markwon/image/data/DataUriParser.java | 79 ----- .../image/data/DataUriSchemeHandler.java | 65 ---- .../markwon/image/file/FileSchemeHandler.java | 105 ------- .../image/network/NetworkSchemeHandler.java | 70 ----- .../ru/noties/markwon/priority/Priority.java | 97 ------ .../markwon/priority/PriorityProcessor.java | 18 -- .../priority/PriorityProcessorImpl.java | 132 -------- .../markwon/AbstractMarkwonPluginTest.java | 1 - .../markwon/MarkwonBuilderImplTest.java | 2 - .../image/data/DataUriSchemeHandlerTest.java | 2 - .../priority/PriorityProcessorTest.java | 1 - .../markwon/ext/latex/JLatexMathPlugin.java | 6 - .../markwon/image/gif/GifMediaDecoder.java | 1 - .../noties/markwon/image/gif/GifPlugin.java | 1 - .../image/okhttp/OkHttpImagesPlugin.java | 2 - .../image/okhttp/OkHttpSchemeHandler.java | 2 - .../markwon/image/svg/SvgMediaDecoder.java | 1 - .../noties/markwon/image/svg/SvgPlugin.java | 1 - markwon-image/gradle.properties | 2 +- .../image/AsyncDrawableLoaderBuilder.java | 86 ++---- .../image/AsyncDrawableLoaderImpl.java | 136 +++----- .../image/DefaultImageMediaDecoder.java | 62 ++++ .../markwon/image/ImageSpanFactory.java | 0 .../ru/noties/markwon/image/ImagesPlugin.java | 156 +++++++--- .../ru/noties/markwon/image/MediaDecoder.java | 12 +- .../noties/markwon/image/SchemeHandler.java | 12 +- .../image/data/DataUriSchemeHandler.java | 8 + .../markwon/image/file/FileSchemeHandler.java | 8 + .../markwon/image/gif/GifMediaDecoder.java | 8 + .../image/network/NetworkSchemeHandler.java | 8 + .../network/OkHttpNetworkSchemeHandler.java | 21 +- .../markwon/image/svg/SvgMediaDecoder.java | 8 + sample/build.gradle | 4 +- .../basicplugins/BasicPluginsActivity.java | 4 - .../CustomExtensionActivity.java | 1 - .../sample/customextension/IconPlugin.java | 2 - .../markwon/sample/latex/LatexActivity.java | 1 - .../sample/recycler/RecyclerActivity.java | 1 - settings.gradle | 3 - 56 files changed, 363 insertions(+), 1521 deletions(-) create mode 100644 _CHANGES.md delete mode 100644 markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderImpl.java delete mode 100644 markwon-core/src/main/java/ru/noties/markwon/image/ImageItem.java delete mode 100644 markwon-core/src/main/java/ru/noties/markwon/image/ImageMediaDecoder.java delete mode 100644 markwon-core/src/main/java/ru/noties/markwon/image/ImagesPlugin.java delete mode 100644 markwon-core/src/main/java/ru/noties/markwon/image/MediaDecoder.java delete mode 100644 markwon-core/src/main/java/ru/noties/markwon/image/SchemeHandler.java delete mode 100644 markwon-core/src/main/java/ru/noties/markwon/image/data/DataUri.java delete mode 100644 markwon-core/src/main/java/ru/noties/markwon/image/data/DataUriDecoder.java delete mode 100644 markwon-core/src/main/java/ru/noties/markwon/image/data/DataUriParser.java delete mode 100644 markwon-core/src/main/java/ru/noties/markwon/image/data/DataUriSchemeHandler.java delete mode 100644 markwon-core/src/main/java/ru/noties/markwon/image/file/FileSchemeHandler.java delete mode 100644 markwon-core/src/main/java/ru/noties/markwon/image/network/NetworkSchemeHandler.java delete mode 100644 markwon-core/src/main/java/ru/noties/markwon/priority/Priority.java delete mode 100644 markwon-core/src/main/java/ru/noties/markwon/priority/PriorityProcessor.java delete mode 100644 markwon-core/src/main/java/ru/noties/markwon/priority/PriorityProcessorImpl.java create mode 100644 markwon-image/src/main/java/ru/noties/markwon/image/DefaultImageMediaDecoder.java rename {markwon-core => markwon-image}/src/main/java/ru/noties/markwon/image/ImageSpanFactory.java (100%) diff --git a/_CHANGES.md b/_CHANGES.md new file mode 100644 index 00000000..b1bb22c8 --- /dev/null +++ b/_CHANGES.md @@ -0,0 +1,2 @@ +* `Markwon.builder` won't require CorePlugin registration (it is done automatically) + to create a builder without CorePlugin - use `Markwon#builderNoCore` \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index c6ad59c1..9d95baaf 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -33,8 +33,7 @@ dependencies { implementation project(':markwon-ext-tables') implementation project(':markwon-ext-tasklist') implementation project(':markwon-html') - implementation project(':markwon-image-gif') - implementation project(':markwon-image-svg') + implementation project(':markwon-image') implementation project(':markwon-syntax-highlight') deps.with { @@ -42,6 +41,8 @@ dependencies { implementation it['prism4j'] implementation it['debug'] implementation it['dagger'] + implementation it['android-svg'] + implementation it['android-gif'] } deps['annotationProcessor'].with { diff --git a/app/src/main/java/ru/noties/markwon/MarkdownRenderer.java b/app/src/main/java/ru/noties/markwon/MarkdownRenderer.java index cf2ab04c..26b247a2 100644 --- a/app/src/main/java/ru/noties/markwon/MarkdownRenderer.java +++ b/app/src/main/java/ru/noties/markwon/MarkdownRenderer.java @@ -14,15 +14,18 @@ import java.util.concurrent.Future; import javax.inject.Inject; import ru.noties.debug.Debug; -import ru.noties.markwon.core.CorePlugin; import ru.noties.markwon.ext.strikethrough.StrikethroughPlugin; import ru.noties.markwon.ext.tables.TablePlugin; import ru.noties.markwon.ext.tasklist.TaskListPlugin; import ru.noties.markwon.gif.GifAwarePlugin; import ru.noties.markwon.html.HtmlPlugin; +import ru.noties.markwon.image.DefaultImageMediaDecoder; import ru.noties.markwon.image.ImagesPlugin; -import ru.noties.markwon.image.gif.GifPlugin; -import ru.noties.markwon.image.svg.SvgPlugin; +import ru.noties.markwon.image.data.DataUriSchemeHandler; +import ru.noties.markwon.image.file.FileSchemeHandler; +import ru.noties.markwon.image.gif.GifMediaDecoder; +import ru.noties.markwon.image.network.OkHttpNetworkSchemeHandler; +import ru.noties.markwon.image.svg.SvgMediaDecoder; import ru.noties.markwon.syntax.Prism4jTheme; import ru.noties.markwon.syntax.Prism4jThemeDarkula; import ru.noties.markwon.syntax.Prism4jThemeDefault; @@ -94,10 +97,18 @@ public class MarkdownRenderer { : prism4JThemeDarkula; final Markwon markwon = Markwon.builder(context) - .usePlugin(CorePlugin.create()) - .usePlugin(ImagesPlugin.createWithAssets(context)) - .usePlugin(SvgPlugin.create(context.getResources())) - .usePlugin(GifPlugin.create(false)) + .usePlugin(ImagesPlugin.create(new ImagesPlugin.ImagesConfigure() { + @Override + public void configureImages(@NonNull ImagesPlugin plugin) { + plugin + .addSchemeHandler(DataUriSchemeHandler.create()) + .addSchemeHandler(OkHttpNetworkSchemeHandler.create()) + .addSchemeHandler(FileSchemeHandler.createWithAssets(context.getAssets())) + .addMediaDecoder(GifMediaDecoder.create(false)) + .addMediaDecoder(SvgMediaDecoder.create()) + .defaultMediaDecoder(DefaultImageMediaDecoder.create()); + } + })) .usePlugin(SyntaxHighlightPlugin.create(prism4j, prism4jTheme)) .usePlugin(GifAwarePlugin.create(context)) .usePlugin(TablePlugin.create(context)) diff --git a/app/src/main/java/ru/noties/markwon/gif/GifAwarePlugin.java b/app/src/main/java/ru/noties/markwon/gif/GifAwarePlugin.java index 89e49384..95509525 100644 --- a/app/src/main/java/ru/noties/markwon/gif/GifAwarePlugin.java +++ b/app/src/main/java/ru/noties/markwon/gif/GifAwarePlugin.java @@ -14,8 +14,6 @@ import ru.noties.markwon.RenderProps; import ru.noties.markwon.SpanFactory; import ru.noties.markwon.image.AsyncDrawableSpan; import ru.noties.markwon.image.ImageProps; -import ru.noties.markwon.image.ImagesPlugin; -import ru.noties.markwon.priority.Priority; public class GifAwarePlugin extends AbstractMarkwonPlugin { @@ -59,12 +57,6 @@ public class GifAwarePlugin extends AbstractMarkwonPlugin { }); } - @NonNull - @Override - public Priority priority() { - return Priority.after(ImagesPlugin.class); - } - @Override public void afterSetText(@NonNull TextView textView) { processor.process(textView); diff --git a/markwon-core/src/main/java/ru/noties/markwon/AbstractMarkwonPlugin.java b/markwon-core/src/main/java/ru/noties/markwon/AbstractMarkwonPlugin.java index 3bf54029..ae05550a 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/AbstractMarkwonPlugin.java +++ b/markwon-core/src/main/java/ru/noties/markwon/AbstractMarkwonPlugin.java @@ -7,11 +7,8 @@ import android.widget.TextView; import org.commonmark.node.Node; import org.commonmark.parser.Parser; -import ru.noties.markwon.core.CorePlugin; import ru.noties.markwon.core.MarkwonTheme; import ru.noties.markwon.html.MarkwonHtmlRenderer; -import ru.noties.markwon.image.AsyncDrawableLoader; -import ru.noties.markwon.priority.Priority; /** * Class that extends {@link MarkwonPlugin} with all methods implemented (empty body) diff --git a/markwon-core/src/main/java/ru/noties/markwon/core/CorePlugin.java b/markwon-core/src/main/java/ru/noties/markwon/core/CorePlugin.java index 39436839..4882441a 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/core/CorePlugin.java +++ b/markwon-core/src/main/java/ru/noties/markwon/core/CorePlugin.java @@ -40,7 +40,6 @@ import ru.noties.markwon.core.factory.ListItemSpanFactory; import ru.noties.markwon.core.factory.StrongEmphasisSpanFactory; import ru.noties.markwon.core.factory.ThematicBreakSpanFactory; import ru.noties.markwon.core.spans.OrderedListItemSpan; -import ru.noties.markwon.priority.Priority; /** * @see CoreProps diff --git a/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawable.java b/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawable.java index 5db212fd..239dad4e 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawable.java +++ b/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawable.java @@ -40,7 +40,7 @@ public class AsyncDrawable extends Drawable { this.imageSizeResolver = imageSizeResolver; this.imageSize = imageSize; - final Drawable placeholder = loader.placeholder(); + final Drawable placeholder = loader.placeholder(this); if (placeholder != null) { setPlaceholderResult(placeholder); } diff --git a/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableLoader.java b/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableLoader.java index 7e297bf3..f9bbb4b7 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableLoader.java +++ b/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableLoader.java @@ -3,13 +3,6 @@ package ru.noties.markwon.image; import android.graphics.drawable.Drawable; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import android.util.Log; - -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; public abstract class AsyncDrawableLoader { @@ -31,28 +24,9 @@ public abstract class AsyncDrawableLoader { */ public abstract void cancel(@NonNull AsyncDrawable drawable); - /** - * @see #load(AsyncDrawable) - * @deprecated 3.1.0-SNAPSHOT - */ - @Deprecated - public void load(@NonNull String destination, @NonNull AsyncDrawable drawable) { - load(drawable); - } - - /** - * Method is deprecated because cancellation won\'t work for markdown input - * with multiple images with the same source - * - * @deprecated 3.1.0-SNAPSHOT - */ - @Deprecated - public void cancel(@NonNull String destination) { - Log.e("MARKWON-IL", "Image loading cancellation must be triggered " + - "by AsyncDrawable, please use #cancel(AsyncDrawable) method instead. " + - "No op, nothing is cancelled for destination: " + destination); - } - @Nullable - public abstract Drawable placeholder(); + public abstract Drawable placeholder(@NonNull AsyncDrawable drawable); + + + } diff --git a/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderImpl.java b/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderImpl.java deleted file mode 100644 index 711508c2..00000000 --- a/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderImpl.java +++ /dev/null @@ -1,290 +0,0 @@ -package ru.noties.markwon.image; - -import android.graphics.drawable.Drawable; -import android.net.Uri; -import android.os.Handler; -import android.os.Looper; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; - -import java.io.IOException; -import java.io.InputStream; -import java.lang.ref.WeakReference; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Future; - -class AsyncDrawableLoaderImpl extends AsyncDrawableLoader { - - private final ExecutorService executorService; - private final Map schemeHandlers; - private final Map mediaDecoders; - private final MediaDecoder defaultMediaDecoder; - private final DrawableProvider placeholderDrawableProvider; - private final DrawableProvider errorDrawableProvider; - - private final Handler mainThread; - - // @since 3.1.0-SNAPSHOT use a hash-map with a weak AsyncDrawable as key for multiple requests - // for the same destination - private final Map, Future> requests = new HashMap<>(2); - - AsyncDrawableLoaderImpl(@NonNull Builder builder) { - this.executorService = builder.executorService; - this.schemeHandlers = builder.schemeHandlers; - this.mediaDecoders = builder.mediaDecoders; - this.defaultMediaDecoder = builder.defaultMediaDecoder; - this.placeholderDrawableProvider = builder.placeholderDrawableProvider; - this.errorDrawableProvider = builder.errorDrawableProvider; - this.mainThread = new Handler(Looper.getMainLooper()); - } - - @Override - public void load(@NonNull final AsyncDrawable drawable) { - - // primitive synchronization via main-thread - if (!isMainThread()) { - mainThread.post(new Runnable() { - @Override - public void run() { - load(drawable); - } - }); - return; - } - - // okay, if by some chance requested drawable already has a future associated -> no-op - // as AsyncDrawable cannot change `destination` (immutable field) - // @since 3.1.0-SNAPSHOT - if (hasTaskAssociated(drawable)) { - return; - } - - final WeakReference reference = new WeakReference<>(drawable); - requests.put(reference, execute(drawable.getDestination(), reference)); - } - - @Override - public void cancel(@NonNull final AsyncDrawable drawable) { - - if (!isMainThread()) { - mainThread.post(new Runnable() { - @Override - public void run() { - cancel(drawable); - } - }); - return; - } - - final Iterator, Future>> iterator = - requests.entrySet().iterator(); - - AsyncDrawable key; - Map.Entry, Future> entry; - - while (iterator.hasNext()) { - - entry = iterator.next(); - key = entry.getKey().get(); - - // if key is null or it contains requested AsyncDrawable -> cancel - if (shouldCleanUp(key) || key == drawable) { - entry.getValue().cancel(true); - iterator.remove(); - } - } - } - - private boolean hasTaskAssociated(@NonNull AsyncDrawable drawable) { - - final Iterator, Future>> iterator = - requests.entrySet().iterator(); - - boolean result = false; - - AsyncDrawable key; - Map.Entry, Future> entry; - - while (iterator.hasNext()) { - - entry = iterator.next(); - key = entry.getKey().get(); - - // clean-up - if (shouldCleanUp(key)) { - entry.getValue().cancel(true); - iterator.remove(); - } else if (key == drawable) { - result = true; - // do not break, let iteration continue to possibly clean-up the rest references - } - } - - return result; - } - - private void cleanUp() { - - final Iterator, Future>> iterator = - requests.entrySet().iterator(); - - AsyncDrawable key; - Map.Entry, Future> entry; - - while (iterator.hasNext()) { - - entry = iterator.next(); - key = entry.getKey().get(); - - // clean-up of already referenced or detached drawables - if (shouldCleanUp(key)) { - entry.getValue().cancel(true); - iterator.remove(); - } - } - } - -// @Override -// public void load(@NonNull String destination, @NonNull AsyncDrawable drawable) { -// -// // todo: we cannot reliably identify request by the destination, as if -// // markdown input has multiple images with the same destination as source -// // we will be tracking only one of them (the one appears the last). We should -// // move to AsyncDrawable based identification. This method also _maybe_ -// // should include the ImageSize (comment @since 3.1.0-SNAPSHOT) -// -// requests.put(destination, execute(destination, drawable)); -// } -// -// @Override -// public void cancel(@NonNull String destination) { -// -// // todo: as we are moving away from a single request for a destination, -// // we should re-evaluate this cancellation logic, as if there are multiple images -// // in markdown input all of them will be cancelled (won't delivered), even if -// // only a single drawable is detached. Cancellation must also take -// // the AsyncDrawable argument (comment @since 3.1.0-SNAPSHOT) -// -// // -// final Future request = requests.remove(destination); -// if (request != null) { -// request.cancel(true); -// } -// } - - @Nullable - @Override - public Drawable placeholder() { - return placeholderDrawableProvider != null - ? placeholderDrawableProvider.provide() - : null; - } - - private Future execute(@NonNull final String destination, @NonNull final WeakReference reference) { - - // todo: error handing (simply applying errorDrawable is not a good solution - // as reason for an error is unclear (no scheme handler, no input data, error decoding, etc) - - // todo: more efficient ImageMediaDecoder... BitmapFactory.decodeStream is a bit not optimal - // for big images for sure. We _could_ introduce internal Drawable that will check for - // image bounds (but we will need to cache inputStream in order to inspect and optimize - // input image...) - - return executorService.submit(new Runnable() { - @Override - public void run() { - - final ImageItem item; - - final Uri uri = Uri.parse(destination); - - final SchemeHandler schemeHandler = schemeHandlers.get(uri.getScheme()); - - if (schemeHandler != null) { - item = schemeHandler.handle(destination, uri); - } else { - item = null; - } - - final InputStream inputStream = item != null - ? item.inputStream() - : null; - - Drawable result = null; - - if (inputStream != null) { - try { - - MediaDecoder mediaDecoder = mediaDecoders.get(item.contentType()); - if (mediaDecoder == null) { - mediaDecoder = defaultMediaDecoder; - } - - if (mediaDecoder != null) { - result = mediaDecoder.decode(inputStream); - } - - } finally { - try { - inputStream.close(); - } catch (IOException e) { - // ignored - } - } - } - - // if result is null, we assume it's an error - if (result == null) { - result = errorDrawableProvider != null - ? errorDrawableProvider.provide() - : null; - } - - final Drawable out = result; - - mainThread.post(new Runnable() { - @Override - public void run() { - - if (out != null) { - - // this doesn't work with markdown input with multiple images with the - // same source (comment @since 3.1.0-SNAPSHOT) -// final boolean canDeliver = requests.remove(destination) != null; -// if (canDeliver) { -// final AsyncDrawable asyncDrawable = reference.get(); -// if (asyncDrawable != null && asyncDrawable.isAttached()) { -// asyncDrawable.setResult(out); -// } -// } - - // todo: AsyncDrawable cannot change destination, so if it's - // attached and not garbage-collected, we can deliver the result. - // Note that there is no cache, so attach/detach of drawables - // will always request a new entry.. (comment @since 3.1.0-SNAPSHOT) - final AsyncDrawable asyncDrawable = reference.get(); - if (asyncDrawable != null && asyncDrawable.isAttached()) { - asyncDrawable.setResult(out); - } - } - - requests.remove(reference); - cleanUp(); - } - }); - } - }); - } - - private static boolean shouldCleanUp(@Nullable AsyncDrawable drawable) { - return drawable == null || !drawable.isAttached(); - } - - @SuppressWarnings("BooleanMethodIsAlwaysInverted") - private static boolean isMainThread() { - return Looper.myLooper() == Looper.getMainLooper(); - } -} diff --git a/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderNoOp.java b/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderNoOp.java index 330abe94..7c3475b7 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderNoOp.java +++ b/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderNoOp.java @@ -4,7 +4,7 @@ import android.graphics.drawable.Drawable; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -class AsyncDrawableLoaderNoOp extends AsyncDrawableLoader { +public class AsyncDrawableLoaderNoOp extends AsyncDrawableLoader { @Override public void load(@NonNull AsyncDrawable drawable) { @@ -17,7 +17,7 @@ class AsyncDrawableLoaderNoOp extends AsyncDrawableLoader { @Nullable @Override - public Drawable placeholder() { + public Drawable placeholder(@NonNull AsyncDrawable drawable) { return null; } } diff --git a/markwon-core/src/main/java/ru/noties/markwon/image/ImageItem.java b/markwon-core/src/main/java/ru/noties/markwon/image/ImageItem.java deleted file mode 100644 index a6e9f72e..00000000 --- a/markwon-core/src/main/java/ru/noties/markwon/image/ImageItem.java +++ /dev/null @@ -1,70 +0,0 @@ -package ru.noties.markwon.image; - -import android.graphics.drawable.Drawable; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; - -import java.io.InputStream; - -/** - * @since 2.0.0 - */ -public abstract class ImageItem { - - /** - * Create an {@link ImageItem} with result, so no further decoding is required. - * - * @since 4.0.0-SNAPSHOT - */ - @NonNull - public static ImageItem withResult(@Nullable Drawable drawable) { - return new WithResult(drawable); - } - - @NonNull - public static ImageItem withDecodingNeeded( - @Nullable String contentType, - @Nullable InputStream inputStream) { - return new WithDecodingNeeded(contentType, inputStream); - } - - private ImageItem() { - } - - public static class WithResult extends ImageItem { - - private final Drawable result; - - WithResult(@Nullable Drawable drawable) { - result = drawable; - } - - @Nullable - public Drawable result() { - return result; - } - } - - public static class WithDecodingNeeded extends ImageItem { - - private final String contentType; - private final InputStream inputStream; - - WithDecodingNeeded( - @Nullable String contentType, - @Nullable InputStream inputStream) { - this.contentType = contentType; - this.inputStream = inputStream; - } - - @Nullable - public String contentType() { - return contentType; - } - - @Nullable - public InputStream inputStream() { - return inputStream; - } - } -} diff --git a/markwon-core/src/main/java/ru/noties/markwon/image/ImageMediaDecoder.java b/markwon-core/src/main/java/ru/noties/markwon/image/ImageMediaDecoder.java deleted file mode 100644 index c510c4d8..00000000 --- a/markwon-core/src/main/java/ru/noties/markwon/image/ImageMediaDecoder.java +++ /dev/null @@ -1,50 +0,0 @@ -package ru.noties.markwon.image; - -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; - -import java.io.InputStream; - -/** - * This class can be used as the last {@link MediaDecoder} to _try_ to handle all rest cases. - * Here we just assume that supplied InputStream is of image type and try to decode it. - * - * @since 1.1.0 - */ -public class ImageMediaDecoder extends MediaDecoder { - - @NonNull - public static ImageMediaDecoder create(@NonNull Resources resources) { - return new ImageMediaDecoder(resources); - } - - private final Resources resources; - - @SuppressWarnings("WeakerAccess") - ImageMediaDecoder(Resources resources) { - this.resources = resources; - } - - @Nullable - @Override - public Drawable decode(@NonNull InputStream inputStream) { - - final Drawable out; - - // absolutely not optimal... thing - final Bitmap bitmap = BitmapFactory.decodeStream(inputStream); - if (bitmap != null) { - out = new BitmapDrawable(resources, bitmap); - DrawableUtils.applyIntrinsicBounds(out); - } else { - out = null; - } - - return out; - } -} diff --git a/markwon-core/src/main/java/ru/noties/markwon/image/ImagesPlugin.java b/markwon-core/src/main/java/ru/noties/markwon/image/ImagesPlugin.java deleted file mode 100644 index 2f6e8117..00000000 --- a/markwon-core/src/main/java/ru/noties/markwon/image/ImagesPlugin.java +++ /dev/null @@ -1,130 +0,0 @@ -package ru.noties.markwon.image; - -import android.content.Context; -import android.support.annotation.NonNull; -import android.text.Spanned; -import android.widget.TextView; - -import org.commonmark.node.Image; -import org.commonmark.node.Link; -import org.commonmark.node.Node; - -import java.util.Arrays; - -import ru.noties.markwon.AbstractMarkwonPlugin; -import ru.noties.markwon.MarkwonConfiguration; -import ru.noties.markwon.MarkwonSpansFactory; -import ru.noties.markwon.MarkwonVisitor; -import ru.noties.markwon.RenderProps; -import ru.noties.markwon.SpanFactory; -import ru.noties.markwon.image.data.DataUriSchemeHandler; -import ru.noties.markwon.image.file.FileSchemeHandler; -import ru.noties.markwon.image.network.NetworkSchemeHandler; - -/** - * @since 3.0.0 - */ -public class ImagesPlugin extends AbstractMarkwonPlugin { - - @NonNull - public static ImagesPlugin create(@NonNull Context context) { - return new ImagesPlugin(context, false); - } - - /** - * Special scheme that is used {@code file:///android_asset/} - * - * @param context - * @return - */ - @NonNull - public static ImagesPlugin createWithAssets(@NonNull Context context) { - return new ImagesPlugin(context, true); - } - - private final Context context; - private final boolean useAssets; - - protected ImagesPlugin(Context context, boolean useAssets) { - this.context = context; - this.useAssets = useAssets; - } - - @Override - public void configureImages(@NonNull AsyncDrawableLoader.Builder builder) { - - final FileSchemeHandler fileSchemeHandler = useAssets - ? FileSchemeHandler.createWithAssets(context.getAssets()) - : FileSchemeHandler.create(); - - builder - .addSchemeHandler(DataUriSchemeHandler.SCHEME, DataUriSchemeHandler.create()) - .addSchemeHandler(FileSchemeHandler.SCHEME, fileSchemeHandler) - .addSchemeHandler( - Arrays.asList( - NetworkSchemeHandler.SCHEME_HTTP, - NetworkSchemeHandler.SCHEME_HTTPS), - NetworkSchemeHandler.create()) - .defaultMediaDecoder(ImageMediaDecoder.create(context.getResources())); - } - - @Override - public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) { - builder.setFactory(Image.class, new ImageSpanFactory()); - } - - @Override - public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) { - builder.on(Image.class, new MarkwonVisitor.NodeVisitor() { - @Override - public void visit(@NonNull MarkwonVisitor visitor, @NonNull Image image) { - - // if there is no image spanFactory, ignore - final SpanFactory spanFactory = visitor.configuration().spansFactory().get(Image.class); - if (spanFactory == null) { - visitor.visitChildren(image); - return; - } - - final int length = visitor.length(); - - visitor.visitChildren(image); - - // we must check if anything _was_ added, as we need at least one char to render - if (length == visitor.length()) { - visitor.builder().append('\uFFFC'); - } - - final MarkwonConfiguration configuration = visitor.configuration(); - - final Node parent = image.getParent(); - final boolean link = parent instanceof Link; - - final String destination = configuration - .urlProcessor() - .process(image.getDestination()); - - final RenderProps props = visitor.renderProps(); - - // apply image properties - // Please note that we explicitly set IMAGE_SIZE to null as we do not clear - // properties after we applied span (we could though) - ImageProps.DESTINATION.set(props, destination); - ImageProps.REPLACEMENT_TEXT_IS_LINK.set(props, link); - ImageProps.IMAGE_SIZE.set(props, null); - - visitor.setSpans(length, spanFactory.getSpans(configuration, props)); - } - }); - } - - @Override - public void beforeSetText(@NonNull TextView textView, @NonNull Spanned markdown) { - AsyncDrawableScheduler.unschedule(textView); - } - - @Override - public void afterSetText(@NonNull TextView textView) { - AsyncDrawableScheduler.schedule(textView); - } -} diff --git a/markwon-core/src/main/java/ru/noties/markwon/image/MediaDecoder.java b/markwon-core/src/main/java/ru/noties/markwon/image/MediaDecoder.java deleted file mode 100644 index 68d0ff33..00000000 --- a/markwon-core/src/main/java/ru/noties/markwon/image/MediaDecoder.java +++ /dev/null @@ -1,16 +0,0 @@ -package ru.noties.markwon.image; - -import android.graphics.drawable.Drawable; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; - -import java.io.InputStream; - -/** - * @since 3.0.0 - */ -public abstract class MediaDecoder { - - @Nullable - public abstract Drawable decode(@NonNull InputStream inputStream); -} diff --git a/markwon-core/src/main/java/ru/noties/markwon/image/SchemeHandler.java b/markwon-core/src/main/java/ru/noties/markwon/image/SchemeHandler.java deleted file mode 100644 index cac1c801..00000000 --- a/markwon-core/src/main/java/ru/noties/markwon/image/SchemeHandler.java +++ /dev/null @@ -1,14 +0,0 @@ -package ru.noties.markwon.image; - -import android.net.Uri; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; - -/** - * @since 3.0.0 - */ -public abstract class SchemeHandler { - - @Nullable - public abstract ImageItem handle(@NonNull String raw, @NonNull Uri uri); -} diff --git a/markwon-core/src/main/java/ru/noties/markwon/image/data/DataUri.java b/markwon-core/src/main/java/ru/noties/markwon/image/data/DataUri.java deleted file mode 100644 index 6e812c92..00000000 --- a/markwon-core/src/main/java/ru/noties/markwon/image/data/DataUri.java +++ /dev/null @@ -1,60 +0,0 @@ -package ru.noties.markwon.image.data; - -import android.support.annotation.Nullable; - -public class DataUri { - - private final String contentType; - private final boolean base64; - private final String data; - - public DataUri(@Nullable String contentType, boolean base64, @Nullable String data) { - this.contentType = contentType; - this.base64 = base64; - this.data = data; - } - - @Nullable - public String contentType() { - return contentType; - } - - public boolean base64() { - return base64; - } - - @Nullable - public String data() { - return data; - } - - @Override - public String toString() { - return "DataUri{" + - "contentType='" + contentType + '\'' + - ", base64=" + base64 + - ", data='" + data + '\'' + - '}'; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - DataUri dataUri = (DataUri) o; - - if (base64 != dataUri.base64) return false; - if (contentType != null ? !contentType.equals(dataUri.contentType) : dataUri.contentType != null) - return false; - return data != null ? data.equals(dataUri.data) : dataUri.data == null; - } - - @Override - public int hashCode() { - int result = contentType != null ? contentType.hashCode() : 0; - result = 31 * result + (base64 ? 1 : 0); - result = 31 * result + (data != null ? data.hashCode() : 0); - return result; - } -} diff --git a/markwon-core/src/main/java/ru/noties/markwon/image/data/DataUriDecoder.java b/markwon-core/src/main/java/ru/noties/markwon/image/data/DataUriDecoder.java deleted file mode 100644 index 7e3d4f73..00000000 --- a/markwon-core/src/main/java/ru/noties/markwon/image/data/DataUriDecoder.java +++ /dev/null @@ -1,41 +0,0 @@ -package ru.noties.markwon.image.data; - -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.text.TextUtils; -import android.util.Base64; - -public abstract class DataUriDecoder { - - @Nullable - public abstract byte[] decode(@NonNull DataUri dataUri); - - @NonNull - public static DataUriDecoder create() { - return new Impl(); - } - - static class Impl extends DataUriDecoder { - - @Nullable - @Override - public byte[] decode(@NonNull DataUri dataUri) { - - final String data = dataUri.data(); - - if (!TextUtils.isEmpty(data)) { - try { - if (dataUri.base64()) { - return Base64.decode(data.getBytes("UTF-8"), Base64.DEFAULT); - } else { - return data.getBytes("UTF-8"); - } - } catch (Throwable t) { - return null; - } - } else { - return null; - } - } - } -} diff --git a/markwon-core/src/main/java/ru/noties/markwon/image/data/DataUriParser.java b/markwon-core/src/main/java/ru/noties/markwon/image/data/DataUriParser.java deleted file mode 100644 index 0768ee4a..00000000 --- a/markwon-core/src/main/java/ru/noties/markwon/image/data/DataUriParser.java +++ /dev/null @@ -1,79 +0,0 @@ -package ru.noties.markwon.image.data; - -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; - -public abstract class DataUriParser { - - @Nullable - public abstract DataUri parse(@NonNull String input); - - - @NonNull - public static DataUriParser create() { - return new Impl(); - } - - static class Impl extends DataUriParser { - - @Nullable - @Override - public DataUri parse(@NonNull String input) { - - final int index = input.indexOf(','); - // we expect exactly one comma - if (index < 0) { - return null; - } - - final String contentType; - final boolean base64; - - if (index > 0) { - final String part = input.substring(0, index); - final String[] parts = part.split(";"); - final int length = parts.length; - if (length > 0) { - // if one: either content-type or base64 - if (length == 1) { - final String value = parts[0]; - if ("base64".equals(value)) { - contentType = null; - base64 = true; - } else { - contentType = value.indexOf('/') > -1 - ? value - : null; - base64 = false; - } - } else { - contentType = parts[0].indexOf('/') > -1 - ? parts[0] - : null; - base64 = "base64".equals(parts[length - 1]); - } - } else { - contentType = null; - base64 = false; - } - } else { - contentType = null; - base64 = false; - } - - final String data; - if (index < input.length()) { - final String value = input.substring(index + 1, input.length()).replaceAll("\n", ""); - if (value.length() == 0) { - data = null; - } else { - data = value; - } - } else { - data = null; - } - - return new DataUri(contentType, base64, data); - } - } -} diff --git a/markwon-core/src/main/java/ru/noties/markwon/image/data/DataUriSchemeHandler.java b/markwon-core/src/main/java/ru/noties/markwon/image/data/DataUriSchemeHandler.java deleted file mode 100644 index f4c87ed4..00000000 --- a/markwon-core/src/main/java/ru/noties/markwon/image/data/DataUriSchemeHandler.java +++ /dev/null @@ -1,65 +0,0 @@ -package ru.noties.markwon.image.data; - -import android.net.Uri; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; - -import java.io.ByteArrayInputStream; - -import ru.noties.markwon.image.ImageItem; -import ru.noties.markwon.image.SchemeHandler; - -/** - * @since 2.0.0 - */ -public class DataUriSchemeHandler extends SchemeHandler { - - public static final String SCHEME = "data"; - - @NonNull - public static DataUriSchemeHandler create() { - return new DataUriSchemeHandler(DataUriParser.create(), DataUriDecoder.create()); - } - - private static final String START = "data:"; - - private final DataUriParser uriParser; - private final DataUriDecoder uriDecoder; - - @SuppressWarnings("WeakerAccess") - DataUriSchemeHandler(@NonNull DataUriParser uriParser, @NonNull DataUriDecoder uriDecoder) { - this.uriParser = uriParser; - this.uriDecoder = uriDecoder; - } - - @Nullable - @Override - public ImageItem handle(@NonNull String raw, @NonNull Uri uri) { - - if (!raw.startsWith(START)) { - return null; - } - - String part = raw.substring(START.length()); - - // this part is added to support `data://` with which this functionality was released - if (part.startsWith("//")) { - part = part.substring(2); - } - - final DataUri dataUri = uriParser.parse(part); - if (dataUri == null) { - return null; - } - - final byte[] bytes = uriDecoder.decode(dataUri); - if (bytes == null) { - return null; - } - - return new ImageItem( - dataUri.contentType(), - new ByteArrayInputStream(bytes) - ); - } -} diff --git a/markwon-core/src/main/java/ru/noties/markwon/image/file/FileSchemeHandler.java b/markwon-core/src/main/java/ru/noties/markwon/image/file/FileSchemeHandler.java deleted file mode 100644 index 712899aa..00000000 --- a/markwon-core/src/main/java/ru/noties/markwon/image/file/FileSchemeHandler.java +++ /dev/null @@ -1,105 +0,0 @@ -package ru.noties.markwon.image.file; - -import android.content.res.AssetManager; -import android.net.Uri; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.webkit.MimeTypeMap; - -import java.io.BufferedInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.util.List; - -import ru.noties.markwon.image.ImageItem; -import ru.noties.markwon.image.SchemeHandler; - -/** - * @since 3.0.0 - */ -public class FileSchemeHandler extends SchemeHandler { - - public static final String SCHEME = "file"; - - @NonNull - public static FileSchemeHandler createWithAssets(@NonNull AssetManager assetManager) { - return new FileSchemeHandler(assetManager); - } - - @NonNull - public static FileSchemeHandler create() { - return new FileSchemeHandler(null); - } - - private static final String FILE_ANDROID_ASSETS = "android_asset"; - - @Nullable - private final AssetManager assetManager; - - @SuppressWarnings("WeakerAccess") - FileSchemeHandler(@Nullable AssetManager assetManager) { - this.assetManager = assetManager; - } - - @Nullable - @Override - public ImageItem handle(@NonNull String raw, @NonNull 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 ImageItem out; - - InputStream inputStream = null; - - final boolean assets = FILE_ANDROID_ASSETS.equals(segments.get(0)); - final String fileName = uri.getLastPathSegment(); - - if (assets) { - - // no handling of assets here if we have no assetsManager - if (assetManager != null) { - - 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 - - try { - inputStream = assetManager.open(path.toString()); - } catch (IOException e) { - e.printStackTrace(); - } - } - - } else { - try { - inputStream = new BufferedInputStream(new FileInputStream(new File(uri.getPath()))); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } - } - - if (inputStream != null) { - final String contentType = MimeTypeMap - .getSingleton() - .getMimeTypeFromExtension(MimeTypeMap.getFileExtensionFromUrl(fileName)); - out = new ImageItem(contentType, inputStream); - } else { - out = null; - } - - return out; - } -} diff --git a/markwon-core/src/main/java/ru/noties/markwon/image/network/NetworkSchemeHandler.java b/markwon-core/src/main/java/ru/noties/markwon/image/network/NetworkSchemeHandler.java deleted file mode 100644 index ebaaf803..00000000 --- a/markwon-core/src/main/java/ru/noties/markwon/image/network/NetworkSchemeHandler.java +++ /dev/null @@ -1,70 +0,0 @@ -package ru.noties.markwon.image.network; - -import android.net.Uri; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; - -import java.io.BufferedInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.HttpURLConnection; -import java.net.URL; - -import ru.noties.markwon.image.ImageItem; -import ru.noties.markwon.image.SchemeHandler; - -/** - * A simple network scheme handler that is not dependent on any external libraries. - * - * @see #create() - * @since 3.0.0 - */ -public class NetworkSchemeHandler extends SchemeHandler { - - public static final String SCHEME_HTTP = "http"; - public static final String SCHEME_HTTPS = "https"; - - @NonNull - public static NetworkSchemeHandler create() { - return new NetworkSchemeHandler(); - } - - @Nullable - @Override - public ImageItem handle(@NonNull String raw, @NonNull Uri uri) { - - try { - - final URL url = new URL(raw); - final HttpURLConnection connection = (HttpURLConnection) url.openConnection(); - connection.connect(); - - final int responseCode = connection.getResponseCode(); - if (responseCode >= 200 && responseCode < 300) { - final String contentType = contentType(connection.getHeaderField("Content-Type")); - final InputStream inputStream = new BufferedInputStream(connection.getInputStream()); - return new ImageItem(contentType, inputStream); - } - - } catch (IOException e) { - e.printStackTrace(); - } - - return null; - } - - @Nullable - static String contentType(@Nullable String contentType) { - - if (contentType == null) { - return null; - } - - final int index = contentType.indexOf(';'); - if (index > -1) { - return contentType.substring(0, index); - } - - return contentType; - } -} diff --git a/markwon-core/src/main/java/ru/noties/markwon/priority/Priority.java b/markwon-core/src/main/java/ru/noties/markwon/priority/Priority.java deleted file mode 100644 index e10faf2a..00000000 --- a/markwon-core/src/main/java/ru/noties/markwon/priority/Priority.java +++ /dev/null @@ -1,97 +0,0 @@ -package ru.noties.markwon.priority; - -import android.support.annotation.NonNull; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import ru.noties.markwon.MarkwonPlugin; - -// a small dependency graph also -// what if plugins cannot be constructed into a graph? for example they depend on something -// but not overlap? then it would be hard to sort them (but this doesn't make sense, if -// they do not care about other components, just put them in whatever order, no?) - -/** - * @see MarkwonPlugin#priority() - * @since 3.0.0 - */ -@Deprecated -public abstract class Priority { - - @NonNull - public static Priority none() { - return builder().build(); - } - - @NonNull - public static Priority after(@NonNull Class plugin) { - return builder().after(plugin).build(); - } - - @NonNull - public static Priority after( - @NonNull Class plugin1, - @NonNull Class plugin2) { - return builder().after(plugin1).after(plugin2).build(); - } - - @NonNull - public static Builder builder() { - return new Impl.BuilderImpl(); - } - - public interface Builder { - - @NonNull - Builder after(@NonNull Class plugin); - - @NonNull - Priority build(); - } - - @NonNull - public abstract List> after(); - - - static class Impl extends Priority { - - private final List> after; - - Impl(@NonNull List> after) { - this.after = after; - } - - @NonNull - @Override - public List> after() { - return after; - } - - @Override - public String toString() { - return "Priority{" + - "after=" + after + - '}'; - } - - static class BuilderImpl implements Builder { - - private final List> after = new ArrayList<>(0); - - @NonNull - @Override - public Builder after(@NonNull Class plugin) { - after.add(plugin); - return this; - } - - @NonNull - @Override - public Priority build() { - return new Impl(Collections.unmodifiableList(after)); - } - } - } -} diff --git a/markwon-core/src/main/java/ru/noties/markwon/priority/PriorityProcessor.java b/markwon-core/src/main/java/ru/noties/markwon/priority/PriorityProcessor.java deleted file mode 100644 index 1ba1353d..00000000 --- a/markwon-core/src/main/java/ru/noties/markwon/priority/PriorityProcessor.java +++ /dev/null @@ -1,18 +0,0 @@ -package ru.noties.markwon.priority; - -import android.support.annotation.NonNull; - -import java.util.List; - -import ru.noties.markwon.MarkwonPlugin; - -public abstract class PriorityProcessor { - - @NonNull - public static PriorityProcessor create() { - return new PriorityProcessorImpl(); - } - - @NonNull - public abstract List process(@NonNull List plugins); -} diff --git a/markwon-core/src/main/java/ru/noties/markwon/priority/PriorityProcessorImpl.java b/markwon-core/src/main/java/ru/noties/markwon/priority/PriorityProcessorImpl.java deleted file mode 100644 index e676a9c9..00000000 --- a/markwon-core/src/main/java/ru/noties/markwon/priority/PriorityProcessorImpl.java +++ /dev/null @@ -1,132 +0,0 @@ -package ru.noties.markwon.priority; - -import android.support.annotation.NonNull; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import ru.noties.markwon.MarkwonPlugin; - -import static java.lang.Math.max; - -class PriorityProcessorImpl extends PriorityProcessor { - - @NonNull - @Override - public List process(@NonNull List in) { - - // create new collection based on supplied argument - final List plugins = new ArrayList<>(in); - - final int size = plugins.size(); - - final Map, Set>> map = - new HashMap<>(size); - - for (MarkwonPlugin plugin : plugins) { - if (map.put(plugin.getClass(), new HashSet<>(plugin.priority().after())) != null) { - throw new IllegalStateException(String.format("Markwon duplicate plugin " + - "found `%s`: %s", plugin.getClass().getName(), plugin)); - } - } - - final Map cache = new HashMap<>(size); - for (MarkwonPlugin plugin : plugins) { - cache.put(plugin, eval(plugin, map)); - } - - Collections.sort(plugins, new PriorityComparator(cache)); - - return plugins; - } - - private static int eval( - @NonNull MarkwonPlugin plugin, - @NonNull Map, Set>> map) { - - final Set> set = map.get(plugin.getClass()); - - // no dependencies - if (set.isEmpty()) { - return 0; - } - - final Class who = plugin.getClass(); - - int max = 0; - - for (Class dependency : set) { - max = max(max, eval(who, dependency, map)); - } - - return 1 + max; - } - - // we need to count the number of steps to a root node (which has no parents) - private static int eval( - @NonNull Class who, - @NonNull Class plugin, - @NonNull Map, Set>> map) { - - // exact match - Set> set = map.get(plugin); - - if (set == null) { - - // let's try to find inexact type (overridden/subclassed) - for (Map.Entry, Set>> entry : map.entrySet()) { - if (plugin.isAssignableFrom(entry.getKey())) { - set = entry.getValue(); - break; - } - } - - if (set == null) { - // unsatisfied dependency - throw new IllegalStateException(String.format("Markwon unsatisfied dependency found. " + - "Plugin `%s` comes after `%s` but it is not added.", - who.getName(), plugin.getName())); - } - } - - if (set.isEmpty()) { - return 0; - } - - int value = 1; - - for (Class dependency : set) { - - // a case when a plugin defines `Priority.after(getClass)` or being - // referenced by own dependency (even indirect) - if (who.equals(dependency)) { - throw new IllegalStateException(String.format("Markwon plugin `%s` defined self " + - "as a dependency or being referenced by own dependency (cycle)", who.getName())); - } - - value += eval(who, dependency, map); - } - - return value; - } - - private static class PriorityComparator implements Comparator { - - private final Map map; - - PriorityComparator(@NonNull Map map) { - this.map = map; - } - - @Override - public int compare(MarkwonPlugin o1, MarkwonPlugin o2) { - return map.get(o1).compareTo(map.get(o2)); - } - } -} diff --git a/markwon-core/src/test/java/ru/noties/markwon/AbstractMarkwonPluginTest.java b/markwon-core/src/test/java/ru/noties/markwon/AbstractMarkwonPluginTest.java index 1af2b513..2002a06d 100644 --- a/markwon-core/src/test/java/ru/noties/markwon/AbstractMarkwonPluginTest.java +++ b/markwon-core/src/test/java/ru/noties/markwon/AbstractMarkwonPluginTest.java @@ -8,7 +8,6 @@ import org.robolectric.annotation.Config; import java.util.List; import ru.noties.markwon.core.CorePlugin; -import ru.noties.markwon.priority.Priority; import static org.junit.Assert.assertEquals; diff --git a/markwon-core/src/test/java/ru/noties/markwon/MarkwonBuilderImplTest.java b/markwon-core/src/test/java/ru/noties/markwon/MarkwonBuilderImplTest.java index af3d00b1..43d115a4 100644 --- a/markwon-core/src/test/java/ru/noties/markwon/MarkwonBuilderImplTest.java +++ b/markwon-core/src/test/java/ru/noties/markwon/MarkwonBuilderImplTest.java @@ -23,8 +23,6 @@ import ru.noties.markwon.core.CorePlugin; import ru.noties.markwon.core.MarkwonTheme; import ru.noties.markwon.html.MarkwonHtmlRenderer; import ru.noties.markwon.image.AsyncDrawableLoader; -import ru.noties.markwon.priority.Priority; -import ru.noties.markwon.priority.PriorityProcessor; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.hasItem; diff --git a/markwon-core/src/test/java/ru/noties/markwon/image/data/DataUriSchemeHandlerTest.java b/markwon-core/src/test/java/ru/noties/markwon/image/data/DataUriSchemeHandlerTest.java index 16dc73b5..82c571f7 100644 --- a/markwon-core/src/test/java/ru/noties/markwon/image/data/DataUriSchemeHandlerTest.java +++ b/markwon-core/src/test/java/ru/noties/markwon/image/data/DataUriSchemeHandlerTest.java @@ -14,8 +14,6 @@ import java.util.HashMap; import java.util.Map; import java.util.Scanner; -import ru.noties.markwon.image.ImageItem; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; diff --git a/markwon-core/src/test/java/ru/noties/markwon/priority/PriorityProcessorTest.java b/markwon-core/src/test/java/ru/noties/markwon/priority/PriorityProcessorTest.java index 2a6063ed..164f98a5 100644 --- a/markwon-core/src/test/java/ru/noties/markwon/priority/PriorityProcessorTest.java +++ b/markwon-core/src/test/java/ru/noties/markwon/priority/PriorityProcessorTest.java @@ -18,7 +18,6 @@ import java.util.List; import ru.noties.markwon.AbstractMarkwonPlugin; import ru.noties.markwon.MarkwonPlugin; import ru.noties.markwon.core.CorePlugin; -import ru.noties.markwon.image.ImagesPlugin; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; diff --git a/markwon-ext-latex/src/main/java/ru/noties/markwon/ext/latex/JLatexMathPlugin.java b/markwon-ext-latex/src/main/java/ru/noties/markwon/ext/latex/JLatexMathPlugin.java index c4761d0c..9a09679d 100644 --- a/markwon-ext-latex/src/main/java/ru/noties/markwon/ext/latex/JLatexMathPlugin.java +++ b/markwon-ext-latex/src/main/java/ru/noties/markwon/ext/latex/JLatexMathPlugin.java @@ -19,13 +19,7 @@ import ru.noties.markwon.AbstractMarkwonPlugin; import ru.noties.markwon.MarkwonVisitor; import ru.noties.markwon.RenderProps; import ru.noties.markwon.image.AsyncDrawableLoader; -import ru.noties.markwon.image.ImageItem; -import ru.noties.markwon.image.ImageProps; import ru.noties.markwon.image.ImageSize; -import ru.noties.markwon.image.ImagesPlugin; -import ru.noties.markwon.image.MediaDecoder; -import ru.noties.markwon.image.SchemeHandler; -import ru.noties.markwon.priority.Priority; /** * @since 3.0.0 diff --git a/markwon-image-gif/src/main/java/ru/noties/markwon/image/gif/GifMediaDecoder.java b/markwon-image-gif/src/main/java/ru/noties/markwon/image/gif/GifMediaDecoder.java index 6f5eda18..72dd572c 100644 --- a/markwon-image-gif/src/main/java/ru/noties/markwon/image/gif/GifMediaDecoder.java +++ b/markwon-image-gif/src/main/java/ru/noties/markwon/image/gif/GifMediaDecoder.java @@ -10,7 +10,6 @@ import java.io.InputStream; import pl.droidsonroids.gif.GifDrawable; import ru.noties.markwon.image.DrawableUtils; -import ru.noties.markwon.image.MediaDecoder; /** * @since 1.1.0 diff --git a/markwon-image-gif/src/main/java/ru/noties/markwon/image/gif/GifPlugin.java b/markwon-image-gif/src/main/java/ru/noties/markwon/image/gif/GifPlugin.java index d0db857e..6cceffdf 100644 --- a/markwon-image-gif/src/main/java/ru/noties/markwon/image/gif/GifPlugin.java +++ b/markwon-image-gif/src/main/java/ru/noties/markwon/image/gif/GifPlugin.java @@ -4,7 +4,6 @@ import android.support.annotation.NonNull; import ru.noties.markwon.AbstractMarkwonPlugin; import ru.noties.markwon.image.AsyncDrawableLoader; -import ru.noties.markwon.image.ImagesPlugin; import ru.noties.markwon.priority.Priority; public class GifPlugin extends AbstractMarkwonPlugin { diff --git a/markwon-image-okhttp/src/main/java/ru/noties/markwon/image/okhttp/OkHttpImagesPlugin.java b/markwon-image-okhttp/src/main/java/ru/noties/markwon/image/okhttp/OkHttpImagesPlugin.java index fe43c289..36cc79fb 100644 --- a/markwon-image-okhttp/src/main/java/ru/noties/markwon/image/okhttp/OkHttpImagesPlugin.java +++ b/markwon-image-okhttp/src/main/java/ru/noties/markwon/image/okhttp/OkHttpImagesPlugin.java @@ -7,8 +7,6 @@ import java.util.Arrays; import okhttp3.OkHttpClient; import ru.noties.markwon.AbstractMarkwonPlugin; import ru.noties.markwon.image.AsyncDrawableLoader; -import ru.noties.markwon.image.ImagesPlugin; -import ru.noties.markwon.image.network.NetworkSchemeHandler; import ru.noties.markwon.priority.Priority; /** diff --git a/markwon-image-okhttp/src/main/java/ru/noties/markwon/image/okhttp/OkHttpSchemeHandler.java b/markwon-image-okhttp/src/main/java/ru/noties/markwon/image/okhttp/OkHttpSchemeHandler.java index eaf73bd6..32527bdf 100644 --- a/markwon-image-okhttp/src/main/java/ru/noties/markwon/image/okhttp/OkHttpSchemeHandler.java +++ b/markwon-image-okhttp/src/main/java/ru/noties/markwon/image/okhttp/OkHttpSchemeHandler.java @@ -11,8 +11,6 @@ import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; import okhttp3.ResponseBody; -import ru.noties.markwon.image.ImageItem; -import ru.noties.markwon.image.SchemeHandler; class OkHttpSchemeHandler extends SchemeHandler { diff --git a/markwon-image-svg/src/main/java/ru/noties/markwon/image/svg/SvgMediaDecoder.java b/markwon-image-svg/src/main/java/ru/noties/markwon/image/svg/SvgMediaDecoder.java index 5ee71c61..8c8b9dcc 100644 --- a/markwon-image-svg/src/main/java/ru/noties/markwon/image/svg/SvgMediaDecoder.java +++ b/markwon-image-svg/src/main/java/ru/noties/markwon/image/svg/SvgMediaDecoder.java @@ -14,7 +14,6 @@ import com.caverock.androidsvg.SVGParseException; import java.io.InputStream; import ru.noties.markwon.image.DrawableUtils; -import ru.noties.markwon.image.MediaDecoder; /** * @since 1.1.0 diff --git a/markwon-image-svg/src/main/java/ru/noties/markwon/image/svg/SvgPlugin.java b/markwon-image-svg/src/main/java/ru/noties/markwon/image/svg/SvgPlugin.java index be357480..c4486fc6 100644 --- a/markwon-image-svg/src/main/java/ru/noties/markwon/image/svg/SvgPlugin.java +++ b/markwon-image-svg/src/main/java/ru/noties/markwon/image/svg/SvgPlugin.java @@ -5,7 +5,6 @@ import android.support.annotation.NonNull; import ru.noties.markwon.AbstractMarkwonPlugin; import ru.noties.markwon.image.AsyncDrawableLoader; -import ru.noties.markwon.image.ImagesPlugin; import ru.noties.markwon.priority.Priority; public class SvgPlugin extends AbstractMarkwonPlugin { diff --git a/markwon-image/gradle.properties b/markwon-image/gradle.properties index a845eebf..d7dd30bd 100644 --- a/markwon-image/gradle.properties +++ b/markwon-image/gradle.properties @@ -1,4 +1,4 @@ POM_NAME=Image POM_ARTIFACT_ID=image -POM_DESCRIPTION=Markwon image loading module (with GIF and SVG support) +POM_DESCRIPTION=Markwon image loading module (with optional GIF and SVG support) POM_PACKAGING=aar \ No newline at end of file diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderBuilder.java b/markwon-image/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderBuilder.java index 47c91146..6bbe234b 100644 --- a/markwon-image/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderBuilder.java +++ b/markwon-image/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderBuilder.java @@ -1,6 +1,5 @@ package ru.noties.markwon.image; -import android.graphics.drawable.Drawable; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -10,88 +9,69 @@ import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -public class AsyncDrawableLoaderBuilder { +class AsyncDrawableLoaderBuilder { ExecutorService executorService; final Map schemeHandlers = new HashMap<>(3); final Map mediaDecoders = new HashMap<>(3); MediaDecoder defaultMediaDecoder; - DrawableProvider placeholderDrawableProvider; - DrawableProvider errorDrawableProvider; + ImagesPlugin.PlaceholderProvider placeholderProvider; + ImagesPlugin.ErrorHandler errorHandler; - @NonNull - public AsyncDrawableLoaderBuilder executorService(@NonNull ExecutorService executorService) { + boolean isBuilt; + + void executorService(@NonNull ExecutorService executorService) { this.executorService = executorService; - return this; } - @NonNull - public AsyncDrawableLoaderBuilder addSchemeHandler(@NonNull String scheme, @NonNull SchemeHandler schemeHandler) { - schemeHandlers.put(scheme, schemeHandler); - return this; - } - - @NonNull - public AsyncDrawableLoaderBuilder addSchemeHandler(@NonNull Collection schemes, @NonNull SchemeHandler schemeHandler) { - for (String scheme : schemes) { + void addSchemeHandler(@NonNull SchemeHandler schemeHandler) { + for (String scheme : schemeHandler.supportedSchemes()) { schemeHandlers.put(scheme, schemeHandler); } - return this; } - @NonNull - public AsyncDrawableLoaderBuilder addMediaDecoder(@NonNull String contentType, @NonNull MediaDecoder mediaDecoder) { - mediaDecoders.put(contentType, mediaDecoder); - return this; - } - - @NonNull - public AsyncDrawableLoaderBuilder addMediaDecoder(@NonNull Collection contentTypes, @NonNull MediaDecoder mediaDecoder) { - for (String contentType : contentTypes) { - mediaDecoders.put(contentType, mediaDecoder); + void addMediaDecoder(@NonNull MediaDecoder mediaDecoder) { + final Collection supportedTypes = mediaDecoder.supportedTypes(); + if (supportedTypes.isEmpty()) { + // todo: we should think about this little _side-effect_... does it worth it? + defaultMediaDecoder = mediaDecoder; + } else { + for (String type : supportedTypes) { + mediaDecoders.put(type, mediaDecoder); + } } - return this; } - @NonNull - public AsyncDrawableLoaderBuilder removeSchemeHandler(@NonNull String scheme) { - schemeHandlers.remove(scheme); - return this; - } - - @NonNull - public AsyncDrawableLoaderBuilder removeMediaDecoder(@NonNull String contentType) { - mediaDecoders.remove(contentType); - return this; - } - - @NonNull - public AsyncDrawableLoaderBuilder defaultMediaDecoder(@Nullable MediaDecoder mediaDecoder) { + void defaultMediaDecoder(@Nullable MediaDecoder mediaDecoder) { this.defaultMediaDecoder = mediaDecoder; - return this; + } + + void removeSchemeHandler(@NonNull String scheme) { + schemeHandlers.remove(scheme); + } + + void removeMediaDecoder(@NonNull String contentType) { + mediaDecoders.remove(contentType); } /** * @since 3.0.0 */ - @NonNull - public AsyncDrawableLoaderBuilder placeholderDrawableProvider(@NonNull DrawableProvider placeholderDrawableProvider) { - this.placeholderDrawableProvider = placeholderDrawableProvider; - return this; + void placeholderProvider(@NonNull ImagesPlugin.PlaceholderProvider placeholderDrawableProvider) { + this.placeholderProvider = placeholderDrawableProvider; } /** * @since 3.0.0 */ - @NonNull - public AsyncDrawableLoaderBuilder errorDrawableProvider(@NonNull DrawableProvider errorDrawableProvider) { - this.errorDrawableProvider = errorDrawableProvider; - return this; + void errorHandler(@NonNull ImagesPlugin.ErrorHandler errorHandler) { + this.errorHandler = errorHandler; } - @NonNull - public AsyncDrawableLoader build() { + AsyncDrawableLoader build() { + + isBuilt = true; // if we have no schemeHandlers -> we cannot show anything // OR if we have no media decoders diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderImpl.java b/markwon-image/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderImpl.java index 711508c2..a0226c48 100644 --- a/markwon-image/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderImpl.java +++ b/markwon-image/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderImpl.java @@ -6,9 +6,8 @@ import android.os.Handler; import android.os.Looper; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.util.Log; -import java.io.IOException; -import java.io.InputStream; import java.lang.ref.WeakReference; import java.util.HashMap; import java.util.Iterator; @@ -22,8 +21,8 @@ class AsyncDrawableLoaderImpl extends AsyncDrawableLoader { private final Map schemeHandlers; private final Map mediaDecoders; private final MediaDecoder defaultMediaDecoder; - private final DrawableProvider placeholderDrawableProvider; - private final DrawableProvider errorDrawableProvider; + private final ImagesPlugin.PlaceholderProvider placeholderProvider; + private final ImagesPlugin.ErrorHandler errorHandler; private final Handler mainThread; @@ -31,13 +30,13 @@ class AsyncDrawableLoaderImpl extends AsyncDrawableLoader { // for the same destination private final Map, Future> requests = new HashMap<>(2); - AsyncDrawableLoaderImpl(@NonNull Builder builder) { + AsyncDrawableLoaderImpl(@NonNull AsyncDrawableLoaderBuilder builder) { this.executorService = builder.executorService; this.schemeHandlers = builder.schemeHandlers; this.mediaDecoders = builder.mediaDecoders; this.defaultMediaDecoder = builder.defaultMediaDecoder; - this.placeholderDrawableProvider = builder.placeholderDrawableProvider; - this.errorDrawableProvider = builder.errorDrawableProvider; + this.placeholderProvider = builder.placeholderProvider; + this.errorHandler = builder.errorHandler; this.mainThread = new Handler(Looper.getMainLooper()); } @@ -147,48 +146,18 @@ class AsyncDrawableLoaderImpl extends AsyncDrawableLoader { } } -// @Override -// public void load(@NonNull String destination, @NonNull AsyncDrawable drawable) { -// -// // todo: we cannot reliably identify request by the destination, as if -// // markdown input has multiple images with the same destination as source -// // we will be tracking only one of them (the one appears the last). We should -// // move to AsyncDrawable based identification. This method also _maybe_ -// // should include the ImageSize (comment @since 3.1.0-SNAPSHOT) -// -// requests.put(destination, execute(destination, drawable)); -// } -// -// @Override -// public void cancel(@NonNull String destination) { -// -// // todo: as we are moving away from a single request for a destination, -// // we should re-evaluate this cancellation logic, as if there are multiple images -// // in markdown input all of them will be cancelled (won't delivered), even if -// // only a single drawable is detached. Cancellation must also take -// // the AsyncDrawable argument (comment @since 3.1.0-SNAPSHOT) -// -// // -// final Future request = requests.remove(destination); -// if (request != null) { -// request.cancel(true); -// } -// } - @Nullable @Override - public Drawable placeholder() { - return placeholderDrawableProvider != null - ? placeholderDrawableProvider.provide() + public Drawable placeholder(@NonNull AsyncDrawable drawable) { + return placeholderProvider != null + ? placeholderProvider.providePlaceholder(drawable) : null; } + @NonNull private Future execute(@NonNull final String destination, @NonNull final WeakReference reference) { - // todo: error handing (simply applying errorDrawable is not a good solution - // as reason for an error is unclear (no scheme handler, no input data, error decoding, etc) - - // todo: more efficient ImageMediaDecoder... BitmapFactory.decodeStream is a bit not optimal + // todo: more efficient DefaultImageMediaDecoder... BitmapFactory.decodeStream is a bit not optimal // for big images for sure. We _could_ introduce internal Drawable that will check for // image bounds (but we will need to cache inputStream in order to inspect and optimize // input image...) @@ -197,71 +166,60 @@ class AsyncDrawableLoaderImpl extends AsyncDrawableLoader { @Override public void run() { - final ImageItem item; - final Uri uri = Uri.parse(destination); - final SchemeHandler schemeHandler = schemeHandlers.get(uri.getScheme()); + Drawable drawable = null; - if (schemeHandler != null) { - item = schemeHandler.handle(destination, uri); - } else { - item = null; - } + try { + // obtain scheme handler + final SchemeHandler schemeHandler = schemeHandlers.get(uri.getScheme()); + if (schemeHandler != null) { - final InputStream inputStream = item != null - ? item.inputStream() - : null; + // handle scheme + final ImageItem imageItem = schemeHandler.handle(destination, uri); - Drawable result = null; + // if resulting imageItem needs further decoding -> proceed + if (imageItem.hasDecodingNeeded()) { - if (inputStream != null) { - try { + final ImageItem.WithDecodingNeeded withDecodingNeeded = imageItem.getAsWithDecodingNeeded(); - MediaDecoder mediaDecoder = mediaDecoders.get(item.contentType()); - if (mediaDecoder == null) { - mediaDecoder = defaultMediaDecoder; + MediaDecoder mediaDecoder = mediaDecoders.get(withDecodingNeeded.contentType()); + + if (mediaDecoder == null) { + mediaDecoder = defaultMediaDecoder; + } + + if (mediaDecoder != null) { + drawable = mediaDecoder.decode(withDecodingNeeded.contentType(), withDecodingNeeded.inputStream()); + } else { + // throw that no media decoder is found + throw new IllegalStateException("No media-decoder is found: " + destination); + } + } else { + drawable = imageItem.getAsWithResult().result(); } + } else { + // throw no scheme handler is available + throw new IllegalStateException("No scheme-handler is found: " + destination); + } - if (mediaDecoder != null) { - result = mediaDecoder.decode(inputStream); - } - - } finally { - try { - inputStream.close(); - } catch (IOException e) { - // ignored - } + } catch (Throwable t) { + if (errorHandler != null) { + drawable = errorHandler.handleError(destination, t); + } else { + // else simply log the error + Log.e("MARKWON-IMAGE", "Error loading image: " + destination, t); } } - // if result is null, we assume it's an error - if (result == null) { - result = errorDrawableProvider != null - ? errorDrawableProvider.provide() - : null; - } - - final Drawable out = result; + final Drawable out = drawable; mainThread.post(new Runnable() { @Override public void run() { if (out != null) { - - // this doesn't work with markdown input with multiple images with the - // same source (comment @since 3.1.0-SNAPSHOT) -// final boolean canDeliver = requests.remove(destination) != null; -// if (canDeliver) { -// final AsyncDrawable asyncDrawable = reference.get(); -// if (asyncDrawable != null && asyncDrawable.isAttached()) { -// asyncDrawable.setResult(out); -// } -// } - - // todo: AsyncDrawable cannot change destination, so if it's + // AsyncDrawable cannot change destination, so if it's // attached and not garbage-collected, we can deliver the result. // Note that there is no cache, so attach/detach of drawables // will always request a new entry.. (comment @since 3.1.0-SNAPSHOT) diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/DefaultImageMediaDecoder.java b/markwon-image/src/main/java/ru/noties/markwon/image/DefaultImageMediaDecoder.java new file mode 100644 index 00000000..8322f745 --- /dev/null +++ b/markwon-image/src/main/java/ru/noties/markwon/image/DefaultImageMediaDecoder.java @@ -0,0 +1,62 @@ +package ru.noties.markwon.image; + +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import java.io.InputStream; +import java.util.Collection; +import java.util.Collections; + +/** + * This class can be used as the last {@link MediaDecoder} to _try_ to handle all rest cases. + * Here we just assume that supplied InputStream is of image type and try to decode it. + * + * @since 1.1.0 + */ +public class DefaultImageMediaDecoder extends MediaDecoder { + + @NonNull + public static DefaultImageMediaDecoder create() { + return new DefaultImageMediaDecoder(Resources.getSystem()); + } + + @NonNull + public static DefaultImageMediaDecoder create(@NonNull Resources resources) { + return new DefaultImageMediaDecoder(resources); + } + + private final Resources resources; + + @SuppressWarnings("WeakerAccess") + DefaultImageMediaDecoder(Resources resources) { + this.resources = resources; + } + + @NonNull + @Override + public Drawable decode(@Nullable String contentType, @NonNull InputStream inputStream) { + + final Bitmap bitmap; + try { + // absolutely not optimal... thing + bitmap = BitmapFactory.decodeStream(inputStream); + } catch (Throwable t) { + throw new IllegalStateException("Exception decoding input-stream", t); + } + + final Drawable drawable = new BitmapDrawable(resources, bitmap); + DrawableUtils.applyIntrinsicBounds(drawable); + return drawable; + } + + @NonNull + @Override + public Collection supportedTypes() { + return Collections.emptySet(); + } +} diff --git a/markwon-core/src/main/java/ru/noties/markwon/image/ImageSpanFactory.java b/markwon-image/src/main/java/ru/noties/markwon/image/ImageSpanFactory.java similarity index 100% rename from markwon-core/src/main/java/ru/noties/markwon/image/ImageSpanFactory.java rename to markwon-image/src/main/java/ru/noties/markwon/image/ImageSpanFactory.java diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/ImagesPlugin.java b/markwon-image/src/main/java/ru/noties/markwon/image/ImagesPlugin.java index 3d441f7b..e8cd8324 100644 --- a/markwon-image/src/main/java/ru/noties/markwon/image/ImagesPlugin.java +++ b/markwon-image/src/main/java/ru/noties/markwon/image/ImagesPlugin.java @@ -1,6 +1,5 @@ package ru.noties.markwon.image; -import android.content.Context; import android.graphics.drawable.Drawable; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -11,6 +10,8 @@ import org.commonmark.node.Image; import org.commonmark.node.Link; import org.commonmark.node.Node; +import java.util.concurrent.ExecutorService; + import ru.noties.markwon.AbstractMarkwonPlugin; import ru.noties.markwon.MarkwonConfiguration; import ru.noties.markwon.MarkwonSpansFactory; @@ -23,55 +24,123 @@ public class ImagesPlugin extends AbstractMarkwonPlugin { /** * @since 4.0.0-SNAPSHOT */ - public interface DrawableProvider { - @Nullable - Drawable provide(); - } - - - @NonNull - public static ImagesPlugin create(@NonNull Context context) { - return new ImagesPlugin(context, false); + public interface ImagesConfigure { + void configureImages(@NonNull ImagesPlugin plugin); } /** - * Special scheme that is used {@code file:///android_asset/} - * - * @param context - * @return + * @since 4.0.0-SNAPSHOT + */ + public interface PlaceholderProvider { + @Nullable + Drawable providePlaceholder(@NonNull AsyncDrawable drawable); + } + + /** + * @since 4.0.0-SNAPSHOT + */ + public interface ErrorHandler { + + /** + * Can optionally return a Drawable that will be displayed in case of an error + */ + @Nullable + Drawable handleError(@NonNull String url, @NonNull Throwable throwable); + } + + /** + * Factory method to create an empty {@link ImagesPlugin} instance with no {@link SchemeHandler}s + * nor {@link MediaDecoder}s registered. Can be used to further configure via instance methods or + * via {@link ru.noties.markwon.MarkwonPlugin#configure(Registry)} */ @NonNull - public static ImagesPlugin createWithAssets(@NonNull Context context) { - return new ImagesPlugin(context, true); + public static ImagesPlugin createEmpty() { + return new ImagesPlugin(); } - private final Context context; - private final boolean useAssets; - - protected ImagesPlugin(Context context, boolean useAssets) { - this.context = context; - this.useAssets = useAssets; + @NonNull + public static ImagesPlugin create(@NonNull ImagesConfigure configure) { + final ImagesPlugin plugin = new ImagesPlugin(); + configure.configureImages(plugin); + return plugin; } - // we must expose scheme handling... so it's available during construction and via `require` + private final AsyncDrawableLoaderBuilder builder = new AsyncDrawableLoaderBuilder(); -// @Override -// public void configureImages(@NonNull AsyncDrawableLoader.Builder builder) { -// -// final FileSchemeHandler fileSchemeHandler = useAssets -// ? FileSchemeHandler.createWithAssets(context.getAssets()) -// : FileSchemeHandler.create(); -// -// builder -// .addSchemeHandler(DataUriSchemeHandler.SCHEME, DataUriSchemeHandler.create()) -// .addSchemeHandler(FileSchemeHandler.SCHEME, fileSchemeHandler) -// .addSchemeHandler( -// Arrays.asList( -// NetworkSchemeHandler.SCHEME_HTTP, -// NetworkSchemeHandler.SCHEME_HTTPS), -// NetworkSchemeHandler.create()) -// .defaultMediaDecoder(ImageMediaDecoder.create(context.getResources())); -// } + /** + * Optional (by default new cached thread executor will be used) + * + * @since 4.0.0-SNAPSHOT + */ + @NonNull + public ImagesPlugin executorService(@NonNull ExecutorService executorService) { + checkBuilderState(); + builder.executorService(executorService); + return this; + } + + /** + * @see SchemeHandler + * @see ru.noties.markwon.image.data.DataUriSchemeHandler + * @see ru.noties.markwon.image.file.FileSchemeHandler + * @see ru.noties.markwon.image.network.NetworkSchemeHandler + * @see ru.noties.markwon.image.network.OkHttpNetworkSchemeHandler + * @since 4.0.0-SNAPSHOT + */ + @NonNull + public ImagesPlugin addSchemeHandler(@NonNull SchemeHandler schemeHandler) { + checkBuilderState(); + builder.addSchemeHandler(schemeHandler); + return this; + } + + @NonNull + public ImagesPlugin addMediaDecoder(@NonNull MediaDecoder mediaDecoder) { + checkBuilderState(); + builder.addMediaDecoder(mediaDecoder); + return this; + } + + @NonNull + public ImagesPlugin defaultMediaDecoder(@Nullable MediaDecoder mediaDecoder) { + checkBuilderState(); + builder.defaultMediaDecoder(mediaDecoder); + return this; + } + + @NonNull + public ImagesPlugin removeSchemeHandler(@NonNull String scheme) { + checkBuilderState(); + builder.removeSchemeHandler(scheme); + return this; + } + + @NonNull + public ImagesPlugin removeMediaDecoder(@NonNull String contentType) { + checkBuilderState(); + builder.removeMediaDecoder(contentType); + return this; + } + + @NonNull + public ImagesPlugin placeholderProvider(@NonNull PlaceholderProvider placeholderProvider) { + checkBuilderState(); + builder.placeholderProvider(placeholderProvider); + return this; + } + + @NonNull + public ImagesPlugin errorHandler(@NonNull ErrorHandler errorHandler) { + checkBuilderState(); + builder.errorHandler(errorHandler); + return this; + } + + @Override + public void configureConfiguration(@NonNull MarkwonConfiguration.Builder builder) { + checkBuilderState(); + builder.asyncDrawableLoader(this.builder.build()); + } @Override public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) { @@ -132,4 +201,11 @@ public class ImagesPlugin extends AbstractMarkwonPlugin { public void afterSetText(@NonNull TextView textView) { AsyncDrawableScheduler.schedule(textView); } + + private void checkBuilderState() { + if (builder.isBuilt) { + throw new IllegalStateException("ImagesPlugin has already been configured " + + "and cannot be modified any further"); + } + } } diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/MediaDecoder.java b/markwon-image/src/main/java/ru/noties/markwon/image/MediaDecoder.java index ecea7a98..4470c50e 100644 --- a/markwon-image/src/main/java/ru/noties/markwon/image/MediaDecoder.java +++ b/markwon-image/src/main/java/ru/noties/markwon/image/MediaDecoder.java @@ -5,6 +5,7 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; import java.io.InputStream; +import java.util.Collection; /** * @since 3.0.0 @@ -16,14 +17,17 @@ public abstract class MediaDecoder { *
    *
  • Returns `non-null` drawable
  • *
  • Added `contentType` method parameter
  • - *
  • Added `throws Exception` to method signature
  • *
- * - * @throws Exception since 4.0.0-SNAPSHOT */ @NonNull public abstract Drawable decode( @Nullable String contentType, @NonNull InputStream inputStream - ) throws Exception; + ); + + /** + * @since 4.0.0-SNAPSHOT + */ + @NonNull + public abstract Collection supportedTypes(); } diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/SchemeHandler.java b/markwon-image/src/main/java/ru/noties/markwon/image/SchemeHandler.java index 2c5889ed..32402136 100644 --- a/markwon-image/src/main/java/ru/noties/markwon/image/SchemeHandler.java +++ b/markwon-image/src/main/java/ru/noties/markwon/image/SchemeHandler.java @@ -3,6 +3,8 @@ package ru.noties.markwon.image; import android.net.Uri; import android.support.annotation.NonNull; +import java.util.Collection; + /** * @since 3.0.0 */ @@ -12,13 +14,17 @@ public abstract class SchemeHandler { * Changes since 4.0.0-SNAPSHOT: *
    *
  • Returns `non-null` image-item
  • - *
  • added `throws Exception` to method signature
  • *
* - * @throws Exception since 4.0.0-SNAPSHOT * @see ImageItem#withResult(android.graphics.drawable.Drawable) * @see ImageItem#withDecodingNeeded(String, java.io.InputStream) */ @NonNull - public abstract ImageItem handle(@NonNull String raw, @NonNull Uri uri) throws Exception; + public abstract ImageItem handle(@NonNull String raw, @NonNull Uri uri); + + /** + * @since 4.0.0-SNAPSHOT + */ + @NonNull + public abstract Collection supportedSchemes(); } diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/data/DataUriSchemeHandler.java b/markwon-image/src/main/java/ru/noties/markwon/image/data/DataUriSchemeHandler.java index cd4bd570..b5c8dcc4 100644 --- a/markwon-image/src/main/java/ru/noties/markwon/image/data/DataUriSchemeHandler.java +++ b/markwon-image/src/main/java/ru/noties/markwon/image/data/DataUriSchemeHandler.java @@ -4,6 +4,8 @@ import android.net.Uri; import android.support.annotation.NonNull; import java.io.ByteArrayInputStream; +import java.util.Collection; +import java.util.Collections; import ru.noties.markwon.image.ImageItem; import ru.noties.markwon.image.SchemeHandler; @@ -61,4 +63,10 @@ public class DataUriSchemeHandler extends SchemeHandler { dataUri.contentType(), new ByteArrayInputStream(bytes)); } + + @NonNull + @Override + public Collection supportedSchemes() { + return Collections.singleton(SCHEME); + } } diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/file/FileSchemeHandler.java b/markwon-image/src/main/java/ru/noties/markwon/image/file/FileSchemeHandler.java index cd5030c1..681fb29f 100644 --- a/markwon-image/src/main/java/ru/noties/markwon/image/file/FileSchemeHandler.java +++ b/markwon-image/src/main/java/ru/noties/markwon/image/file/FileSchemeHandler.java @@ -13,6 +13,8 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; +import java.util.Collection; +import java.util.Collections; import java.util.List; import ru.noties.markwon.image.ImageItem; @@ -111,4 +113,10 @@ public class FileSchemeHandler extends SchemeHandler { return ImageItem.withDecodingNeeded(contentType, inputStream); } + + @NonNull + @Override + public Collection supportedSchemes() { + return Collections.singleton(SCHEME); + } } diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/gif/GifMediaDecoder.java b/markwon-image/src/main/java/ru/noties/markwon/image/gif/GifMediaDecoder.java index 4d0cbe32..e5195bc5 100644 --- a/markwon-image/src/main/java/ru/noties/markwon/image/gif/GifMediaDecoder.java +++ b/markwon-image/src/main/java/ru/noties/markwon/image/gif/GifMediaDecoder.java @@ -7,6 +7,8 @@ import android.support.annotation.Nullable; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; +import java.util.Collection; +import java.util.Collections; import pl.droidsonroids.gif.GifDrawable; import ru.noties.markwon.image.DrawableUtils; @@ -58,6 +60,12 @@ public class GifMediaDecoder extends MediaDecoder { return drawable; } + @NonNull + @Override + public Collection supportedTypes() { + return Collections.singleton(CONTENT_TYPE); + } + @NonNull protected GifDrawable newGifDrawable(@NonNull byte[] bytes) throws IOException { return new GifDrawable(bytes); diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/network/NetworkSchemeHandler.java b/markwon-image/src/main/java/ru/noties/markwon/image/network/NetworkSchemeHandler.java index c48d54d3..a9dbfaee 100644 --- a/markwon-image/src/main/java/ru/noties/markwon/image/network/NetworkSchemeHandler.java +++ b/markwon-image/src/main/java/ru/noties/markwon/image/network/NetworkSchemeHandler.java @@ -9,6 +9,8 @@ import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; +import java.util.Arrays; +import java.util.Collection; import ru.noties.markwon.image.ImageItem; import ru.noties.markwon.image.SchemeHandler; @@ -56,6 +58,12 @@ public class NetworkSchemeHandler extends SchemeHandler { return imageItem; } + @NonNull + @Override + public Collection supportedSchemes() { + return Arrays.asList(SCHEME_HTTP, SCHEME_HTTPS); + } + @Nullable static String contentType(@Nullable String contentType) { diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/network/OkHttpNetworkSchemeHandler.java b/markwon-image/src/main/java/ru/noties/markwon/image/network/OkHttpNetworkSchemeHandler.java index 0433fd13..7faec7e5 100644 --- a/markwon-image/src/main/java/ru/noties/markwon/image/network/OkHttpNetworkSchemeHandler.java +++ b/markwon-image/src/main/java/ru/noties/markwon/image/network/OkHttpNetworkSchemeHandler.java @@ -3,8 +3,9 @@ package ru.noties.markwon.image.network; import android.net.Uri; import android.support.annotation.NonNull; -import java.io.IOException; import java.io.InputStream; +import java.util.Arrays; +import java.util.Collection; import okhttp3.OkHttpClient; import okhttp3.Request; @@ -16,7 +17,7 @@ import ru.noties.markwon.image.SchemeHandler; /** * @since 4.0.0-SNAPSHOT */ -class OkHttpNetworkSchemeHandler extends SchemeHandler { +public class OkHttpNetworkSchemeHandler extends SchemeHandler { /** * @see #create(OkHttpClient) @@ -51,8 +52,8 @@ class OkHttpNetworkSchemeHandler extends SchemeHandler { final Response response; try { response = client.newCall(request).execute(); - } catch (IOException e) { - throw new IllegalStateException("Exception obtaining network resource: " + raw, e); + } catch (Throwable t) { + throw new IllegalStateException("Exception obtaining network resource: " + raw, t); } if (response == null) { @@ -68,8 +69,18 @@ class OkHttpNetworkSchemeHandler extends SchemeHandler { throw new IllegalStateException("Response does not contain body: " + raw); } - final String contentType = response.header(HEADER_CONTENT_TYPE); + // important to process content-type as it can have encoding specified (which we should remove) + final String contentType = + NetworkSchemeHandler.contentType(response.header(HEADER_CONTENT_TYPE)); return ImageItem.withDecodingNeeded(contentType, inputStream); } + + @NonNull + @Override + public Collection supportedSchemes() { + return Arrays.asList( + NetworkSchemeHandler.SCHEME_HTTP, + NetworkSchemeHandler.SCHEME_HTTPS); + } } diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/svg/SvgMediaDecoder.java b/markwon-image/src/main/java/ru/noties/markwon/image/svg/SvgMediaDecoder.java index cba9fb39..e9484a25 100644 --- a/markwon-image/src/main/java/ru/noties/markwon/image/svg/SvgMediaDecoder.java +++ b/markwon-image/src/main/java/ru/noties/markwon/image/svg/SvgMediaDecoder.java @@ -12,6 +12,8 @@ import com.caverock.androidsvg.SVG; import com.caverock.androidsvg.SVGParseException; import java.io.InputStream; +import java.util.Collection; +import java.util.Collections; import ru.noties.markwon.image.DrawableUtils; import ru.noties.markwon.image.MediaDecoder; @@ -71,4 +73,10 @@ public class SvgMediaDecoder extends MediaDecoder { DrawableUtils.applyIntrinsicBounds(drawable); return drawable; } + + @NonNull + @Override + public Collection supportedTypes() { + return Collections.singleton(CONTENT_TYPE); + } } diff --git a/sample/build.gradle b/sample/build.gradle index dbe4bdaa..649e3a8e 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -39,9 +39,7 @@ dependencies { implementation project(':markwon-ext-tables') implementation project(':markwon-ext-tasklist') implementation project(':markwon-html') - implementation project(':markwon-image-gif') - implementation project(':markwon-image-okhttp') - implementation project(':markwon-image-svg') + implementation project(':markwon-image') implementation project(':markwon-syntax-highlight') implementation project(':markwon-recycler') implementation project(':markwon-recycler-table') diff --git a/sample/src/main/java/ru/noties/markwon/sample/basicplugins/BasicPluginsActivity.java b/sample/src/main/java/ru/noties/markwon/sample/basicplugins/BasicPluginsActivity.java index 0728be6c..45f35cf8 100644 --- a/sample/src/main/java/ru/noties/markwon/sample/basicplugins/BasicPluginsActivity.java +++ b/sample/src/main/java/ru/noties/markwon/sample/basicplugins/BasicPluginsActivity.java @@ -22,10 +22,6 @@ import ru.noties.markwon.MarkwonVisitor; import ru.noties.markwon.movement.MovementMethodPlugin; import ru.noties.markwon.core.MarkwonTheme; import ru.noties.markwon.image.AsyncDrawableLoader; -import ru.noties.markwon.image.ImageItem; -import ru.noties.markwon.image.ImagesPlugin; -import ru.noties.markwon.image.SchemeHandler; -import ru.noties.markwon.image.network.NetworkSchemeHandler; public class BasicPluginsActivity extends Activity { diff --git a/sample/src/main/java/ru/noties/markwon/sample/customextension/CustomExtensionActivity.java b/sample/src/main/java/ru/noties/markwon/sample/customextension/CustomExtensionActivity.java index 4a9c2fd9..d2e80e18 100644 --- a/sample/src/main/java/ru/noties/markwon/sample/customextension/CustomExtensionActivity.java +++ b/sample/src/main/java/ru/noties/markwon/sample/customextension/CustomExtensionActivity.java @@ -6,7 +6,6 @@ import android.support.annotation.Nullable; import android.widget.TextView; import ru.noties.markwon.Markwon; -import ru.noties.markwon.image.ImagesPlugin; import ru.noties.markwon.sample.R; public class CustomExtensionActivity extends Activity { diff --git a/sample/src/main/java/ru/noties/markwon/sample/customextension/IconPlugin.java b/sample/src/main/java/ru/noties/markwon/sample/customextension/IconPlugin.java index 3de96315..cbd2348b 100644 --- a/sample/src/main/java/ru/noties/markwon/sample/customextension/IconPlugin.java +++ b/sample/src/main/java/ru/noties/markwon/sample/customextension/IconPlugin.java @@ -7,8 +7,6 @@ import org.commonmark.parser.Parser; import ru.noties.markwon.AbstractMarkwonPlugin; import ru.noties.markwon.MarkwonVisitor; -import ru.noties.markwon.image.ImagesPlugin; -import ru.noties.markwon.priority.Priority; public class IconPlugin extends AbstractMarkwonPlugin { diff --git a/sample/src/main/java/ru/noties/markwon/sample/latex/LatexActivity.java b/sample/src/main/java/ru/noties/markwon/sample/latex/LatexActivity.java index d4143a76..40da04f7 100644 --- a/sample/src/main/java/ru/noties/markwon/sample/latex/LatexActivity.java +++ b/sample/src/main/java/ru/noties/markwon/sample/latex/LatexActivity.java @@ -7,7 +7,6 @@ import android.widget.TextView; import ru.noties.markwon.Markwon; import ru.noties.markwon.ext.latex.JLatexMathPlugin; -import ru.noties.markwon.image.ImagesPlugin; import ru.noties.markwon.sample.R; public class LatexActivity extends Activity { diff --git a/sample/src/main/java/ru/noties/markwon/sample/recycler/RecyclerActivity.java b/sample/src/main/java/ru/noties/markwon/sample/recycler/RecyclerActivity.java index adeb6c4b..2bed0452 100644 --- a/sample/src/main/java/ru/noties/markwon/sample/recycler/RecyclerActivity.java +++ b/sample/src/main/java/ru/noties/markwon/sample/recycler/RecyclerActivity.java @@ -26,7 +26,6 @@ import ru.noties.markwon.MarkwonConfiguration; import ru.noties.markwon.MarkwonVisitor; import ru.noties.markwon.core.CorePlugin; import ru.noties.markwon.html.HtmlPlugin; -import ru.noties.markwon.image.ImagesPlugin; import ru.noties.markwon.image.svg.SvgPlugin; import ru.noties.markwon.recycler.MarkwonAdapter; import ru.noties.markwon.recycler.SimpleEntry; diff --git a/settings.gradle b/settings.gradle index 258291b4..f0568523 100644 --- a/settings.gradle +++ b/settings.gradle @@ -7,9 +7,6 @@ include ':app', ':sample', ':markwon-ext-tasklist', ':markwon-html', ':markwon-image', - ':markwon-image-gif', - ':markwon-image-okhttp', - ':markwon-image-svg', ':markwon-recycler', ':markwon-recycler-table', ':markwon-syntax-highlight', From 64af306e53228219fb5d6bc5a7b21df28f212af9 Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Tue, 28 May 2019 19:01:41 +0300 Subject: [PATCH 04/42] Fix test compilation --- .../markwon/AbstractMarkwonPluginTest.java | 17 +- .../markwon/MarkwonBuilderImplTest.java | 184 +------ .../noties/markwon/core/CorePluginTest.java | 7 - .../ru/noties/markwon/image/ImageTest.java | 3 - .../priority/PriorityProcessorTest.java | 494 ------------------ .../markwon/syntax/SyntaxHighlightTest.java | 3 +- markwon-image/build.gradle | 11 + .../markwon/image/data/DataUriParserTest.java | 0 .../image/data/DataUriSchemeHandlerTest.java | 56 +- 9 files changed, 63 insertions(+), 712 deletions(-) delete mode 100644 markwon-core/src/test/java/ru/noties/markwon/priority/PriorityProcessorTest.java rename {markwon-core => markwon-image}/src/test/java/ru/noties/markwon/image/data/DataUriParserTest.java (100%) rename {markwon-core => markwon-image}/src/test/java/ru/noties/markwon/image/data/DataUriSchemeHandlerTest.java (63%) diff --git a/markwon-core/src/test/java/ru/noties/markwon/AbstractMarkwonPluginTest.java b/markwon-core/src/test/java/ru/noties/markwon/AbstractMarkwonPluginTest.java index 2002a06d..7ee70ceb 100644 --- a/markwon-core/src/test/java/ru/noties/markwon/AbstractMarkwonPluginTest.java +++ b/markwon-core/src/test/java/ru/noties/markwon/AbstractMarkwonPluginTest.java @@ -5,27 +5,12 @@ import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -import java.util.List; - -import ru.noties.markwon.core.CorePlugin; - import static org.junit.Assert.assertEquals; @RunWith(RobolectricTestRunner.class) @Config(manifest = Config.NONE) public class AbstractMarkwonPluginTest { - - @Test - public void priority() { - // returns CorePlugin dependency - - final Priority priority = new AbstractMarkwonPlugin() { - }.priority(); - final List> after = priority.after(); - assertEquals(1, after.size()); - assertEquals(CorePlugin.class, after.get(0)); - } - + @Test public void process_markdown() { // returns supplied argument (no-op) diff --git a/markwon-core/src/test/java/ru/noties/markwon/MarkwonBuilderImplTest.java b/markwon-core/src/test/java/ru/noties/markwon/MarkwonBuilderImplTest.java index 43d115a4..fc4c73fc 100644 --- a/markwon-core/src/test/java/ru/noties/markwon/MarkwonBuilderImplTest.java +++ b/markwon-core/src/test/java/ru/noties/markwon/MarkwonBuilderImplTest.java @@ -1,6 +1,5 @@ package ru.noties.markwon; -import android.support.annotation.NonNull; import android.text.Spanned; import android.widget.TextView; @@ -8,183 +7,57 @@ import org.commonmark.node.Node; import org.commonmark.parser.Parser; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.ArgumentMatchers; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -import ru.noties.markwon.core.CorePlugin; import ru.noties.markwon.core.MarkwonTheme; import ru.noties.markwon.html.MarkwonHtmlRenderer; -import ru.noties.markwon.image.AsyncDrawableLoader; import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.hasItem; -import static org.hamcrest.Matchers.hasSize; -import static org.hamcrest.Matchers.isA; -import static org.hamcrest.Matchers.not; import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static ru.noties.markwon.MarkwonBuilderImpl.ensureImplicitCoreIfHasDependents; -import static ru.noties.markwon.MarkwonBuilderImpl.preparePlugins; @RunWith(RobolectricTestRunner.class) @Config(manifest = Config.NONE) public class MarkwonBuilderImplTest { - @Test - public void implicit_core_created() { - // a plugin explicitly requests CorePlugin, but CorePlugin is not added manually by user - // we validate that default CorePlugin instance is added - - final MarkwonPlugin plugin = new AbstractMarkwonPlugin() { - @NonNull - @Override - public Priority priority() { - // strictly speaking we do not need to override this method - // as all children of AbstractMarkwonPlugin specify CorePlugin as a dependency. - // but we still add it to make things explicit and future proof, if this - // behavior changes - return Priority.after(CorePlugin.class); - } - }; - - final List plugins = ensureImplicitCoreIfHasDependents(Collections.singletonList(plugin)); - - assertThat(plugins, hasSize(2)); - assertThat(plugins, hasItem(isA(CorePlugin.class))); - } - - @Test - public void implicit_core_no_dependents_not_added() { - final MarkwonPlugin a = new AbstractMarkwonPlugin() { - @NonNull - @Override - public Priority priority() { - return Priority.none(); - } - }; - - final MarkwonPlugin b = new AbstractMarkwonPlugin() { - @NonNull - @Override - public Priority priority() { - return Priority.after(a.getClass()); - } - }; - - final List plugins = ensureImplicitCoreIfHasDependents(Arrays.asList(a, b)); - assertThat(plugins, hasSize(2)); - assertThat(plugins, not(hasItem(isA(CorePlugin.class)))); - } - - @Test - public void implicit_core_present() { - // if core is present it won't be added (whether or not there are dependents) - - final MarkwonPlugin plugin = new AbstractMarkwonPlugin() { - @NonNull - @Override - public Priority priority() { - return Priority.after(CorePlugin.class); - } - }; - - final CorePlugin corePlugin = CorePlugin.create(); - - final List plugins = ensureImplicitCoreIfHasDependents(Arrays.asList(plugin, corePlugin)); - assertThat(plugins, hasSize(2)); - assertThat(plugins, hasItem(plugin)); - assertThat(plugins, hasItem(corePlugin)); - } - - @Test - public void implicit_core_subclass_present() { - // core was subclassed by a user and provided (implicit core won't be added) - - final MarkwonPlugin plugin = new AbstractMarkwonPlugin() { - @NonNull - @Override - public Priority priority() { - return Priority.after(CorePlugin.class); - } - }; - - // our subclass - final CorePlugin corePlugin = new CorePlugin() { - - }; - - final List plugins = ensureImplicitCoreIfHasDependents(Arrays.asList(plugin, corePlugin)); - assertThat(plugins, hasSize(2)); - assertThat(plugins, hasItem(plugin)); - assertThat(plugins, hasItem(corePlugin)); - } - @Test public void prepare_plugins() { // validate that prepare plugins is calling `ensureImplicitCoreIfHasDependents` and // priority processor - final PriorityProcessor priorityProcessor = mock(PriorityProcessor.class); - when(priorityProcessor.process(ArgumentMatchers.anyList())) - .thenAnswer(new Answer() { - @Override - public Object answer(InvocationOnMock invocation) { - return invocation.getArgument(0); - } - }); +// final PriorityProcessor priorityProcessor = mock(PriorityProcessor.class); +// when(priorityProcessor.process(ArgumentMatchers.anyList())) +// .thenAnswer(new Answer() { +// @Override +// public Object answer(InvocationOnMock invocation) { +// return invocation.getArgument(0); +// } +// }); +// +// final MarkwonPlugin plugin = new AbstractMarkwonPlugin() { +// @NonNull +// @Override +// public Priority priority() { +// return Priority.after(CorePlugin.class); +// } +// }; +// +// final List plugins = preparePlugins(priorityProcessor, Collections.singletonList(plugin)); +// assertThat(plugins, hasSize(2)); +// assertThat(plugins, hasItem(plugin)); +// assertThat(plugins, hasItem(isA(CorePlugin.class))); +// +// verify(priorityProcessor, times(1)) +// .process(ArgumentMatchers.anyList()); - final MarkwonPlugin plugin = new AbstractMarkwonPlugin() { - @NonNull - @Override - public Priority priority() { - return Priority.after(CorePlugin.class); - } - }; - - final List plugins = preparePlugins(priorityProcessor, Collections.singletonList(plugin)); - assertThat(plugins, hasSize(2)); - assertThat(plugins, hasItem(plugin)); - assertThat(plugins, hasItem(isA(CorePlugin.class))); - - verify(priorityProcessor, times(1)) - .process(ArgumentMatchers.anyList()); - } - - @Test - public void user_supplied_priority_processor() { - // verify that if user supplied priority processor it will be used - - final PriorityProcessor priorityProcessor = mock(PriorityProcessor.class); - final MarkwonBuilderImpl impl = new MarkwonBuilderImpl(RuntimeEnvironment.application); - - // add some plugin (we do not care which one, but it must be present as we do not - // allow empty plugins list) - impl.usePlugin(new AbstractMarkwonPlugin() { - @NonNull - @Override - public Priority priority() { - return Priority.none(); - } - }); - impl.priorityProcessor(priorityProcessor); - impl.build(); - - verify(priorityProcessor, times(1)).process(ArgumentMatchers.anyList()); + fail(); } @Test @@ -204,22 +77,19 @@ public class MarkwonBuilderImplTest { // verify that all configuration methods (applicable) are called final MarkwonPlugin plugin = mock(MarkwonPlugin.class); - when(plugin.priority()).thenReturn(Priority.none()); final MarkwonBuilderImpl impl = new MarkwonBuilderImpl(RuntimeEnvironment.application); impl.usePlugin(plugin).build(); + verify(plugin, times(1)).configure(any(MarkwonPlugin.Registry.class)); + verify(plugin, times(1)).configureParser(any(Parser.Builder.class)); verify(plugin, times(1)).configureTheme(any(MarkwonTheme.Builder.class)); - verify(plugin, times(1)).configureImages(any(AsyncDrawableLoader.Builder.class)); verify(plugin, times(1)).configureConfiguration(any(MarkwonConfiguration.Builder.class)); verify(plugin, times(1)).configureVisitor(any(MarkwonVisitor.Builder.class)); verify(plugin, times(1)).configureSpansFactory(any(MarkwonSpansFactory.Builder.class)); verify(plugin, times(1)).configureHtmlRenderer(any(MarkwonHtmlRenderer.Builder.class)); - // we do not know how many times exactly, but at least once it must be called - verify(plugin, atLeast(1)).priority(); - // note, no render props -> they must be configured on render stage verify(plugin, times(0)).processMarkdown(anyString()); verify(plugin, times(0)).beforeRender(any(Node.class)); diff --git a/markwon-core/src/test/java/ru/noties/markwon/core/CorePluginTest.java b/markwon-core/src/test/java/ru/noties/markwon/core/CorePluginTest.java index dd1d43cc..3a300cfb 100644 --- a/markwon-core/src/test/java/ru/noties/markwon/core/CorePluginTest.java +++ b/markwon-core/src/test/java/ru/noties/markwon/core/CorePluginTest.java @@ -191,13 +191,6 @@ public class CorePluginTest { assertEquals(impl.map.toString(), 0, impl.map.size()); } - @Test - public void priority_none() { - // CorePlugin returns none as priority (thus 0) - - assertEquals(0, CorePlugin.create().priority().after().size()); - } - @Test public void plugin_methods() { // checks that only expected plugin methods are overridden diff --git a/markwon-core/src/test/java/ru/noties/markwon/image/ImageTest.java b/markwon-core/src/test/java/ru/noties/markwon/image/ImageTest.java index 69391899..def53907 100644 --- a/markwon-core/src/test/java/ru/noties/markwon/image/ImageTest.java +++ b/markwon-core/src/test/java/ru/noties/markwon/image/ImageTest.java @@ -2,7 +2,6 @@ package ru.noties.markwon.image; import android.content.Context; import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import org.commonmark.node.Image; import org.junit.Test; @@ -18,7 +17,6 @@ import ru.noties.markwon.MarkwonSpansFactory; import ru.noties.markwon.RenderProps; import ru.noties.markwon.SpanFactory; import ru.noties.markwon.core.CorePlugin; -import ru.noties.markwon.core.MarkwonTheme; import ru.noties.markwon.test.TestSpan.Document; import ru.noties.markwon.test.TestSpanMatcher; @@ -39,7 +37,6 @@ public class ImageTest { final Context context = RuntimeEnvironment.application; final Markwon markwon = Markwon.builder(context) .usePlugin(CorePlugin.create()) - .usePlugin(new ImagesPlugin(context, false)) .usePlugin(new AbstractMarkwonPlugin() { @Override public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) { diff --git a/markwon-core/src/test/java/ru/noties/markwon/priority/PriorityProcessorTest.java b/markwon-core/src/test/java/ru/noties/markwon/priority/PriorityProcessorTest.java deleted file mode 100644 index 164f98a5..00000000 --- a/markwon-core/src/test/java/ru/noties/markwon/priority/PriorityProcessorTest.java +++ /dev/null @@ -1,494 +0,0 @@ -package ru.noties.markwon.priority; - -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; - -import ru.noties.markwon.AbstractMarkwonPlugin; -import ru.noties.markwon.MarkwonPlugin; -import ru.noties.markwon.core.CorePlugin; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -@RunWith(RobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class PriorityProcessorTest { - - private PriorityProcessor processor; - - @Before - public void before() { - processor = PriorityProcessor.create(); - } - - @Test - public void empty_list() { - final List plugins = Collections.emptyList(); - assertEquals(0, processor.process(plugins).size()); - } - - @Test - public void simple_two_plugins() { - - final MarkwonPlugin first = new AbstractMarkwonPlugin() { - @NonNull - @Override - public Priority priority() { - return Priority.none(); - } - }; - - final MarkwonPlugin second = new AbstractMarkwonPlugin() { - @NonNull - @Override - public Priority priority() { - return Priority.after(first.getClass()); - } - }; - - final List plugins = processor.process(Arrays.asList(second, first)); - - assertEquals(2, plugins.size()); - assertEquals(first, plugins.get(0)); - assertEquals(second, plugins.get(1)); - } - - @Test - public void plugin_after_self() { - - final MarkwonPlugin plugin = new AbstractMarkwonPlugin() { - @NonNull - @Override - public Priority priority() { - return Priority.after(getClass()); - } - }; - - try { - processor.process(Collections.singletonList(plugin)); - fail(); - } catch (IllegalStateException e) { - assertTrue(e.getMessage(), e.getMessage().contains("defined self as a dependency")); - } - } - - @Test - public void unsatisfied_dependency() { - - final MarkwonPlugin plugin = new AbstractMarkwonPlugin() { - @NonNull - @Override - public Priority priority() { - return Priority.after(ImagesPlugin.class); - } - }; - - try { - processor.process(Collections.singletonList(plugin)); - fail(); - } catch (IllegalStateException e) { - assertTrue(e.getMessage(), e.getMessage().contains("Markwon unsatisfied dependency found")); - } - } - - @Test - public void subclass_found() { - // when a plugin comes after another, but _another_ was subclassed and placed in the list - - final MarkwonPlugin core = new CorePlugin() { - }; - final MarkwonPlugin plugin = new AbstractMarkwonPlugin() { - @NonNull - @Override - public Priority priority() { - return Priority.after(CorePlugin.class); - } - }; - - final List plugins = processor.process(Arrays.asList(plugin, core)); - assertEquals(2, plugins.size()); - assertEquals(core, plugins.get(0)); - assertEquals(plugin, plugins.get(1)); - } - - @Test - public void three_plugins_sequential() { - - final MarkwonPlugin first = new AbstractMarkwonPlugin() { - @NonNull - @Override - public Priority priority() { - return Priority.none(); - } - }; - - final MarkwonPlugin second = new AbstractMarkwonPlugin() { - @NonNull - @Override - public Priority priority() { - return Priority.after(first.getClass()); - } - }; - - final MarkwonPlugin third = new AbstractMarkwonPlugin() { - @NonNull - @Override - public Priority priority() { - return Priority.after(second.getClass()); - } - }; - - final List plugins = processor.process(Arrays.asList(third, second, first)); - assertEquals(3, plugins.size()); - assertEquals(first, plugins.get(0)); - assertEquals(second, plugins.get(1)); - assertEquals(third, plugins.get(2)); - } - - @Test - public void five_plugins_sequential() { - - final MarkwonPlugin a = new NamedPlugin("a") { - }; - - final MarkwonPlugin b = new NamedPlugin("b", a) { - }; - - final MarkwonPlugin c = new NamedPlugin("c", b) { - }; - - final MarkwonPlugin d = new NamedPlugin("d", c) { - }; - - final MarkwonPlugin e = new NamedPlugin("e", d) { - }; - - final List plugins = processor.process(Arrays.asList(d, e, a, c, b)); - assertEquals(5, plugins.size()); - assertEquals(a, plugins.get(0)); - assertEquals(b, plugins.get(1)); - assertEquals(c, plugins.get(2)); - assertEquals(d, plugins.get(3)); - assertEquals(e, plugins.get(4)); - } - - @Test - public void plugin_duplicate() { - - final MarkwonPlugin plugin = new AbstractMarkwonPlugin() { - @NonNull - @Override - public Priority priority() { - return Priority.none(); - } - }; - - try { - processor.process(Arrays.asList(plugin, plugin)); - fail(); - } catch (IllegalStateException e) { - assertTrue(e.getMessage(), e.getMessage().contains("Markwon duplicate plugin found")); - } - } - - @Test - public void multiple_after_3() { - - final MarkwonPlugin a1 = new AbstractMarkwonPlugin() { - @NonNull - @Override - public Priority priority() { - return Priority.none(); - } - }; - - final MarkwonPlugin b1 = new AbstractMarkwonPlugin() { - @NonNull - @Override - public Priority priority() { - return Priority.after(a1.getClass()); - } - }; - - final MarkwonPlugin c1 = new AbstractMarkwonPlugin() { - @NonNull - @Override - public Priority priority() { - return Priority.after(a1.getClass(), b1.getClass()); - } - }; - - final List plugins = processor.process(Arrays.asList(c1, a1, b1)); - assertEquals(3, plugins.size()); - assertEquals(a1, plugins.get(0)); - assertEquals(b1, plugins.get(1)); - assertEquals(c1, plugins.get(2)); - } - - @Test - public void multiple_after_4() { - - final MarkwonPlugin a1 = new AbstractMarkwonPlugin() { - @NonNull - @Override - public Priority priority() { - return Priority.none(); - } - }; - - final MarkwonPlugin b1 = new AbstractMarkwonPlugin() { - @NonNull - @Override - public Priority priority() { - return Priority.after(a1.getClass()); - } - }; - - final MarkwonPlugin c1 = new AbstractMarkwonPlugin() { - @NonNull - @Override - public Priority priority() { - return Priority.after(a1.getClass(), b1.getClass()); - } - }; - - final MarkwonPlugin d1 = new AbstractMarkwonPlugin() { - @NonNull - @Override - public Priority priority() { - return Priority.builder() - .after(a1.getClass()) - .after(b1.getClass()) - .after(c1.getClass()) - .build(); - } - }; - - final List plugins = processor.process(Arrays.asList(c1, d1, a1, b1)); - assertEquals(4, plugins.size()); - assertEquals(a1, plugins.get(0)); - assertEquals(b1, plugins.get(1)); - assertEquals(c1, plugins.get(2)); - assertEquals(d1, plugins.get(3)); - } - - @Test - public void cycle() { - - final class Holder { - Class type; - } - final Holder holder = new Holder(); - - final MarkwonPlugin first = new AbstractMarkwonPlugin() { - @NonNull - @Override - public Priority priority() { - return Priority.after(holder.type); - } - }; - - final MarkwonPlugin second = new AbstractMarkwonPlugin() { - - { - holder.type = getClass(); - } - - @NonNull - @Override - public Priority priority() { - return Priority.after(first.getClass()); - } - }; - - try { - processor.process(Arrays.asList(second, first)); - fail(); - } catch (IllegalStateException e) { - assertTrue(e.getMessage(), e.getMessage().contains("being referenced by own dependency (cycle)")); - } - } - - @Test - public void bigger_cycle() { - - final class Plugin extends NamedPlugin { - - private Priority priority; - - private Plugin(@NonNull String name) { - super(name); - } - - private void set(@NonNull MarkwonPlugin plugin) { - priority = Priority.after(plugin.getClass()); - } - - @NonNull - @Override - public Priority priority() { - return priority; - } - } - - final Plugin a = new Plugin("a"); - - final List plugins = new ArrayList<>(); - plugins.add(a); - plugins.add(new NamedPlugin("b", plugins.get(plugins.size() - 1)) { - }); - plugins.add(new NamedPlugin("c", plugins.get(plugins.size() - 1)) { - }); - plugins.add(new NamedPlugin("d", plugins.get(plugins.size() - 1)) { - }); - plugins.add(new NamedPlugin("e", plugins.get(plugins.size() - 1)) { - }); - plugins.add(new NamedPlugin("f", plugins.get(plugins.size() - 1)) { - }); - plugins.add(new NamedPlugin("g", plugins.get(plugins.size() - 1)) { - }); - - // link with the last one - a.set(plugins.get(plugins.size() - 1)); - - try { - processor.process(plugins); - fail(); - } catch (IllegalStateException e) { - assertTrue(e.getMessage(), e.getMessage().contains("being referenced by own dependency (cycle)")); - } - } - - @Test - public void deep_tree() { - - // we must create subclasses in order to register them like this (otherwise -> duplicates) - final MarkwonPlugin a = new NamedPlugin("a") { - }; - final MarkwonPlugin b1 = new NamedPlugin("b1", a) { - }; - final MarkwonPlugin b2 = new NamedPlugin("b2", a) { - }; - final MarkwonPlugin c1 = new NamedPlugin("c1", b1) { - }; - final MarkwonPlugin c2 = new NamedPlugin("c2", b1) { - }; - final MarkwonPlugin c3 = new NamedPlugin("c3", b2) { - }; - final MarkwonPlugin c4 = new NamedPlugin("c4", b2) { - }; - final MarkwonPlugin d1 = new NamedPlugin("d1", c1) { - }; - final MarkwonPlugin e1 = new NamedPlugin("e1", d1, c2, c3, c4) { - }; - - final List plugins = processor.process(Arrays.asList(b2, b1, - a, e1, c4, c3, c2, c1, d1)); - - // a is first - // b1 + b2 -> second+third - // c1 + c2 + c3 + c4 -> forth, fifth, sixth, seventh - // d1 -> 8th - // e1 -> 9th - - assertEquals(9, plugins.size()); - assertEquals(a, plugins.get(0)); - assertEquals(new HashSet<>(Arrays.asList(b1, b2)), new HashSet<>(plugins.subList(1, 3))); - assertEquals(new HashSet<>(Arrays.asList(c1, c2, c3, c4)), new HashSet<>(plugins.subList(3, 7))); - assertEquals(d1, plugins.get(7)); - assertEquals(e1, plugins.get(8)); - } - - @Test - public void multiple_detached() { - - // when graph has independent elements that are not connected with each other - final MarkwonPlugin a0 = new NamedPlugin("a0") { - }; - final MarkwonPlugin a1 = new NamedPlugin("a1", a0) { - }; - final MarkwonPlugin a2 = new NamedPlugin("a2", a1) { - }; - - final MarkwonPlugin b0 = new NamedPlugin("b0") { - }; - final MarkwonPlugin b1 = new NamedPlugin("b1", b0) { - }; - final MarkwonPlugin b2 = new NamedPlugin("b2", b1) { - }; - - final List plugins = processor.process(Arrays.asList( - b2, a2, a0, b0, b1, a1)); - - assertEquals(6, plugins.size()); - - assertEquals(new HashSet<>(Arrays.asList(a0, b0)), new HashSet<>(plugins.subList(0, 2))); - assertEquals(new HashSet<>(Arrays.asList(a1, b1)), new HashSet<>(plugins.subList(2, 4))); - assertEquals(new HashSet<>(Arrays.asList(a2, b2)), new HashSet<>(plugins.subList(4, 6))); - } - - private static abstract class NamedPlugin extends AbstractMarkwonPlugin { - - private final String name; - private final Priority priority; - - NamedPlugin(@NonNull String name) { - this(name, (Priority) null); - } - - NamedPlugin(@NonNull String name, @Nullable MarkwonPlugin plugin) { - this(name, plugin != null ? Priority.after(plugin.getClass()) : null); - } - - NamedPlugin(@NonNull String name, MarkwonPlugin... plugins) { - this(name, of(plugins)); - } - - NamedPlugin(@NonNull String name, @Nullable Class plugin) { - this(name, plugin != null ? Priority.after(plugin) : null); - } - - NamedPlugin(@NonNull String name, @Nullable Priority priority) { - this.name = name; - this.priority = priority; - } - - @NonNull - @Override - public Priority priority() { - return priority != null - ? priority - : Priority.none(); - } - - @Override - public String toString() { - return "NamedPlugin{" + - "name='" + name + '\'' + - '}'; - } - - @NonNull - private static Priority of(@NonNull MarkwonPlugin... plugins) { - if (plugins.length == 0) return Priority.none(); - final Priority.Builder builder = Priority.builder(); - for (MarkwonPlugin plugin : plugins) { - builder.after(plugin.getClass()); - } - return builder.build(); - } - } -} \ No newline at end of file diff --git a/markwon-core/src/test/java/ru/noties/markwon/syntax/SyntaxHighlightTest.java b/markwon-core/src/test/java/ru/noties/markwon/syntax/SyntaxHighlightTest.java index 9c0262bb..68fa8a12 100644 --- a/markwon-core/src/test/java/ru/noties/markwon/syntax/SyntaxHighlightTest.java +++ b/markwon-core/src/test/java/ru/noties/markwon/syntax/SyntaxHighlightTest.java @@ -27,7 +27,6 @@ import ru.noties.markwon.SpannableBuilder; import ru.noties.markwon.core.CorePluginBridge; import ru.noties.markwon.core.MarkwonTheme; import ru.noties.markwon.html.MarkwonHtmlRenderer; -import ru.noties.markwon.image.AsyncDrawableLoader; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -84,7 +83,7 @@ public class SyntaxHighlightTest { final MarkwonConfiguration configuration = MarkwonConfiguration.builder() .syntaxHighlight(highlight) - .build(mock(MarkwonTheme.class), mock(AsyncDrawableLoader.class), mock(MarkwonHtmlRenderer.class), spansFactory); + .build(mock(MarkwonTheme.class), mock(MarkwonHtmlRenderer.class), spansFactory); final Map, MarkwonVisitor.NodeVisitor> visitorMap = Collections.emptyMap(); diff --git a/markwon-image/build.gradle b/markwon-image/build.gradle index 86fac312..2e0c86dd 100644 --- a/markwon-image/build.gradle +++ b/markwon-image/build.gradle @@ -22,6 +22,17 @@ dependencies { compileOnly it['android-svg'] compileOnly it['okhttp'] } + + deps['test'].with { + + testImplementation project(':markwon-test-span') + + testImplementation it['junit'] + testImplementation it['robolectric'] + testImplementation it['mockito'] + + testImplementation it['commons-io'] + } } registerArtifact(this) \ No newline at end of file diff --git a/markwon-core/src/test/java/ru/noties/markwon/image/data/DataUriParserTest.java b/markwon-image/src/test/java/ru/noties/markwon/image/data/DataUriParserTest.java similarity index 100% rename from markwon-core/src/test/java/ru/noties/markwon/image/data/DataUriParserTest.java rename to markwon-image/src/test/java/ru/noties/markwon/image/data/DataUriParserTest.java diff --git a/markwon-core/src/test/java/ru/noties/markwon/image/data/DataUriSchemeHandlerTest.java b/markwon-image/src/test/java/ru/noties/markwon/image/data/DataUriSchemeHandlerTest.java similarity index 63% rename from markwon-core/src/test/java/ru/noties/markwon/image/data/DataUriSchemeHandlerTest.java rename to markwon-image/src/test/java/ru/noties/markwon/image/data/DataUriSchemeHandlerTest.java index 82c571f7..6cb64cd2 100644 --- a/markwon-core/src/test/java/ru/noties/markwon/image/data/DataUriSchemeHandlerTest.java +++ b/markwon-image/src/test/java/ru/noties/markwon/image/data/DataUriSchemeHandlerTest.java @@ -14,9 +14,11 @@ import java.util.HashMap; import java.util.Map; import java.util.Scanner; +import ru.noties.markwon.image.ImageItem; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; @RunWith(RobolectricTestRunner.class) @Config(manifest = Config.NONE) @@ -31,17 +33,29 @@ public class DataUriSchemeHandlerTest { @Test public void scheme_specific_part_is_empty() { - assertNull(handler.handle("data:", Uri.parse("data:"))); + try { + handler.handle("data:", Uri.parse("data:")); + } catch (Throwable t) { + assertTrue(t.getMessage(), t.getMessage().contains("Invalid data-uri")); + } } @Test public void data_uri_is_empty() { - assertNull(handler.handle("data://whatever", Uri.parse("data://whatever"))); + try { + handler.handle("data:whatever", Uri.parse("data:whatever")); + } catch (Throwable t) { + assertTrue(t.getMessage(), t.getMessage().contains("Invalid data-uri")); + } } @Test public void no_data() { - assertNull(handler.handle("data://,", Uri.parse("data://,"))); + try { + handler.handle("data:,", Uri.parse("data:,")); + } catch (Throwable t) { + assertTrue(t.getMessage(), t.getMessage().contains("Decoding data-uri failed")); + } } @Test @@ -58,33 +72,6 @@ public class DataUriSchemeHandlerTest { } } - final Map expected = new HashMap() {{ - put("data://text/plain;,123", new Item("text/plain", "123")); - put("data://image/svg+xml;base64,MTIz", new Item("image/svg+xml", "123")); - }}; - - for (Map.Entry entry : expected.entrySet()) { - final ImageItem item = handler.handle(entry.getKey(), Uri.parse(entry.getKey())); - assertNotNull(entry.getKey(), item); - assertEquals(entry.getKey(), entry.getValue().contentType, item.contentType()); - assertEquals(entry.getKey(), entry.getValue().data, readStream(item.inputStream())); - } - } - - @Test - public void correct_real() { - - final class Item { - - final String contentType; - final String data; - - Item(String contentType, String data) { - this.contentType = contentType; - this.data = data; - } - } - final Map expected = new HashMap() {{ put("data:text/plain;,123", new Item("text/plain", "123")); put("data:image/svg+xml;base64,MTIz", new Item("image/svg+xml", "123")); @@ -93,8 +80,11 @@ public class DataUriSchemeHandlerTest { for (Map.Entry entry : expected.entrySet()) { final ImageItem item = handler.handle(entry.getKey(), Uri.parse(entry.getKey())); assertNotNull(entry.getKey(), item); - assertEquals(entry.getKey(), entry.getValue().contentType, item.contentType()); - assertEquals(entry.getKey(), entry.getValue().data, readStream(item.inputStream())); + assertTrue(item.hasDecodingNeeded()); + + final ImageItem.WithDecodingNeeded withDecodingNeeded = item.getAsWithDecodingNeeded(); + assertEquals(entry.getKey(), entry.getValue().contentType, withDecodingNeeded.contentType()); + assertEquals(entry.getKey(), entry.getValue().data, readStream(withDecodingNeeded.inputStream())); } } From e35d3ad04436da6924a595f256790061c27baeac Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Wed, 29 May 2019 13:41:40 +0300 Subject: [PATCH 05/42] Update jlatex plugin to be independent of images --- _CHANGES.md | 6 +- .../markwon/image/AsyncDrawableScheduler.java | 97 +++++---- markwon-core/src/main/res/values/ids.xml | 1 + .../markwon/AbstractMarkwonPluginTest.java | 2 +- markwon-ext-latex/build.gradle | 1 + .../markwon/ext/latex/JLatexMathPlugin.java | 202 ++++++++++++------ sample/build.gradle | 1 + .../basicplugins/BasicPluginsActivity.java | 41 ++-- .../CustomExtensionActivity.java | 2 +- .../sample/customextension/IconPlugin.java | 12 +- .../markwon/sample/latex/LatexActivity.java | 2 +- .../sample/recycler/RecyclerActivity.java | 15 +- 12 files changed, 230 insertions(+), 152 deletions(-) diff --git a/_CHANGES.md b/_CHANGES.md index b1bb22c8..3a63fbbe 100644 --- a/_CHANGES.md +++ b/_CHANGES.md @@ -1,2 +1,6 @@ * `Markwon.builder` won't require CorePlugin registration (it is done automatically) - to create a builder without CorePlugin - use `Markwon#builderNoCore` \ No newline at end of file + to create a builder without CorePlugin - use `Markwon#builderNoCore` +* `JLatex` plugin now is not dependent on ImagesPlugin + also accepts a ExecutorService (optional, by default cachedThreadPool is used) +* AsyncDrawableScheduler now can be called by multiple plugins without penalty + internally caches latest state and skips scheduling if drawables are already processed \ No newline at end of file diff --git a/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableScheduler.java b/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableScheduler.java index 0093abed..dd1735cf 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableScheduler.java +++ b/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableScheduler.java @@ -5,23 +5,37 @@ import android.graphics.drawable.Drawable; import android.os.Looper; import android.os.SystemClock; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.text.Spanned; -import android.text.style.DynamicDrawableSpan; import android.view.View; import android.widget.TextView; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - import ru.noties.markwon.renderer.R; public abstract class AsyncDrawableScheduler { public static void schedule(@NonNull final TextView textView) { - final List list = extract(textView); - if (list.size() > 0) { + // we need a simple check if current text has already scheduled drawables + // we need this in order to allow multiple calls to schedule (different plugins + // might use AsyncDrawable), but we do not want to repeat the task + // + // hm... we need the same thing for unschedule then... we can check if last hash is !null, + // if it's not -> unschedule, else ignore + + final Integer lastTextHashCode = + (Integer) textView.getTag(R.id.markwon_drawables_scheduler_last_text_hashcode); + final int textHashCode = textView.getText().hashCode(); + if (lastTextHashCode != null + && lastTextHashCode == textHashCode) { + return; + } + textView.setTag(R.id.markwon_drawables_scheduler_last_text_hashcode, textHashCode); + + + final AsyncDrawableSpan[] spans = extractSpans(textView); + if (spans != null + && spans.length > 0) { if (textView.getTag(R.id.markwon_drawables_scheduler) == null) { final View.OnAttachStateChangeListener listener = new View.OnAttachStateChangeListener() { @@ -41,7 +55,10 @@ public abstract class AsyncDrawableScheduler { textView.setTag(R.id.markwon_drawables_scheduler, listener); } - for (AsyncDrawable drawable : list) { + AsyncDrawable drawable; + + for (AsyncDrawableSpan span : spans) { + drawable = span.getDrawable(); drawable.setCallback2(new DrawableCallbackImpl(textView, drawable.getBounds())); } } @@ -49,57 +66,39 @@ public abstract class AsyncDrawableScheduler { // must be called when text manually changed in TextView public static void unschedule(@NonNull TextView view) { - for (AsyncDrawable drawable : extract(view)) { - drawable.setCallback2(null); + + if (view.getTag(R.id.markwon_drawables_scheduler_last_text_hashcode) == null) { + return; + } + view.setTag(R.id.markwon_drawables_scheduler_last_text_hashcode, null); + + + final AsyncDrawableSpan[] spans = extractSpans(view); + if (spans != null + && spans.length > 0) { + for (AsyncDrawableSpan span : spans) { + span.getDrawable().setCallback2(null); + } } } - private static List extract(@NonNull TextView view) { + @Nullable + private static AsyncDrawableSpan[] extractSpans(@NonNull TextView textView) { - final List list; - - final CharSequence cs = view.getText(); + final CharSequence cs = textView.getText(); final int length = cs != null ? cs.length() : 0; - if (length == 0 || !(cs instanceof Spanned)) { - //noinspection unchecked - list = Collections.EMPTY_LIST; - } else { - - final List drawables = new ArrayList<>(2); - - final Spanned spanned = (Spanned) cs; - final AsyncDrawableSpan[] asyncDrawableSpans = spanned.getSpans(0, length, AsyncDrawableSpan.class); - if (asyncDrawableSpans != null - && asyncDrawableSpans.length > 0) { - for (AsyncDrawableSpan span : asyncDrawableSpans) { - drawables.add(span.getDrawable()); - } - } - - final DynamicDrawableSpan[] dynamicDrawableSpans = spanned.getSpans(0, length, DynamicDrawableSpan.class); - if (dynamicDrawableSpans != null - && dynamicDrawableSpans.length > 0) { - for (DynamicDrawableSpan span : dynamicDrawableSpans) { - final Drawable d = span.getDrawable(); - if (d != null - && d instanceof AsyncDrawable) { - drawables.add((AsyncDrawable) d); - } - } - } - - if (drawables.size() == 0) { - //noinspection unchecked - list = Collections.EMPTY_LIST; - } else { - list = drawables; - } + if (length == 0 + || !(cs instanceof Spanned)) { + return null; } - return list; + // we also could've tried the `nextSpanTransition`, but strangely it leads to worse performance + // then direct getSpans + + return ((Spanned) cs).getSpans(0, length, AsyncDrawableSpan.class); } private AsyncDrawableScheduler() { diff --git a/markwon-core/src/main/res/values/ids.xml b/markwon-core/src/main/res/values/ids.xml index 90fb8322..31a4445d 100644 --- a/markwon-core/src/main/res/values/ids.xml +++ b/markwon-core/src/main/res/values/ids.xml @@ -2,5 +2,6 @@ + \ No newline at end of file diff --git a/markwon-core/src/test/java/ru/noties/markwon/AbstractMarkwonPluginTest.java b/markwon-core/src/test/java/ru/noties/markwon/AbstractMarkwonPluginTest.java index 7ee70ceb..025af005 100644 --- a/markwon-core/src/test/java/ru/noties/markwon/AbstractMarkwonPluginTest.java +++ b/markwon-core/src/test/java/ru/noties/markwon/AbstractMarkwonPluginTest.java @@ -10,7 +10,7 @@ import static org.junit.Assert.assertEquals; @RunWith(RobolectricTestRunner.class) @Config(manifest = Config.NONE) public class AbstractMarkwonPluginTest { - + @Test public void process_markdown() { // returns supplied argument (no-op) diff --git a/markwon-ext-latex/build.gradle b/markwon-ext-latex/build.gradle index 7cd28127..da8a9971 100644 --- a/markwon-ext-latex/build.gradle +++ b/markwon-ext-latex/build.gradle @@ -16,6 +16,7 @@ android { dependencies { api project(':markwon-core') + api project(':markwon-image') api deps['jlatexmath-android'] } diff --git a/markwon-ext-latex/src/main/java/ru/noties/markwon/ext/latex/JLatexMathPlugin.java b/markwon-ext-latex/src/main/java/ru/noties/markwon/ext/latex/JLatexMathPlugin.java index 9a09679d..ee28e04e 100644 --- a/markwon-ext-latex/src/main/java/ru/noties/markwon/ext/latex/JLatexMathPlugin.java +++ b/markwon-ext-latex/src/main/java/ru/noties/markwon/ext/latex/JLatexMathPlugin.java @@ -1,24 +1,31 @@ package ru.noties.markwon.ext.latex; import android.graphics.drawable.Drawable; -import android.net.Uri; +import android.os.Handler; +import android.os.Looper; +import android.os.SystemClock; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.Px; +import android.text.Spanned; +import android.widget.TextView; -import org.commonmark.node.Image; import org.commonmark.parser.Parser; -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.io.UnsupportedEncodingException; -import java.util.Scanner; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; import ru.noties.jlatexmath.JLatexMathDrawable; import ru.noties.markwon.AbstractMarkwonPlugin; +import ru.noties.markwon.MarkwonConfiguration; import ru.noties.markwon.MarkwonVisitor; -import ru.noties.markwon.RenderProps; +import ru.noties.markwon.image.AsyncDrawable; import ru.noties.markwon.image.AsyncDrawableLoader; +import ru.noties.markwon.image.AsyncDrawableScheduler; +import ru.noties.markwon.image.AsyncDrawableSpan; import ru.noties.markwon.image.ImageSize; /** @@ -65,27 +72,29 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin { private final int padding; + // @since 4.0.0-SNAPSHOT + private final ExecutorService executorService; + Config(@NonNull Builder builder) { this.textSize = builder.textSize; this.background = builder.background; this.align = builder.align; this.fitCanvas = builder.fitCanvas; this.padding = builder.padding; + + // @since 4.0.0-SNAPSHOT + ExecutorService executorService = builder.executorService; + if (executorService == null) { + executorService = Executors.newCachedThreadPool(); + } + this.executorService = executorService; } } - @NonNull - public static String makeDestination(@NonNull String latex) { - return SCHEME + "://" + latex; - } - - private static final String SCHEME = "jlatexmath"; - private static final String CONTENT_TYPE = "text/jlatexmath"; - - private final Config config; + private final JLatextAsyncDrawableLoader jLatextAsyncDrawableLoader; JLatexMathPlugin(@NonNull Config config) { - this.config = config; + this.jLatextAsyncDrawableLoader = new JLatextAsyncDrawableLoader(config); } @Override @@ -102,70 +111,36 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin { final String latex = jLatexMathBlock.latex(); final int length = visitor.length(); + visitor.builder().append(latex); - final RenderProps renderProps = visitor.renderProps(); + final MarkwonConfiguration configuration = visitor.configuration(); - ImageProps.DESTINATION.set(renderProps, makeDestination(latex)); - ImageProps.REPLACEMENT_TEXT_IS_LINK.set(renderProps, false); - ImageProps.IMAGE_SIZE.set(renderProps, new ImageSize(new ImageSize.Dimension(100, "%"), null)); + final AsyncDrawableSpan span = new AsyncDrawableSpan( + configuration.theme(), + new AsyncDrawable( + latex, + jLatextAsyncDrawableLoader, + configuration.imageSizeResolver(), + new ImageSize( + new ImageSize.Dimension(100, "%"), + null)), + AsyncDrawableSpan.ALIGN_BOTTOM, + false); - visitor.setSpansForNode(Image.class, length); + visitor.setSpans(length, span); } }); } @Override - public void configureImages(@NonNull AsyncDrawableLoader.Builder builder) { - builder - .addSchemeHandler(SCHEME, new SchemeHandler() { - @Nullable - @Override - public ImageItem handle(@NonNull String raw, @NonNull Uri uri) { - - ImageItem item = null; - - try { - final byte[] bytes = raw.substring(SCHEME.length()).getBytes("UTF-8"); - item = new ImageItem( - CONTENT_TYPE, - new ByteArrayInputStream(bytes)); - } catch (UnsupportedEncodingException e) { - e.printStackTrace(); - } - - return item; - } - }) - .addMediaDecoder(CONTENT_TYPE, new MediaDecoder() { - @Nullable - @Override - public Drawable decode(@NonNull InputStream inputStream) { - - final Scanner scanner = new Scanner(inputStream, "UTF-8").useDelimiter("\\A"); - final String latex = scanner.hasNext() - ? scanner.next() - : null; - - if (latex == null) { - return null; - } - - return JLatexMathDrawable.builder(latex) - .textSize(config.textSize) - .background(config.background) - .align(config.align) - .fitCanvas(config.fitCanvas) - .padding(config.padding) - .build(); - } - }); + public void beforeSetText(@NonNull TextView textView, @NonNull Spanned markdown) { + AsyncDrawableScheduler.unschedule(textView); } - @NonNull @Override - public Priority priority() { - return Priority.after(ImagesPlugin.class); + public void afterSetText(@NonNull TextView textView) { + AsyncDrawableScheduler.schedule(textView); } public static class Builder { @@ -181,6 +156,9 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin { private int padding; + // @since 4.0.0-SNAPSHOT + private ExecutorService executorService; + Builder(float textSize) { this.textSize = textSize; } @@ -209,9 +187,95 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin { return this; } + /** + * @since 4.0.0-SNAPSHOT + */ + @NonNull + public Builder executorService(@NonNull ExecutorService executorService) { + this.executorService = executorService; + return this; + } + @NonNull public Config build() { return new Config(this); } } + + // @since 4.0.0-SNAPSHOT + private static class JLatextAsyncDrawableLoader extends AsyncDrawableLoader { + + private final Config config; + private final Handler handler = new Handler(Looper.getMainLooper()); + private final Map> cache = new HashMap<>(3); + + JLatextAsyncDrawableLoader(@NonNull Config config) { + this.config = config; + } + + @Override + public void load(@NonNull final AsyncDrawable drawable) { + + // this method must be called from main-thread only (thus synchronization can be skipped) + + // check for currently running tasks associated with provided drawable + final Future future = cache.get(drawable); + + // if it's present -> proceed with new execution + // as asyncDrawable is immutable, it won't have destination changed (so there is no need + // to cancel any started tasks) + if (future == null) { + + cache.put(drawable, config.executorService.submit(new Runnable() { + @Override + public void run() { + + // create JLatexMathDrawable + final JLatexMathDrawable jLatexMathDrawable = + JLatexMathDrawable.builder(drawable.getDestination()) + .textSize(config.textSize) + .background(config.background) + .align(config.align) + .fitCanvas(config.fitCanvas) + .padding(config.padding) + .build(); + + // we must post to handler, but also have a way to identify the drawable + // for which we are posting (in case of cancellation) + handler.postAtTime(new Runnable() { + @Override + public void run() { + // remove entry from cache (it will be present if task is not cancelled) + if (cache.remove(drawable) != null + && drawable.isAttached()) { + drawable.setResult(jLatexMathDrawable); + } + + } + }, drawable, SystemClock.uptimeMillis()); + } + })); + } + } + + @Override + public void cancel(@NonNull AsyncDrawable drawable) { + + // this method also must be called from main thread only + + final Future future = cache.remove(drawable); + if (future != null) { + future.cancel(true); + } + + // remove all callbacks (via runnable) and messages posted for this drawable + handler.removeCallbacksAndMessages(drawable); + } + + @Nullable + @Override + public Drawable placeholder(@NonNull AsyncDrawable drawable) { + return null; + } + } } diff --git a/sample/build.gradle b/sample/build.gradle index 649e3a8e..a16436b9 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -50,6 +50,7 @@ dependencies { implementation it['prism4j'] implementation it['debug'] implementation it['adapt'] + implementation it['android-svg'] } deps['annotationProcessor'].with { diff --git a/sample/src/main/java/ru/noties/markwon/sample/basicplugins/BasicPluginsActivity.java b/sample/src/main/java/ru/noties/markwon/sample/basicplugins/BasicPluginsActivity.java index 45f35cf8..98596972 100644 --- a/sample/src/main/java/ru/noties/markwon/sample/basicplugins/BasicPluginsActivity.java +++ b/sample/src/main/java/ru/noties/markwon/sample/basicplugins/BasicPluginsActivity.java @@ -19,9 +19,8 @@ import ru.noties.markwon.MarkwonConfiguration; import ru.noties.markwon.MarkwonPlugin; import ru.noties.markwon.MarkwonSpansFactory; import ru.noties.markwon.MarkwonVisitor; -import ru.noties.markwon.movement.MovementMethodPlugin; import ru.noties.markwon.core.MarkwonTheme; -import ru.noties.markwon.image.AsyncDrawableLoader; +import ru.noties.markwon.movement.MovementMethodPlugin; public class BasicPluginsActivity extends Activity { @@ -168,25 +167,25 @@ public class BasicPluginsActivity extends Activity { final String markdown = "![image](myownscheme://en.wikipedia.org/static/images/project-logos/enwiki-2x.png)"; final Markwon markwon = Markwon.builder(this) - .usePlugin(ImagesPlugin.create(this)) - .usePlugin(new AbstractMarkwonPlugin() { - @Override - public void configureImages(@NonNull AsyncDrawableLoader.Builder builder) { - // we can have a custom SchemeHandler - // here we will just use networkSchemeHandler to redirect call - builder.addSchemeHandler("myownscheme", new SchemeHandler() { - - final NetworkSchemeHandler networkSchemeHandler = NetworkSchemeHandler.create(); - - @Nullable - @Override - public ImageItem handle(@NonNull String raw, @NonNull Uri uri) { - raw = raw.replace("myownscheme", "https"); - return networkSchemeHandler.handle(raw, Uri.parse(raw)); - } - }); - } - }) +// .usePlugin(ImagesPlugin.create(this)) +// .usePlugin(new AbstractMarkwonPlugin() { +// @Override +// public void configureImages(@NonNull AsyncDrawableLoader.Builder builder) { +// // we can have a custom SchemeHandler +// // here we will just use networkSchemeHandler to redirect call +// builder.addSchemeHandler("myownscheme", new SchemeHandler() { +// +// final NetworkSchemeHandler networkSchemeHandler = NetworkSchemeHandler.create(); +// +// @Nullable +// @Override +// public ImageItem handle(@NonNull String raw, @NonNull Uri uri) { +// raw = raw.replace("myownscheme", "https"); +// return networkSchemeHandler.handle(raw, Uri.parse(raw)); +// } +// }); +// } +// }) .build(); markwon.setMarkdown(textView, markdown); diff --git a/sample/src/main/java/ru/noties/markwon/sample/customextension/CustomExtensionActivity.java b/sample/src/main/java/ru/noties/markwon/sample/customextension/CustomExtensionActivity.java index d2e80e18..71e592c6 100644 --- a/sample/src/main/java/ru/noties/markwon/sample/customextension/CustomExtensionActivity.java +++ b/sample/src/main/java/ru/noties/markwon/sample/customextension/CustomExtensionActivity.java @@ -26,7 +26,7 @@ public class CustomExtensionActivity extends Activity { // `usePlugin` call final Markwon markwon = Markwon.builder(this) // try commenting out this line to see runtime dependency resolution - .usePlugin(ImagesPlugin.create(this)) +// .usePlugin(ImagesPlugin.create(this)) .usePlugin(IconPlugin.create(IconSpanProvider.create(this, 0))) .build(); diff --git a/sample/src/main/java/ru/noties/markwon/sample/customextension/IconPlugin.java b/sample/src/main/java/ru/noties/markwon/sample/customextension/IconPlugin.java index cbd2348b..42b7c8d8 100644 --- a/sample/src/main/java/ru/noties/markwon/sample/customextension/IconPlugin.java +++ b/sample/src/main/java/ru/noties/markwon/sample/customextension/IconPlugin.java @@ -21,12 +21,12 @@ public class IconPlugin extends AbstractMarkwonPlugin { this.iconSpanProvider = iconSpanProvider; } - @NonNull - @Override - public Priority priority() { - // define images dependency - return Priority.after(ImagesPlugin.class); - } +// @NonNull +// @Override +// public Priority priority() { +// // define images dependency +// return Priority.after(ImagesPlugin.class); +// } @Override public void configureParser(@NonNull Parser.Builder builder) { diff --git a/sample/src/main/java/ru/noties/markwon/sample/latex/LatexActivity.java b/sample/src/main/java/ru/noties/markwon/sample/latex/LatexActivity.java index 40da04f7..ec4cd397 100644 --- a/sample/src/main/java/ru/noties/markwon/sample/latex/LatexActivity.java +++ b/sample/src/main/java/ru/noties/markwon/sample/latex/LatexActivity.java @@ -42,7 +42,7 @@ public class LatexActivity extends Activity { + latex + "$$\n\n something like **this**"; final Markwon markwon = Markwon.builder(this) - .usePlugin(ImagesPlugin.create(this)) +// .usePlugin(ImagesPlugin.create(this)) .usePlugin(JLatexMathPlugin.create(textView.getTextSize())) .build(); diff --git a/sample/src/main/java/ru/noties/markwon/sample/recycler/RecyclerActivity.java b/sample/src/main/java/ru/noties/markwon/sample/recycler/RecyclerActivity.java index 2bed0452..7b7cc091 100644 --- a/sample/src/main/java/ru/noties/markwon/sample/recycler/RecyclerActivity.java +++ b/sample/src/main/java/ru/noties/markwon/sample/recycler/RecyclerActivity.java @@ -26,7 +26,11 @@ import ru.noties.markwon.MarkwonConfiguration; import ru.noties.markwon.MarkwonVisitor; import ru.noties.markwon.core.CorePlugin; import ru.noties.markwon.html.HtmlPlugin; -import ru.noties.markwon.image.svg.SvgPlugin; +import ru.noties.markwon.image.DefaultImageMediaDecoder; +import ru.noties.markwon.image.ImagesPlugin; +import ru.noties.markwon.image.file.FileSchemeHandler; +import ru.noties.markwon.image.network.OkHttpNetworkSchemeHandler; +import ru.noties.markwon.image.svg.SvgMediaDecoder; import ru.noties.markwon.recycler.MarkwonAdapter; import ru.noties.markwon.recycler.SimpleEntry; import ru.noties.markwon.recycler.table.TableEntry; @@ -73,8 +77,13 @@ public class RecyclerActivity extends Activity { private static Markwon markwon(@NonNull Context context) { return Markwon.builder(context) .usePlugin(CorePlugin.create()) - .usePlugin(ImagesPlugin.createWithAssets(context)) - .usePlugin(SvgPlugin.create(context.getResources())) + .usePlugin(ImagesPlugin.create(plugin -> { + plugin + .addSchemeHandler(FileSchemeHandler.createWithAssets(context.getAssets())) + .addSchemeHandler(OkHttpNetworkSchemeHandler.create()) + .addMediaDecoder(SvgMediaDecoder.create()) + .defaultMediaDecoder(DefaultImageMediaDecoder.create()); + })) // important to use TableEntryPlugin instead of TablePlugin .usePlugin(TableEntryPlugin.create(context)) .usePlugin(HtmlPlugin.create()) From 19091b5675006d74ed407b210ecfa379a4c46952 Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Wed, 29 May 2019 17:44:05 +0300 Subject: [PATCH 06/42] Add image loading plugin based on picasso library --- build.gradle | 3 +- .../ru/noties/markwon/core/CorePlugin.java | 52 +++++ .../noties/markwon/image/AsyncDrawable.java | 18 +- .../markwon/image/AsyncDrawableScheduler.java | 2 + .../markwon/image/ImageSpanFactory.java | 0 markwon-image-picasso/build.gradle | 21 +++ markwon-image-picasso/gradle.properties | 4 + .../src/main/AndroidManifest.xml | 1 + .../image/picasso/PicassoImagesPlugin.java | 177 ++++++++++++++++++ .../image/AsyncDrawableLoaderBuilder.java | 12 +- .../ru/noties/markwon/image/ImagesPlugin.java | 50 ----- .../markwon/image/file/FileSchemeHandler.java | 11 ++ sample/build.gradle | 2 + .../sample/recycler/RecyclerActivity.java | 26 +-- settings.gradle | 1 + 15 files changed, 311 insertions(+), 69 deletions(-) rename {markwon-image => markwon-core}/src/main/java/ru/noties/markwon/image/ImageSpanFactory.java (100%) create mode 100644 markwon-image-picasso/build.gradle create mode 100644 markwon-image-picasso/gradle.properties create mode 100644 markwon-image-picasso/src/main/AndroidManifest.xml create mode 100644 markwon-image-picasso/src/main/java/ru/noties/markwon/image/picasso/PicassoImagesPlugin.java diff --git a/build.gradle b/build.gradle index 63782269..a7574d80 100644 --- a/build.gradle +++ b/build.gradle @@ -71,7 +71,8 @@ ext { 'prism4j' : 'ru.noties:prism4j:1.1.0', 'debug' : 'ru.noties:debug:3.0.0@jar', 'adapt' : 'ru.noties:adapt:1.1.0', - 'dagger' : "com.google.dagger:dagger:$daggerVersion" + 'dagger' : "com.google.dagger:dagger:$daggerVersion", + 'picasso' : "com.squareup.picasso:picasso:2.71828" ] deps['annotationProcessor'] = [ diff --git a/markwon-core/src/main/java/ru/noties/markwon/core/CorePlugin.java b/markwon-core/src/main/java/ru/noties/markwon/core/CorePlugin.java index 4882441a..8f471a1e 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/core/CorePlugin.java +++ b/markwon-core/src/main/java/ru/noties/markwon/core/CorePlugin.java @@ -14,6 +14,7 @@ import org.commonmark.node.Emphasis; import org.commonmark.node.FencedCodeBlock; import org.commonmark.node.HardLineBreak; import org.commonmark.node.Heading; +import org.commonmark.node.Image; import org.commonmark.node.IndentedCodeBlock; import org.commonmark.node.Link; import org.commonmark.node.ListBlock; @@ -30,6 +31,8 @@ import ru.noties.markwon.AbstractMarkwonPlugin; import ru.noties.markwon.MarkwonConfiguration; import ru.noties.markwon.MarkwonSpansFactory; import ru.noties.markwon.MarkwonVisitor; +import ru.noties.markwon.RenderProps; +import ru.noties.markwon.SpanFactory; import ru.noties.markwon.core.factory.BlockQuoteSpanFactory; import ru.noties.markwon.core.factory.CodeBlockSpanFactory; import ru.noties.markwon.core.factory.CodeSpanFactory; @@ -40,6 +43,7 @@ import ru.noties.markwon.core.factory.ListItemSpanFactory; import ru.noties.markwon.core.factory.StrongEmphasisSpanFactory; import ru.noties.markwon.core.factory.ThematicBreakSpanFactory; import ru.noties.markwon.core.spans.OrderedListItemSpan; +import ru.noties.markwon.image.ImageProps; /** * @see CoreProps @@ -64,6 +68,7 @@ public class CorePlugin extends AbstractMarkwonPlugin { code(builder); fencedCodeBlock(builder); indentedCodeBlock(builder); + image(builder); bulletList(builder); orderedList(builder); listItem(builder); @@ -197,6 +202,53 @@ public class CorePlugin extends AbstractMarkwonPlugin { }); } + // @since 4.0.0-SNAPSHOT + // his method is moved from ImagesPlugin. Alternative implementations must set SpanFactory + // for Image node in order for this visitor to function + private static void image(MarkwonVisitor.Builder builder) { + builder.on(Image.class, new MarkwonVisitor.NodeVisitor() { + @Override + public void visit(@NonNull MarkwonVisitor visitor, @NonNull Image image) { + + // if there is no image spanFactory, ignore + final SpanFactory spanFactory = visitor.configuration().spansFactory().get(Image.class); + if (spanFactory == null) { + visitor.visitChildren(image); + return; + } + + final int length = visitor.length(); + + visitor.visitChildren(image); + + // we must check if anything _was_ added, as we need at least one char to render + if (length == visitor.length()) { + visitor.builder().append('\uFFFC'); + } + + final MarkwonConfiguration configuration = visitor.configuration(); + + final Node parent = image.getParent(); + final boolean link = parent instanceof Link; + + final String destination = configuration + .urlProcessor() + .process(image.getDestination()); + + final RenderProps props = visitor.renderProps(); + + // apply image properties + // Please note that we explicitly set IMAGE_SIZE to null as we do not clear + // properties after we applied span (we could though) + ImageProps.DESTINATION.set(props, destination); + ImageProps.REPLACEMENT_TEXT_IS_LINK.set(props, link); + ImageProps.IMAGE_SIZE.set(props, null); + + visitor.setSpans(length, spanFactory.getSpans(configuration, props)); + } + }); + } + @VisibleForTesting static void visitCodeBlock( @NonNull MarkwonVisitor visitor, diff --git a/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawable.java b/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawable.java index 239dad4e..10e4d45d 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawable.java +++ b/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawable.java @@ -261,7 +261,8 @@ public class AsyncDrawable extends Drawable { if (hasResult()) { out = result.getIntrinsicWidth(); } else { - out = 0; + // @since 4.0.0-SNAPSHOT, must not be zero in order to receive canvas dimensions + out = 1; } return out; } @@ -272,7 +273,8 @@ public class AsyncDrawable extends Drawable { if (hasResult()) { out = result.getIntrinsicHeight(); } else { - out = 0; + // @since 4.0.0-SNAPSHOT, must not be zero in order to receive canvas dimensions + out = 1; } return out; } @@ -290,4 +292,16 @@ public class AsyncDrawable extends Drawable { ? imageSizeResolver.resolveImageSize(imageSize, result.getBounds(), canvasWidth, textSize) : result.getBounds(); } + + @Override + public String toString() { + return "AsyncDrawable{" + + "destination='" + destination + '\'' + + ", imageSize=" + imageSize + + ", result=" + result + + ", canvasWidth=" + canvasWidth + + ", textSize=" + textSize + + ", waitingForDimensions=" + waitingForDimensions + + '}'; + } } diff --git a/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableScheduler.java b/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableScheduler.java index dd1735cf..83a4b150 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableScheduler.java +++ b/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableScheduler.java @@ -23,6 +23,7 @@ public abstract class AsyncDrawableScheduler { // hm... we need the same thing for unschedule then... we can check if last hash is !null, // if it's not -> unschedule, else ignore + // @since 4.0.0-SNAPSHOT final Integer lastTextHashCode = (Integer) textView.getTag(R.id.markwon_drawables_scheduler_last_text_hashcode); final int textHashCode = textView.getText().hashCode(); @@ -67,6 +68,7 @@ public abstract class AsyncDrawableScheduler { // must be called when text manually changed in TextView public static void unschedule(@NonNull TextView view) { + // @since 4.0.0-SNAPSHOT if (view.getTag(R.id.markwon_drawables_scheduler_last_text_hashcode) == null) { return; } diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/ImageSpanFactory.java b/markwon-core/src/main/java/ru/noties/markwon/image/ImageSpanFactory.java similarity index 100% rename from markwon-image/src/main/java/ru/noties/markwon/image/ImageSpanFactory.java rename to markwon-core/src/main/java/ru/noties/markwon/image/ImageSpanFactory.java diff --git a/markwon-image-picasso/build.gradle b/markwon-image-picasso/build.gradle new file mode 100644 index 00000000..b646c01c --- /dev/null +++ b/markwon-image-picasso/build.gradle @@ -0,0 +1,21 @@ +apply plugin: 'com.android.library' + +android { + + compileSdkVersion config['compile-sdk'] + buildToolsVersion config['build-tools'] + + defaultConfig { + minSdkVersion config['min-sdk'] + targetSdkVersion config['target-sdk'] + versionCode 1 + versionName version + } +} + +dependencies { + api project(':markwon-core') + api deps['picasso'] +} + +registerArtifact(this) \ No newline at end of file diff --git a/markwon-image-picasso/gradle.properties b/markwon-image-picasso/gradle.properties new file mode 100644 index 00000000..70a5e05a --- /dev/null +++ b/markwon-image-picasso/gradle.properties @@ -0,0 +1,4 @@ +POM_NAME=Image +POM_ARTIFACT_ID=image-picasso +POM_DESCRIPTION=Markwon image loading module (based on Picasso library) +POM_PACKAGING=aar \ No newline at end of file diff --git a/markwon-image-picasso/src/main/AndroidManifest.xml b/markwon-image-picasso/src/main/AndroidManifest.xml new file mode 100644 index 00000000..a32bdc6e --- /dev/null +++ b/markwon-image-picasso/src/main/AndroidManifest.xml @@ -0,0 +1 @@ + diff --git a/markwon-image-picasso/src/main/java/ru/noties/markwon/image/picasso/PicassoImagesPlugin.java b/markwon-image-picasso/src/main/java/ru/noties/markwon/image/picasso/PicassoImagesPlugin.java new file mode 100644 index 00000000..5eeb5b6d --- /dev/null +++ b/markwon-image-picasso/src/main/java/ru/noties/markwon/image/picasso/PicassoImagesPlugin.java @@ -0,0 +1,177 @@ +package ru.noties.markwon.image.picasso; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.text.Spanned; +import android.widget.TextView; + +import com.squareup.picasso.Picasso; +import com.squareup.picasso.RequestCreator; +import com.squareup.picasso.Target; + +import org.commonmark.node.Image; + +import java.util.HashMap; +import java.util.Map; + +import ru.noties.markwon.AbstractMarkwonPlugin; +import ru.noties.markwon.MarkwonConfiguration; +import ru.noties.markwon.MarkwonSpansFactory; +import ru.noties.markwon.image.AsyncDrawable; +import ru.noties.markwon.image.AsyncDrawableLoader; +import ru.noties.markwon.image.AsyncDrawableScheduler; +import ru.noties.markwon.image.DrawableUtils; +import ru.noties.markwon.image.ImageSpanFactory; + +/** + * @since 4.0.0-SNAPSHOT + */ +public class PicassoImagesPlugin extends AbstractMarkwonPlugin { + + public interface PicassoStore { + + @NonNull + RequestCreator load(@NonNull AsyncDrawable drawable); + + void cancel(@NonNull AsyncDrawable drawable); + } + + @NonNull + public static PicassoImagesPlugin create(@NonNull Context context) { + return create(new Picasso.Builder(context).build()); + } + + @NonNull + public static PicassoImagesPlugin create(@NonNull final Picasso picasso) { + return create(new PicassoStore() { + @NonNull + @Override + public RequestCreator load(@NonNull AsyncDrawable drawable) { + return picasso.load(drawable.getDestination()) + .tag(drawable); + } + + @Override + public void cancel(@NonNull AsyncDrawable drawable) { + picasso.cancelTag(drawable); + } + }); + } + + @NonNull + public static PicassoImagesPlugin create(@NonNull PicassoStore picassoStore) { + return new PicassoImagesPlugin(picassoStore); + } + + private final PicassoAsyncDrawableLoader picassoAsyncDrawableLoader; + + PicassoImagesPlugin(@NonNull PicassoStore picassoStore) { + this.picassoAsyncDrawableLoader = new PicassoAsyncDrawableLoader(picassoStore); + } + + @Override + public void configureConfiguration(@NonNull MarkwonConfiguration.Builder builder) { + builder.asyncDrawableLoader(picassoAsyncDrawableLoader); + } + + @Override + public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) { + builder.setFactory(Image.class, new ImageSpanFactory()); + } + + @Override + public void beforeSetText(@NonNull TextView textView, @NonNull Spanned markdown) { + AsyncDrawableScheduler.unschedule(textView); + } + + @Override + public void afterSetText(@NonNull TextView textView) { + AsyncDrawableScheduler.schedule(textView); + } + + private static class PicassoAsyncDrawableLoader extends AsyncDrawableLoader { + + private final PicassoStore picassoStore; + private final Map cache = new HashMap<>(2); + + PicassoAsyncDrawableLoader(@NonNull PicassoStore picassoStore) { + this.picassoStore = picassoStore; + } + + @Override + public void load(@NonNull AsyncDrawable drawable) { + + // we must store hard-reference to target (otherwise it will be garbage-collected + // ad picasso internally stores a target in a weak-reference) + final AsyncDrawableTarget target = new AsyncDrawableTarget(drawable); + cache.put(drawable, target); + + picassoStore.load(drawable) + .into(target); + } + + @Override + public void cancel(@NonNull AsyncDrawable drawable) { + + cache.remove(drawable); + + picassoStore.cancel(drawable); + } + + @Nullable + @Override + public Drawable placeholder(@NonNull AsyncDrawable drawable) { + return null; + } + + private class AsyncDrawableTarget implements Target { + + private final AsyncDrawable drawable; + + AsyncDrawableTarget(@NonNull AsyncDrawable drawable) { + this.drawable = drawable; + } + + @Override + public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) { + if (cache.remove(drawable) != null) { + if (drawable.isAttached() && bitmap != null) { + final BitmapDrawable bitmapDrawable = new BitmapDrawable(Resources.getSystem(), bitmap); + DrawableUtils.applyIntrinsicBounds(bitmapDrawable); + drawable.setResult(bitmapDrawable); + } + } + } + + @Override + public void onBitmapFailed(Exception e, Drawable errorDrawable) { + if (cache.remove(drawable) != null) { + if (errorDrawable != null + && drawable.isAttached()) { + DrawableUtils.applyIntrinsicBoundsIfEmpty(errorDrawable); + drawable.setResult(errorDrawable); + } + } + e.printStackTrace(); + } + + @Override + public void onPrepareLoad(Drawable placeHolderDrawable) { + if (placeHolderDrawable != null + && canDeliver()) { + DrawableUtils.applyIntrinsicBoundsIfEmpty(placeHolderDrawable); + drawable.setResult(placeHolderDrawable); + } + } + + private boolean canDeliver() { + return drawable.isAttached() && cache.containsKey(drawable); + } + } + } +} diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderBuilder.java b/markwon-image/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderBuilder.java index 6bbe234b..845d3e48 100644 --- a/markwon-image/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderBuilder.java +++ b/markwon-image/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderBuilder.java @@ -73,13 +73,17 @@ class AsyncDrawableLoaderBuilder { isBuilt = true; - // if we have no schemeHandlers -> we cannot show anything - // OR if we have no media decoders - if (schemeHandlers.size() == 0 - || (mediaDecoders.size() == 0 && defaultMediaDecoder == null)) { + // we must have schemeHandlers registered (we will provide + // default media decoder if it's absent) + if (schemeHandlers.size() == 0) { return new AsyncDrawableLoaderNoOp(); } + // @since 4.0.0-SNAPSHOT + if (defaultMediaDecoder == null) { + defaultMediaDecoder = DefaultImageMediaDecoder.create(); + } + if (executorService == null) { executorService = Executors.newCachedThreadPool(); } diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/ImagesPlugin.java b/markwon-image/src/main/java/ru/noties/markwon/image/ImagesPlugin.java index e8cd8324..77950ad5 100644 --- a/markwon-image/src/main/java/ru/noties/markwon/image/ImagesPlugin.java +++ b/markwon-image/src/main/java/ru/noties/markwon/image/ImagesPlugin.java @@ -7,17 +7,12 @@ import android.text.Spanned; import android.widget.TextView; import org.commonmark.node.Image; -import org.commonmark.node.Link; -import org.commonmark.node.Node; import java.util.concurrent.ExecutorService; import ru.noties.markwon.AbstractMarkwonPlugin; import ru.noties.markwon.MarkwonConfiguration; import ru.noties.markwon.MarkwonSpansFactory; -import ru.noties.markwon.MarkwonVisitor; -import ru.noties.markwon.RenderProps; -import ru.noties.markwon.SpanFactory; public class ImagesPlugin extends AbstractMarkwonPlugin { @@ -147,51 +142,6 @@ public class ImagesPlugin extends AbstractMarkwonPlugin { builder.setFactory(Image.class, new ImageSpanFactory()); } - @Override - public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) { - builder.on(Image.class, new MarkwonVisitor.NodeVisitor() { - @Override - public void visit(@NonNull MarkwonVisitor visitor, @NonNull Image image) { - - // if there is no image spanFactory, ignore - final SpanFactory spanFactory = visitor.configuration().spansFactory().get(Image.class); - if (spanFactory == null) { - visitor.visitChildren(image); - return; - } - - final int length = visitor.length(); - - visitor.visitChildren(image); - - // we must check if anything _was_ added, as we need at least one char to render - if (length == visitor.length()) { - visitor.builder().append('\uFFFC'); - } - - final MarkwonConfiguration configuration = visitor.configuration(); - - final Node parent = image.getParent(); - final boolean link = parent instanceof Link; - - final String destination = configuration - .urlProcessor() - .process(image.getDestination()); - - final RenderProps props = visitor.renderProps(); - - // apply image properties - // Please note that we explicitly set IMAGE_SIZE to null as we do not clear - // properties after we applied span (we could though) - ImageProps.DESTINATION.set(props, destination); - ImageProps.REPLACEMENT_TEXT_IS_LINK.set(props, link); - ImageProps.IMAGE_SIZE.set(props, null); - - visitor.setSpans(length, spanFactory.getSpans(configuration, props)); - } - }); - } - @Override public void beforeSetText(@NonNull TextView textView, @NonNull Spanned markdown) { AsyncDrawableScheduler.unschedule(textView); diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/file/FileSchemeHandler.java b/markwon-image/src/main/java/ru/noties/markwon/image/file/FileSchemeHandler.java index 681fb29f..f09906a1 100644 --- a/markwon-image/src/main/java/ru/noties/markwon/image/file/FileSchemeHandler.java +++ b/markwon-image/src/main/java/ru/noties/markwon/image/file/FileSchemeHandler.java @@ -1,5 +1,6 @@ package ru.noties.markwon.image.file; +import android.content.Context; import android.content.res.AssetManager; import android.net.Uri; import android.support.annotation.NonNull; @@ -35,6 +36,16 @@ public class FileSchemeHandler extends SchemeHandler { return new FileSchemeHandler(assetManager); } + /** + * @see #createWithAssets(AssetManager) + * @see ru.noties.markwon.urlprocessor.UrlProcessorAndroidAssets + * @since 4.0.0-SNAPSHOT + */ + @NonNull + public static FileSchemeHandler createWithAssets(@NonNull Context context) { + return new FileSchemeHandler(context.getAssets()); + } + @NonNull public static FileSchemeHandler create() { return new FileSchemeHandler(null); diff --git a/sample/build.gradle b/sample/build.gradle index a16436b9..86934833 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -44,6 +44,8 @@ dependencies { implementation project(':markwon-recycler') implementation project(':markwon-recycler-table') + implementation project(':markwon-image-picasso') + deps.with { implementation it['support-recycler-view'] implementation it['okhttp'] diff --git a/sample/src/main/java/ru/noties/markwon/sample/recycler/RecyclerActivity.java b/sample/src/main/java/ru/noties/markwon/sample/recycler/RecyclerActivity.java index 7b7cc091..c187ea93 100644 --- a/sample/src/main/java/ru/noties/markwon/sample/recycler/RecyclerActivity.java +++ b/sample/src/main/java/ru/noties/markwon/sample/recycler/RecyclerActivity.java @@ -2,6 +2,8 @@ package ru.noties.markwon.sample.recycler; import android.app.Activity; import android.content.Context; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; import android.net.Uri; import android.os.Bundle; import android.support.annotation.NonNull; @@ -10,6 +12,9 @@ import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.text.TextUtils; +import com.squareup.picasso.Picasso; +import com.squareup.picasso.RequestCreator; + import org.commonmark.ext.gfm.tables.TableBlock; import org.commonmark.node.FencedCodeBlock; @@ -26,11 +31,8 @@ import ru.noties.markwon.MarkwonConfiguration; import ru.noties.markwon.MarkwonVisitor; import ru.noties.markwon.core.CorePlugin; import ru.noties.markwon.html.HtmlPlugin; -import ru.noties.markwon.image.DefaultImageMediaDecoder; -import ru.noties.markwon.image.ImagesPlugin; -import ru.noties.markwon.image.file.FileSchemeHandler; -import ru.noties.markwon.image.network.OkHttpNetworkSchemeHandler; -import ru.noties.markwon.image.svg.SvgMediaDecoder; +import ru.noties.markwon.image.AsyncDrawable; +import ru.noties.markwon.image.picasso.PicassoImagesPlugin; import ru.noties.markwon.recycler.MarkwonAdapter; import ru.noties.markwon.recycler.SimpleEntry; import ru.noties.markwon.recycler.table.TableEntry; @@ -77,13 +79,13 @@ public class RecyclerActivity extends Activity { private static Markwon markwon(@NonNull Context context) { return Markwon.builder(context) .usePlugin(CorePlugin.create()) - .usePlugin(ImagesPlugin.create(plugin -> { - plugin - .addSchemeHandler(FileSchemeHandler.createWithAssets(context.getAssets())) - .addSchemeHandler(OkHttpNetworkSchemeHandler.create()) - .addMediaDecoder(SvgMediaDecoder.create()) - .defaultMediaDecoder(DefaultImageMediaDecoder.create()); - })) +// .usePlugin(ImagesPlugin.create(plugin -> { +// plugin +// .addSchemeHandler(FileSchemeHandler.createWithAssets(context)) +// .addSchemeHandler(OkHttpNetworkSchemeHandler.create()) +// .addMediaDecoder(SvgMediaDecoder.create()); +// })) + .usePlugin(PicassoImagesPlugin.create(context)) // important to use TableEntryPlugin instead of TablePlugin .usePlugin(TableEntryPlugin.create(context)) .usePlugin(HtmlPlugin.create()) diff --git a/settings.gradle b/settings.gradle index f0568523..e5b09011 100644 --- a/settings.gradle +++ b/settings.gradle @@ -7,6 +7,7 @@ include ':app', ':sample', ':markwon-ext-tasklist', ':markwon-html', ':markwon-image', + ':markwon-image-picasso', ':markwon-recycler', ':markwon-recycler-table', ':markwon-syntax-highlight', From 0b0d3c47535e6f06afd64c3bb42aeb6b9df69654 Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Thu, 30 May 2019 00:08:47 +0300 Subject: [PATCH 07/42] Add image loader module based on Glide --- build.gradle | 9 +- gradle/wrapper/gradle-wrapper.jar | Bin 54417 -> 55190 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 2 +- gradlew.bat | 2 +- markwon-image-glide/build.gradle | 21 ++ markwon-image-glide/gradle.properties | 4 + .../src/main/AndroidManifest.xml | 1 + .../image/glide/GlideImagesPlugin.java | 189 ++++++++++++++++++ markwon-image-picasso/gradle.properties | 2 +- .../image/picasso/PicassoImagesPlugin.java | 1 + sample/build.gradle | 5 + .../sample/recycler/RecyclerActivity.java | 4 +- settings.gradle | 1 + 14 files changed, 234 insertions(+), 9 deletions(-) create mode 100644 markwon-image-glide/build.gradle create mode 100644 markwon-image-glide/gradle.properties create mode 100644 markwon-image-glide/src/main/AndroidManifest.xml create mode 100644 markwon-image-glide/src/main/java/ru/noties/markwon/image/glide/GlideImagesPlugin.java diff --git a/build.gradle b/build.gradle index a7574d80..f34a6c05 100644 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.3.2' + classpath 'com.android.tools.build:gradle:3.4.1' classpath 'com.github.ben-manes:gradle-versions-plugin:0.20.0' } } @@ -29,8 +29,8 @@ task clean(type: Delete) { delete rootProject.buildDir } -task wrapper(type: Wrapper) { - gradleVersion '4.10.2' +wrapper { + gradleVersion '5.1.1' distributionType 'all' } @@ -72,7 +72,8 @@ ext { 'debug' : 'ru.noties:debug:3.0.0@jar', 'adapt' : 'ru.noties:adapt:1.1.0', 'dagger' : "com.google.dagger:dagger:$daggerVersion", - 'picasso' : "com.squareup.picasso:picasso:2.71828" + 'picasso' : 'com.squareup.picasso:picasso:2.71828', + 'glide' : 'com.github.bumptech.glide:glide:4.9.0' ] deps['annotationProcessor'] = [ diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 758de960ec7947253b058ff79c88ce51f3abe08a..87b738cbd051603d91cc39de6cb000dd98fe6b02 100644 GIT binary patch literal 55190 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 z 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index d76b502e..c4486d47 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index cccdd3d5..af6708ff 100755 --- a/gradlew +++ b/gradlew @@ -28,7 +28,7 @@ APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +DEFAULT_JVM_OPTS='"-Xmx64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" diff --git a/gradlew.bat b/gradlew.bat index e95643d6..0f8d5937 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -14,7 +14,7 @@ set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= +set DEFAULT_JVM_OPTS="-Xmx64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome diff --git a/markwon-image-glide/build.gradle b/markwon-image-glide/build.gradle new file mode 100644 index 00000000..a9d3ef66 --- /dev/null +++ b/markwon-image-glide/build.gradle @@ -0,0 +1,21 @@ +apply plugin: 'com.android.library' + +android { + + compileSdkVersion config['compile-sdk'] + buildToolsVersion config['build-tools'] + + defaultConfig { + minSdkVersion config['min-sdk'] + targetSdkVersion config['target-sdk'] + versionCode 1 + versionName version + } +} + +dependencies { + api project(':markwon-core') + api deps['glide'] +} + +registerArtifact(this) \ No newline at end of file diff --git a/markwon-image-glide/gradle.properties b/markwon-image-glide/gradle.properties new file mode 100644 index 00000000..8878f2a3 --- /dev/null +++ b/markwon-image-glide/gradle.properties @@ -0,0 +1,4 @@ +POM_NAME=Image Glide +POM_ARTIFACT_ID=image-glide +POM_DESCRIPTION=Markwon image loading module (based on Glide library) +POM_PACKAGING=aar \ No newline at end of file diff --git a/markwon-image-glide/src/main/AndroidManifest.xml b/markwon-image-glide/src/main/AndroidManifest.xml new file mode 100644 index 00000000..806be809 --- /dev/null +++ b/markwon-image-glide/src/main/AndroidManifest.xml @@ -0,0 +1 @@ + diff --git a/markwon-image-glide/src/main/java/ru/noties/markwon/image/glide/GlideImagesPlugin.java b/markwon-image-glide/src/main/java/ru/noties/markwon/image/glide/GlideImagesPlugin.java new file mode 100644 index 00000000..2afa28f7 --- /dev/null +++ b/markwon-image-glide/src/main/java/ru/noties/markwon/image/glide/GlideImagesPlugin.java @@ -0,0 +1,189 @@ +package ru.noties.markwon.image.glide; + +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.text.Spanned; +import android.widget.TextView; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.RequestBuilder; +import com.bumptech.glide.RequestManager; +import com.bumptech.glide.request.target.CustomTarget; +import com.bumptech.glide.request.target.Target; +import com.bumptech.glide.request.transition.Transition; + +import org.commonmark.node.Image; + +import java.util.HashMap; +import java.util.Map; + +import ru.noties.markwon.AbstractMarkwonPlugin; +import ru.noties.markwon.MarkwonConfiguration; +import ru.noties.markwon.MarkwonSpansFactory; +import ru.noties.markwon.image.AsyncDrawable; +import ru.noties.markwon.image.AsyncDrawableLoader; +import ru.noties.markwon.image.AsyncDrawableScheduler; +import ru.noties.markwon.image.DrawableUtils; +import ru.noties.markwon.image.ImageSpanFactory; + +/** + * @since 4.0.0-SNAPSHOT + */ +public class GlideImagesPlugin extends AbstractMarkwonPlugin { + + public interface GlideStore { + + @NonNull + RequestBuilder load(@NonNull AsyncDrawable drawable); + + void cancel(@NonNull Target target); + } + + @NonNull + public static GlideImagesPlugin create(@NonNull final Context context) { + return create(new GlideStore() { + @NonNull + @Override + public RequestBuilder load(@NonNull AsyncDrawable drawable) { + return Glide.with(context) + .load(drawable.getDestination()); + } + + @Override + public void cancel(@NonNull Target target) { + Glide.with(context) + .clear(target); + } + }); + } + + @NonNull + public static GlideImagesPlugin create(@NonNull final RequestManager requestManager) { + return create(new GlideStore() { + @NonNull + @Override + public RequestBuilder load(@NonNull AsyncDrawable drawable) { + return requestManager.load(drawable.getDestination()); + } + + @Override + public void cancel(@NonNull Target target) { + requestManager.clear(target); + } + }); + } + + @NonNull + public static GlideImagesPlugin create(@NonNull GlideStore glideStore) { + return new GlideImagesPlugin(glideStore); + } + + private final GlideAsyncDrawableLoader glideAsyncDrawableLoader; + + @SuppressWarnings("WeakerAccess") + GlideImagesPlugin(@NonNull GlideStore glideStore) { + this.glideAsyncDrawableLoader = new GlideAsyncDrawableLoader(glideStore); + } + + @Override + public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) { + builder.setFactory(Image.class, new ImageSpanFactory()); + } + + @Override + public void configureConfiguration(@NonNull MarkwonConfiguration.Builder builder) { + builder.asyncDrawableLoader(glideAsyncDrawableLoader); + } + + @Override + public void beforeSetText(@NonNull TextView textView, @NonNull Spanned markdown) { + AsyncDrawableScheduler.unschedule(textView); + } + + @Override + public void afterSetText(@NonNull TextView textView) { + AsyncDrawableScheduler.schedule(textView); + } + + private static class GlideAsyncDrawableLoader extends AsyncDrawableLoader { + + private final GlideStore glideStore; + private final Map> cache = new HashMap<>(2); + + GlideAsyncDrawableLoader(@NonNull GlideStore glideStore) { + this.glideStore = glideStore; + } + + @Override + public void load(@NonNull AsyncDrawable drawable) { + final Target target = new AsyncDrawableTarget(drawable); + cache.put(drawable, target); + glideStore.load(drawable) + .into(target); + } + + @Override + public void cancel(@NonNull AsyncDrawable drawable) { + final Target target = cache.remove(drawable); + if (target != null) { + glideStore.cancel(target); + } + } + + @Nullable + @Override + public Drawable placeholder(@NonNull AsyncDrawable drawable) { + return null; + } + + private class AsyncDrawableTarget extends CustomTarget { + + private final AsyncDrawable drawable; + + AsyncDrawableTarget(@NonNull AsyncDrawable drawable) { + this.drawable = drawable; + } + + @Override + public void onResourceReady(@NonNull Drawable resource, @Nullable Transition transition) { + if (cache.remove(drawable) != null) { + if (drawable.isAttached()) { + DrawableUtils.applyIntrinsicBoundsIfEmpty(resource); + drawable.setResult(resource); + } + } + } + + @Override + public void onLoadStarted(@Nullable Drawable placeholder) { + if (placeholder != null + && drawable.isAttached()) { + DrawableUtils.applyIntrinsicBoundsIfEmpty(placeholder); + drawable.setResult(placeholder); + } + } + + @Override + public void onLoadFailed(@Nullable Drawable errorDrawable) { + if (cache.remove(drawable) != null) { + if (errorDrawable != null + && drawable.isAttached()) { + DrawableUtils.applyIntrinsicBoundsIfEmpty(errorDrawable); + drawable.setResult(errorDrawable); + } + } + } + + @Override + public void onLoadCleared(@Nullable Drawable placeholder) { + // we won't be checking if target is still present as cancellation + // must remove target anyway + if (drawable.isAttached()) { + drawable.clearResult(); + } + } + } + } +} diff --git a/markwon-image-picasso/gradle.properties b/markwon-image-picasso/gradle.properties index 70a5e05a..d811058b 100644 --- a/markwon-image-picasso/gradle.properties +++ b/markwon-image-picasso/gradle.properties @@ -1,4 +1,4 @@ -POM_NAME=Image +POM_NAME=Image Picasso POM_ARTIFACT_ID=image-picasso POM_DESCRIPTION=Markwon image loading module (based on Picasso library) POM_PACKAGING=aar \ No newline at end of file diff --git a/markwon-image-picasso/src/main/java/ru/noties/markwon/image/picasso/PicassoImagesPlugin.java b/markwon-image-picasso/src/main/java/ru/noties/markwon/image/picasso/PicassoImagesPlugin.java index 5eeb5b6d..7bb37c1d 100644 --- a/markwon-image-picasso/src/main/java/ru/noties/markwon/image/picasso/PicassoImagesPlugin.java +++ b/markwon-image-picasso/src/main/java/ru/noties/markwon/image/picasso/PicassoImagesPlugin.java @@ -70,6 +70,7 @@ public class PicassoImagesPlugin extends AbstractMarkwonPlugin { private final PicassoAsyncDrawableLoader picassoAsyncDrawableLoader; + @SuppressWarnings("WeakerAccess") PicassoImagesPlugin(@NonNull PicassoStore picassoStore) { this.picassoAsyncDrawableLoader = new PicassoAsyncDrawableLoader(picassoStore); } diff --git a/sample/build.gradle b/sample/build.gradle index 86934833..4bde062b 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -44,6 +44,11 @@ dependencies { implementation project(':markwon-recycler') implementation project(':markwon-recycler-table') + // these are for glide + implementation 'com.android.support:animated-vector-drawable:28.0.0' + implementation 'com.android.support:support-fragment:28.0.0' + + implementation project(':markwon-image-glide') implementation project(':markwon-image-picasso') deps.with { diff --git a/sample/src/main/java/ru/noties/markwon/sample/recycler/RecyclerActivity.java b/sample/src/main/java/ru/noties/markwon/sample/recycler/RecyclerActivity.java index c187ea93..72409a5f 100644 --- a/sample/src/main/java/ru/noties/markwon/sample/recycler/RecyclerActivity.java +++ b/sample/src/main/java/ru/noties/markwon/sample/recycler/RecyclerActivity.java @@ -32,6 +32,7 @@ import ru.noties.markwon.MarkwonVisitor; import ru.noties.markwon.core.CorePlugin; import ru.noties.markwon.html.HtmlPlugin; import ru.noties.markwon.image.AsyncDrawable; +import ru.noties.markwon.image.glide.GlideImagesPlugin; import ru.noties.markwon.image.picasso.PicassoImagesPlugin; import ru.noties.markwon.recycler.MarkwonAdapter; import ru.noties.markwon.recycler.SimpleEntry; @@ -85,7 +86,8 @@ public class RecyclerActivity extends Activity { // .addSchemeHandler(OkHttpNetworkSchemeHandler.create()) // .addMediaDecoder(SvgMediaDecoder.create()); // })) - .usePlugin(PicassoImagesPlugin.create(context)) +// .usePlugin(PicassoImagesPlugin.create(context)) + .usePlugin(GlideImagesPlugin.create(context)) // important to use TableEntryPlugin instead of TablePlugin .usePlugin(TableEntryPlugin.create(context)) .usePlugin(HtmlPlugin.create()) diff --git a/settings.gradle b/settings.gradle index e5b09011..da0bcd9e 100644 --- a/settings.gradle +++ b/settings.gradle @@ -7,6 +7,7 @@ include ':app', ':sample', ':markwon-ext-tasklist', ':markwon-html', ':markwon-image', + ':markwon-image-glide', ':markwon-image-picasso', ':markwon-recycler', ':markwon-recycler-table', From 2e35ef53bb80e24be0a4376d1b721b0f6f137ad7 Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Thu, 30 May 2019 15:28:39 +0300 Subject: [PATCH 08/42] Ensure explicit dependencies for SVG and GIF --- .../ru/noties/markwon/MarkdownRenderer.java | 4 +-- .../markwon/ext/tasklist/TaskListPlugin.java | 2 +- .../image/AsyncDrawableLoaderBuilder.java | 11 ++------ .../ru/noties/markwon/image/ImagesPlugin.java | 4 ++- .../markwon/image/gif/GifMediaDecoder.java | 27 +++++++++++++++++++ .../image/network/NetworkSchemeHandler.java | 5 ++++ .../network/OkHttpNetworkSchemeHandler.java | 1 + .../markwon/image/svg/SvgMediaDecoder.java | 27 +++++++++++++++++++ 8 files changed, 67 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/ru/noties/markwon/MarkdownRenderer.java b/app/src/main/java/ru/noties/markwon/MarkdownRenderer.java index 26b247a2..a55d82dc 100644 --- a/app/src/main/java/ru/noties/markwon/MarkdownRenderer.java +++ b/app/src/main/java/ru/noties/markwon/MarkdownRenderer.java @@ -19,7 +19,6 @@ import ru.noties.markwon.ext.tables.TablePlugin; import ru.noties.markwon.ext.tasklist.TaskListPlugin; import ru.noties.markwon.gif.GifAwarePlugin; import ru.noties.markwon.html.HtmlPlugin; -import ru.noties.markwon.image.DefaultImageMediaDecoder; import ru.noties.markwon.image.ImagesPlugin; import ru.noties.markwon.image.data.DataUriSchemeHandler; import ru.noties.markwon.image.file.FileSchemeHandler; @@ -105,8 +104,7 @@ public class MarkdownRenderer { .addSchemeHandler(OkHttpNetworkSchemeHandler.create()) .addSchemeHandler(FileSchemeHandler.createWithAssets(context.getAssets())) .addMediaDecoder(GifMediaDecoder.create(false)) - .addMediaDecoder(SvgMediaDecoder.create()) - .defaultMediaDecoder(DefaultImageMediaDecoder.create()); + .addMediaDecoder(SvgMediaDecoder.create()); } })) .usePlugin(SyntaxHighlightPlugin.create(prism4j, prism4jTheme)) diff --git a/markwon-ext-tasklist/src/main/java/ru/noties/markwon/ext/tasklist/TaskListPlugin.java b/markwon-ext-tasklist/src/main/java/ru/noties/markwon/ext/tasklist/TaskListPlugin.java index 9f74c206..ec664280 100644 --- a/markwon-ext-tasklist/src/main/java/ru/noties/markwon/ext/tasklist/TaskListPlugin.java +++ b/markwon-ext-tasklist/src/main/java/ru/noties/markwon/ext/tasklist/TaskListPlugin.java @@ -101,7 +101,7 @@ public class TaskListPlugin extends AbstractMarkwonPlugin { private static int resolve(@NonNull Context context, @AttrRes int attr) { final TypedValue typedValue = new TypedValue(); - final int attrs[] = new int[]{attr}; + final int[] attrs = new int[]{attr}; final TypedArray typedArray = context.obtainStyledAttributes(typedValue.data, attrs); try { return typedArray.getColor(0, 0); diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderBuilder.java b/markwon-image/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderBuilder.java index 845d3e48..e82730f4 100644 --- a/markwon-image/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderBuilder.java +++ b/markwon-image/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderBuilder.java @@ -3,7 +3,6 @@ package ru.noties.markwon.image; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ExecutorService; @@ -31,14 +30,8 @@ class AsyncDrawableLoaderBuilder { } void addMediaDecoder(@NonNull MediaDecoder mediaDecoder) { - final Collection supportedTypes = mediaDecoder.supportedTypes(); - if (supportedTypes.isEmpty()) { - // todo: we should think about this little _side-effect_... does it worth it? - defaultMediaDecoder = mediaDecoder; - } else { - for (String type : supportedTypes) { - mediaDecoders.put(type, mediaDecoder); - } + for (String type : mediaDecoder.supportedTypes()) { + mediaDecoders.put(type, mediaDecoder); } } diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/ImagesPlugin.java b/markwon-image/src/main/java/ru/noties/markwon/image/ImagesPlugin.java index 77950ad5..0a7d9446 100644 --- a/markwon-image/src/main/java/ru/noties/markwon/image/ImagesPlugin.java +++ b/markwon-image/src/main/java/ru/noties/markwon/image/ImagesPlugin.java @@ -47,9 +47,11 @@ public class ImagesPlugin extends AbstractMarkwonPlugin { * Factory method to create an empty {@link ImagesPlugin} instance with no {@link SchemeHandler}s * nor {@link MediaDecoder}s registered. Can be used to further configure via instance methods or * via {@link ru.noties.markwon.MarkwonPlugin#configure(Registry)} + * + * @see #create(ImagesConfigure) */ @NonNull - public static ImagesPlugin createEmpty() { + public static ImagesPlugin create() { return new ImagesPlugin(); } diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/gif/GifMediaDecoder.java b/markwon-image/src/main/java/ru/noties/markwon/image/gif/GifMediaDecoder.java index e5195bc5..200be994 100644 --- a/markwon-image/src/main/java/ru/noties/markwon/image/gif/GifMediaDecoder.java +++ b/markwon-image/src/main/java/ru/noties/markwon/image/gif/GifMediaDecoder.java @@ -31,6 +31,9 @@ public class GifMediaDecoder extends MediaDecoder { protected GifMediaDecoder(boolean autoPlayGif) { this.autoPlayGif = autoPlayGif; + + // @since 4.0.0-SNAPSHOT + Holder.validate(); } @NonNull @@ -82,4 +85,28 @@ public class GifMediaDecoder extends MediaDecoder { } return outputStream.toByteArray(); } + + // @since 4.0.0-SNAPSHOT + private static class Holder { + + private static final boolean HAS_GIF; + + static { + boolean result = true; + try { + GifDrawable.class.getName(); + } catch (Throwable t) { + result = false; + t.printStackTrace(); + } + HAS_GIF = result; + } + + static void validate() { + if (!HAS_GIF) { + throw new IllegalStateException("`pl.droidsonroids.gif:android-gif-drawable:*` " + + "dependency is missing, please add to your project explicitly"); + } + } + } } diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/network/NetworkSchemeHandler.java b/markwon-image/src/main/java/ru/noties/markwon/image/network/NetworkSchemeHandler.java index a9dbfaee..920fa4c1 100644 --- a/markwon-image/src/main/java/ru/noties/markwon/image/network/NetworkSchemeHandler.java +++ b/markwon-image/src/main/java/ru/noties/markwon/image/network/NetworkSchemeHandler.java @@ -31,6 +31,11 @@ public class NetworkSchemeHandler extends SchemeHandler { return new NetworkSchemeHandler(); } + @SuppressWarnings("WeakerAccess") + NetworkSchemeHandler() { + + } + @NonNull @Override public ImageItem handle(@NonNull String raw, @NonNull Uri uri) { diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/network/OkHttpNetworkSchemeHandler.java b/markwon-image/src/main/java/ru/noties/markwon/image/network/OkHttpNetworkSchemeHandler.java index 7faec7e5..9feddd0f 100644 --- a/markwon-image/src/main/java/ru/noties/markwon/image/network/OkHttpNetworkSchemeHandler.java +++ b/markwon-image/src/main/java/ru/noties/markwon/image/network/OkHttpNetworkSchemeHandler.java @@ -36,6 +36,7 @@ public class OkHttpNetworkSchemeHandler extends SchemeHandler { private final OkHttpClient client; + @SuppressWarnings("WeakerAccess") OkHttpNetworkSchemeHandler(@NonNull OkHttpClient client) { this.client = client; } diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/svg/SvgMediaDecoder.java b/markwon-image/src/main/java/ru/noties/markwon/image/svg/SvgMediaDecoder.java index e9484a25..78d381a8 100644 --- a/markwon-image/src/main/java/ru/noties/markwon/image/svg/SvgMediaDecoder.java +++ b/markwon-image/src/main/java/ru/noties/markwon/image/svg/SvgMediaDecoder.java @@ -44,6 +44,9 @@ public class SvgMediaDecoder extends MediaDecoder { @SuppressWarnings("WeakerAccess") SvgMediaDecoder(Resources resources) { this.resources = resources; + + // @since 4.0.0-SNAPSHOT + Holder.validate(); } @NonNull @@ -79,4 +82,28 @@ public class SvgMediaDecoder extends MediaDecoder { public Collection supportedTypes() { return Collections.singleton(CONTENT_TYPE); } + + // @since 4.0.0-SNAPSHOT + private static class Holder { + + private static final boolean HAS_SVG; + + static { + boolean result = true; + try { + SVG.class.getName(); + } catch (Throwable t) { + result = false; + t.printStackTrace(); + } + HAS_SVG = result; + } + + static void validate() { + if (!HAS_SVG) { + throw new IllegalStateException("`com.caverock:androidsvg:*` dependency is missing, " + + "please add to your project explicitly"); + } + } + } } From cedb3971a0ff0d72ec07d6e59cbe29ea67093d50 Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Sun, 2 Jun 2019 22:12:40 +0300 Subject: [PATCH 09/42] text-added-listener for core-plugin and linkify module --- _CHANGES.md | 5 +- app/build.gradle | 1 + .../ru/noties/markwon/MarkdownRenderer.java | 2 + app/src/main/res/layout/activity_main.xml | 8 +- .../ru/noties/markwon/core/CorePlugin.java | 59 +++++++++++- markwon-linkify/build.gradle | 20 ++++ markwon-linkify/gradle.properties | 4 + markwon-linkify/src/main/AndroidManifest.xml | 1 + .../noties/markwon/linkify/LinkifyPlugin.java | 91 +++++++++++++++++++ settings.gradle | 1 + 10 files changed, 185 insertions(+), 7 deletions(-) create mode 100644 markwon-linkify/build.gradle create mode 100644 markwon-linkify/gradle.properties create mode 100644 markwon-linkify/src/main/AndroidManifest.xml create mode 100644 markwon-linkify/src/main/java/ru/noties/markwon/linkify/LinkifyPlugin.java diff --git a/_CHANGES.md b/_CHANGES.md index 3a63fbbe..4695759f 100644 --- a/_CHANGES.md +++ b/_CHANGES.md @@ -3,4 +3,7 @@ * `JLatex` plugin now is not dependent on ImagesPlugin also accepts a ExecutorService (optional, by default cachedThreadPool is used) * AsyncDrawableScheduler now can be called by multiple plugins without penalty - internally caches latest state and skips scheduling if drawables are already processed \ No newline at end of file + internally caches latest state and skips scheduling if drawables are already processed +* configure with registry +* removed priority +* images-plugin moved to standalone again \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 9d95baaf..ffa43c25 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -34,6 +34,7 @@ dependencies { implementation project(':markwon-ext-tasklist') implementation project(':markwon-html') implementation project(':markwon-image') + implementation project(':markwon-linkify') implementation project(':markwon-syntax-highlight') deps.with { diff --git a/app/src/main/java/ru/noties/markwon/MarkdownRenderer.java b/app/src/main/java/ru/noties/markwon/MarkdownRenderer.java index a55d82dc..73adc541 100644 --- a/app/src/main/java/ru/noties/markwon/MarkdownRenderer.java +++ b/app/src/main/java/ru/noties/markwon/MarkdownRenderer.java @@ -25,6 +25,7 @@ import ru.noties.markwon.image.file.FileSchemeHandler; import ru.noties.markwon.image.gif.GifMediaDecoder; import ru.noties.markwon.image.network.OkHttpNetworkSchemeHandler; import ru.noties.markwon.image.svg.SvgMediaDecoder; +import ru.noties.markwon.linkify.LinkifyPlugin; import ru.noties.markwon.syntax.Prism4jTheme; import ru.noties.markwon.syntax.Prism4jThemeDarkula; import ru.noties.markwon.syntax.Prism4jThemeDefault; @@ -107,6 +108,7 @@ public class MarkdownRenderer { .addMediaDecoder(SvgMediaDecoder.create()); } })) + .usePlugin(LinkifyPlugin.create()) .usePlugin(SyntaxHighlightPlugin.create(prism4j, prism4jTheme)) .usePlugin(GifAwarePlugin.create(context)) .usePlugin(TablePlugin.create(context)) diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 97c5fb1b..0bd1c6ac 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -8,11 +8,11 @@ android:id="@+id/scroll_view" android:layout_width="match_parent" android:layout_height="match_parent" - android:padding="16dip" - android:clipToPadding="false" + android:layout_marginTop="?android:attr/actionBarSize" android:clipChildren="false" - android:scrollbarStyle="outsideOverlay" - android:layout_marginTop="?android:attr/actionBarSize"> + android:clipToPadding="false" + android:padding="16dip" + android:scrollbarStyle="outsideOverlay"> + * Please note that if you wish to add spans you must use {@code start} parameter + * in order to place spans correctly ({@code start} represents the index at which {@code text} + * was added). So, to set a span for the whole length of the text added one should use: + *

+ * {@code + * visitor.builder().setSpan(new MySpan(), start, start + text.length(), 0); + * } + * + * @param visitor {@link MarkwonVisitor} + * @param text literal that had been added + * @param start index in {@code visitor} as which text had been added + * @see #addOnTextAddedListener(OnTextAddedListener) + */ + void onTextAdded(@NonNull MarkwonVisitor visitor, @NonNull String text, int start); + } + @NonNull public static CorePlugin create() { return new CorePlugin(); } + // @since 4.0.0-SNAPSHOT + private final List onTextAddedListeners = new ArrayList<>(0); + protected CorePlugin() { } + /** + * Can be useful to post-process text added. For example for auto-linking capabilities. + * + * @see OnTextAddedListener + * @since 4.0.0-SNAPSHOT + */ + @SuppressWarnings("UnusedReturnValue") + @NonNull + public CorePlugin addOnTextAddedListener(@NonNull OnTextAddedListener onTextAddedListener) { + onTextAddedListeners.add(onTextAddedListener); + return this; + } + @Override public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) { text(builder); @@ -114,11 +160,20 @@ public class CorePlugin extends AbstractMarkwonPlugin { } } - private static void text(@NonNull MarkwonVisitor.Builder builder) { + private void text(@NonNull MarkwonVisitor.Builder builder) { builder.on(Text.class, new MarkwonVisitor.NodeVisitor() { @Override public void visit(@NonNull MarkwonVisitor visitor, @NonNull Text text) { - visitor.builder().append(text.getLiteral()); + + final int length = visitor.length(); + final String literal = text.getLiteral(); + + visitor.builder().append(literal); + + // @since 4.0.0-SNAPSHOT + for (OnTextAddedListener onTextAddedListener : onTextAddedListeners) { + onTextAddedListener.onTextAdded(visitor, literal, length); + } } }); } diff --git a/markwon-linkify/build.gradle b/markwon-linkify/build.gradle new file mode 100644 index 00000000..764113ab --- /dev/null +++ b/markwon-linkify/build.gradle @@ -0,0 +1,20 @@ +apply plugin: 'com.android.library' + +android { + + compileSdkVersion config['compile-sdk'] + buildToolsVersion config['build-tools'] + + defaultConfig { + minSdkVersion config['min-sdk'] + targetSdkVersion config['target-sdk'] + versionCode 1 + versionName version + } +} + +dependencies { + api project(':markwon-core') +} + +registerArtifact(this) \ No newline at end of file diff --git a/markwon-linkify/gradle.properties b/markwon-linkify/gradle.properties new file mode 100644 index 00000000..405e6449 --- /dev/null +++ b/markwon-linkify/gradle.properties @@ -0,0 +1,4 @@ +POM_NAME=Linkify +POM_ARTIFACT_ID=linkify +POM_DESCRIPTION=Markwon plugin to linkify text (based on Android Linkify) +POM_PACKAGING=aar \ No newline at end of file diff --git a/markwon-linkify/src/main/AndroidManifest.xml b/markwon-linkify/src/main/AndroidManifest.xml new file mode 100644 index 00000000..3a9ba865 --- /dev/null +++ b/markwon-linkify/src/main/AndroidManifest.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/markwon-linkify/src/main/java/ru/noties/markwon/linkify/LinkifyPlugin.java b/markwon-linkify/src/main/java/ru/noties/markwon/linkify/LinkifyPlugin.java new file mode 100644 index 00000000..ff29c1a1 --- /dev/null +++ b/markwon-linkify/src/main/java/ru/noties/markwon/linkify/LinkifyPlugin.java @@ -0,0 +1,91 @@ +package ru.noties.markwon.linkify; + +import android.support.annotation.IntDef; +import android.support.annotation.NonNull; +import android.text.SpannableStringBuilder; +import android.text.util.Linkify; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +import ru.noties.markwon.AbstractMarkwonPlugin; +import ru.noties.markwon.MarkwonVisitor; +import ru.noties.markwon.SpannableBuilder; +import ru.noties.markwon.core.CorePlugin; + +public class LinkifyPlugin extends AbstractMarkwonPlugin { + + @IntDef(flag = true, value = { + Linkify.EMAIL_ADDRESSES, + Linkify.PHONE_NUMBERS, + Linkify.WEB_URLS, + Linkify.ALL + }) + @Retention(RetentionPolicy.SOURCE) + @interface LinkifyMask { + } + + @NonNull + public static LinkifyPlugin create() { + return create(Linkify.EMAIL_ADDRESSES | Linkify.PHONE_NUMBERS | Linkify.WEB_URLS); + } + + @NonNull + public static LinkifyPlugin create(@LinkifyMask int mask) { + return new LinkifyPlugin(mask); + } + + private final int mask; + + @SuppressWarnings("WeakerAccess") + LinkifyPlugin(@LinkifyMask int mask) { + this.mask = mask; + } + + @Override + public void configure(@NonNull Registry registry) { + registry.require(CorePlugin.class, new Action() { + @Override + public void apply(@NonNull CorePlugin corePlugin) { + corePlugin.addOnTextAddedListener(new LinkifyTextAddedListener(mask)); + } + }); + } + + private static class LinkifyTextAddedListener implements CorePlugin.OnTextAddedListener { + + private final int mask; + private final SpannableStringBuilder builder; + + LinkifyTextAddedListener(int mask) { + this.mask = mask; + this.builder = new SpannableStringBuilder(); + } + + @Override + public void onTextAdded(@NonNull MarkwonVisitor visitor, @NonNull String text, int start) { + + // clear previous state + builder.clear(); + builder.clearSpans(); + + // append text to process + builder.append(text); + + if (Linkify.addLinks(builder, mask)) { + final Object[] spans = builder.getSpans(0, builder.length(), Object.class); + if (spans != null + && spans.length > 0) { + final SpannableBuilder spannableBuilder = visitor.builder(); + for (Object span : spans) { + spannableBuilder.setSpan( + span, + start + builder.getSpanStart(span), + start + builder.getSpanEnd(span), + builder.getSpanFlags(span)); + } + } + } + } + } +} diff --git a/settings.gradle b/settings.gradle index da0bcd9e..38372eba 100644 --- a/settings.gradle +++ b/settings.gradle @@ -9,6 +9,7 @@ include ':app', ':sample', ':markwon-image', ':markwon-image-glide', ':markwon-image-picasso', + ':markwon-linkify', ':markwon-recycler', ':markwon-recycler-table', ':markwon-syntax-highlight', From 6bf04e38ad1754f91c233c02dc366848bde9c7e0 Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Mon, 3 Jun 2019 15:28:52 +0300 Subject: [PATCH 10/42] Add tests for markwon-image module --- .../ru/noties/markwon/core/CorePlugin.java | 9 +- .../markwon/image/AsyncDrawableLoader.java | 2 - .../image/AsyncDrawableLoaderNoOp.java | 2 +- .../markwon/ext/latex/JLatexMathPlugin.java | 1 + .../image/AsyncDrawableLoaderBuilder.java | 19 +- .../ru/noties/markwon/image/ImagesPlugin.java | 29 ++- .../image/AsyncDrawableLoaderBuilderTest.java | 194 ++++++++++++++++++ .../markwon/image/ImagesPluginTest.java | 177 ++++++++++++++++ markwon-linkify/README.md | 5 + .../noties/markwon/linkify/LinkifyPlugin.java | 3 +- 10 files changed, 425 insertions(+), 16 deletions(-) create mode 100644 markwon-image/src/test/java/ru/noties/markwon/image/AsyncDrawableLoaderBuilderTest.java create mode 100644 markwon-image/src/test/java/ru/noties/markwon/image/ImagesPluginTest.java create mode 100644 markwon-linkify/README.md diff --git a/markwon-core/src/main/java/ru/noties/markwon/core/CorePlugin.java b/markwon-core/src/main/java/ru/noties/markwon/core/CorePlugin.java index 96d8bb11..506da2b9 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/core/CorePlugin.java +++ b/markwon-core/src/main/java/ru/noties/markwon/core/CorePlugin.java @@ -165,14 +165,17 @@ public class CorePlugin extends AbstractMarkwonPlugin { @Override public void visit(@NonNull MarkwonVisitor visitor, @NonNull Text text) { - final int length = visitor.length(); final String literal = text.getLiteral(); visitor.builder().append(literal); // @since 4.0.0-SNAPSHOT - for (OnTextAddedListener onTextAddedListener : onTextAddedListeners) { - onTextAddedListener.onTextAdded(visitor, literal, length); + if (!onTextAddedListeners.isEmpty()) { + // calculate the start position + final int length = visitor.length() - literal.length(); + for (OnTextAddedListener onTextAddedListener : onTextAddedListeners) { + onTextAddedListener.onTextAdded(visitor, literal, length); + } } } }); diff --git a/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableLoader.java b/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableLoader.java index f9bbb4b7..314e537f 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableLoader.java +++ b/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableLoader.java @@ -27,6 +27,4 @@ public abstract class AsyncDrawableLoader { @Nullable public abstract Drawable placeholder(@NonNull AsyncDrawable drawable); - - } diff --git a/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderNoOp.java b/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderNoOp.java index 7c3475b7..e3a6331a 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderNoOp.java +++ b/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderNoOp.java @@ -4,7 +4,7 @@ import android.graphics.drawable.Drawable; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -public class AsyncDrawableLoaderNoOp extends AsyncDrawableLoader { +class AsyncDrawableLoaderNoOp extends AsyncDrawableLoader { @Override public void load(@NonNull AsyncDrawable drawable) { diff --git a/markwon-ext-latex/src/main/java/ru/noties/markwon/ext/latex/JLatexMathPlugin.java b/markwon-ext-latex/src/main/java/ru/noties/markwon/ext/latex/JLatexMathPlugin.java index ee28e04e..decdb6d1 100644 --- a/markwon-ext-latex/src/main/java/ru/noties/markwon/ext/latex/JLatexMathPlugin.java +++ b/markwon-ext-latex/src/main/java/ru/noties/markwon/ext/latex/JLatexMathPlugin.java @@ -93,6 +93,7 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin { private final JLatextAsyncDrawableLoader jLatextAsyncDrawableLoader; + @SuppressWarnings("WeakerAccess") JLatexMathPlugin(@NonNull Config config) { this.jLatextAsyncDrawableLoader = new JLatextAsyncDrawableLoader(config); } diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderBuilder.java b/markwon-image/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderBuilder.java index e82730f4..57347b70 100644 --- a/markwon-image/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderBuilder.java +++ b/markwon-image/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderBuilder.java @@ -8,6 +8,9 @@ import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import ru.noties.markwon.image.data.DataUriSchemeHandler; +import ru.noties.markwon.image.network.NetworkSchemeHandler; + class AsyncDrawableLoaderBuilder { ExecutorService executorService; @@ -19,6 +22,15 @@ class AsyncDrawableLoaderBuilder { boolean isBuilt; + AsyncDrawableLoaderBuilder() { + + // @since 4.0.0-SNAPSHOT + // okay, let's add supported schemes at the start, this would be : data-uri and default network + // we should not use file-scheme as it's a bit complicated to assume file usage (lack of permissions) + addSchemeHandler(DataUriSchemeHandler.create()); + addSchemeHandler(NetworkSchemeHandler.create()); + } + void executorService(@NonNull ExecutorService executorService) { this.executorService = executorService; } @@ -66,12 +78,6 @@ class AsyncDrawableLoaderBuilder { isBuilt = true; - // we must have schemeHandlers registered (we will provide - // default media decoder if it's absent) - if (schemeHandlers.size() == 0) { - return new AsyncDrawableLoaderNoOp(); - } - // @since 4.0.0-SNAPSHOT if (defaultMediaDecoder == null) { defaultMediaDecoder = DefaultImageMediaDecoder.create(); @@ -83,5 +89,4 @@ class AsyncDrawableLoaderBuilder { return new AsyncDrawableLoaderImpl(this); } - } diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/ImagesPlugin.java b/markwon-image/src/main/java/ru/noties/markwon/image/ImagesPlugin.java index 0a7d9446..e5cac9b3 100644 --- a/markwon-image/src/main/java/ru/noties/markwon/image/ImagesPlugin.java +++ b/markwon-image/src/main/java/ru/noties/markwon/image/ImagesPlugin.java @@ -14,6 +14,7 @@ import ru.noties.markwon.AbstractMarkwonPlugin; import ru.noties.markwon.MarkwonConfiguration; import ru.noties.markwon.MarkwonSpansFactory; +@SuppressWarnings({"UnusedReturnValue", "WeakerAccess"}) public class ImagesPlugin extends AbstractMarkwonPlugin { /** @@ -91,6 +92,12 @@ public class ImagesPlugin extends AbstractMarkwonPlugin { return this; } + /** + * @see DefaultImageMediaDecoder + * @see ru.noties.markwon.image.svg.SvgMediaDecoder + * @see ru.noties.markwon.image.gif.GifMediaDecoder + * @since 4.0.0-SNAPSHOT + */ @NonNull public ImagesPlugin addMediaDecoder(@NonNull MediaDecoder mediaDecoder) { checkBuilderState(); @@ -98,13 +105,23 @@ public class ImagesPlugin extends AbstractMarkwonPlugin { return this; } + /** + * Please note that if not specified a {@link DefaultImageMediaDecoder} will be used. So + * if you need to disable default-image-media-decoder specify here own no-op implementation. + * + * @see DefaultImageMediaDecoder + * @since 4.0.0-SNAPSHOT + */ @NonNull - public ImagesPlugin defaultMediaDecoder(@Nullable MediaDecoder mediaDecoder) { + public ImagesPlugin defaultMediaDecoder(@NonNull MediaDecoder mediaDecoder) { checkBuilderState(); builder.defaultMediaDecoder(mediaDecoder); return this; } + /** + * @since 4.0.0-SNAPSHOT + */ @NonNull public ImagesPlugin removeSchemeHandler(@NonNull String scheme) { checkBuilderState(); @@ -112,6 +129,9 @@ public class ImagesPlugin extends AbstractMarkwonPlugin { return this; } + /** + * @since 4.0.0-SNAPSHOT + */ @NonNull public ImagesPlugin removeMediaDecoder(@NonNull String contentType) { checkBuilderState(); @@ -119,6 +139,9 @@ public class ImagesPlugin extends AbstractMarkwonPlugin { return this; } + /** + * @since 4.0.0-SNAPSHOT + */ @NonNull public ImagesPlugin placeholderProvider(@NonNull PlaceholderProvider placeholderProvider) { checkBuilderState(); @@ -126,6 +149,10 @@ public class ImagesPlugin extends AbstractMarkwonPlugin { return this; } + /** + * @see ErrorHandler + * @since 4.0.0-SNAPSHOT + */ @NonNull public ImagesPlugin errorHandler(@NonNull ErrorHandler errorHandler) { checkBuilderState(); diff --git a/markwon-image/src/test/java/ru/noties/markwon/image/AsyncDrawableLoaderBuilderTest.java b/markwon-image/src/test/java/ru/noties/markwon/image/AsyncDrawableLoaderBuilderTest.java new file mode 100644 index 00000000..b2400a37 --- /dev/null +++ b/markwon-image/src/test/java/ru/noties/markwon/image/AsyncDrawableLoaderBuilderTest.java @@ -0,0 +1,194 @@ +package ru.noties.markwon.image; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; + +import java.util.Arrays; +import java.util.Collections; +import java.util.concurrent.ExecutorService; + +import ru.noties.markwon.image.data.DataUriSchemeHandler; +import ru.noties.markwon.image.network.NetworkSchemeHandler; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@RunWith(RobolectricTestRunner.class) +@Config(manifest = Config.NONE) +public class AsyncDrawableLoaderBuilderTest { + + private AsyncDrawableLoaderBuilder builder; + + @Before + public void before() { + builder = new AsyncDrawableLoaderBuilder(); + } + + @Test + public void default_scheme_handlers() { + // builder adds default data-uri and network scheme-handlers + + final String[] registered = { + DataUriSchemeHandler.SCHEME, + NetworkSchemeHandler.SCHEME_HTTP, + NetworkSchemeHandler.SCHEME_HTTPS + }; + + for (String scheme : registered) { + assertNotNull(scheme, builder.schemeHandlers.get(scheme)); + } + } + + @Test + public void built_flag() { + // isBuilt flag must be set after `build` method call + + assertFalse(builder.isBuilt); + + builder.build(); + + assertTrue(builder.isBuilt); + } + + @Test + public void defaults_initialized() { + // default-media-decoder and executor-service must be initialized + + assertNull(builder.defaultMediaDecoder); + assertNull(builder.executorService); + + builder.build(); + + assertNotNull(builder.defaultMediaDecoder); + assertNotNull(builder.executorService); + } + + @Test + public void executor() { + // supplied executor-service must be used + + assertNull(builder.executorService); + + final ExecutorService service = mock(ExecutorService.class); + builder.executorService(service); + + builder.build(); + + assertEquals(service, builder.executorService); + } + + @Test + public void add_scheme_handler() { + + final String scheme = "mock"; + assertNull(builder.schemeHandlers.get(scheme)); + + final SchemeHandler schemeHandler = mock(SchemeHandler.class); + when(schemeHandler.supportedSchemes()).thenReturn(Collections.singleton(scheme)); + + builder.addSchemeHandler(schemeHandler); + builder.build(); + + assertEquals(schemeHandler, builder.schemeHandlers.get(scheme)); + } + + @Test + public void add_scheme_handler_multiple_types() { + // all supported types are registered + + final String[] schemes = { + "mock-1", + "mock-2" + }; + + final SchemeHandler schemeHandler = mock(SchemeHandler.class); + when(schemeHandler.supportedSchemes()).thenReturn(Arrays.asList(schemes)); + + builder.addSchemeHandler(schemeHandler); + + for (String scheme : schemes) { + assertEquals(scheme, schemeHandler, builder.schemeHandlers.get(scheme)); + } + } + + @Test + public void add_media_decoder() { + + final String media = "mocked/type"; + assertNull(builder.mediaDecoders.get(media)); + + final MediaDecoder mediaDecoder = mock(MediaDecoder.class); + when(mediaDecoder.supportedTypes()).thenReturn(Collections.singleton(media)); + + builder.addMediaDecoder(mediaDecoder); + builder.build(); + + assertEquals(mediaDecoder, builder.mediaDecoders.get(media)); + } + + @Test + public void add_media_decoder_multiple_types() { + + final String[] types = { + "mock/type1", + "mock/type2" + }; + + final MediaDecoder mediaDecoder = mock(MediaDecoder.class); + when(mediaDecoder.supportedTypes()).thenReturn(Arrays.asList(types)); + + builder.addMediaDecoder(mediaDecoder); + + for (String type : types) { + assertEquals(type, mediaDecoder, builder.mediaDecoders.get(type)); + } + } + + @Test + public void default_media_decoder() { + + assertNull(builder.defaultMediaDecoder); + + final MediaDecoder mediaDecoder = mock(MediaDecoder.class); + builder.defaultMediaDecoder(mediaDecoder); + builder.build(); + + assertEquals(mediaDecoder, builder.defaultMediaDecoder); + } + + @Test + public void remove_scheme_handler() { + + final String scheme = "mock"; + final SchemeHandler schemeHandler = mock(SchemeHandler.class); + when(schemeHandler.supportedSchemes()).thenReturn(Collections.singleton(scheme)); + + assertNull(builder.schemeHandlers.get(scheme)); + builder.addSchemeHandler(schemeHandler); + assertNotNull(builder.schemeHandlers.get(scheme)); + builder.removeSchemeHandler(scheme); + assertNull(builder.schemeHandlers.get(scheme)); + } + + @Test + public void remove_media_decoder() { + + final String media = "mock/type"; + final MediaDecoder mediaDecoder = mock(MediaDecoder.class); + when(mediaDecoder.supportedTypes()).thenReturn(Collections.singleton(media)); + + assertNull(builder.mediaDecoders.get(media)); + builder.addMediaDecoder(mediaDecoder); + assertNotNull(builder.mediaDecoders.get(media)); + builder.removeMediaDecoder(media); + assertNull(builder.mediaDecoders.get(media)); + } +} \ No newline at end of file diff --git a/markwon-image/src/test/java/ru/noties/markwon/image/ImagesPluginTest.java b/markwon-image/src/test/java/ru/noties/markwon/image/ImagesPluginTest.java new file mode 100644 index 00000000..e141d456 --- /dev/null +++ b/markwon-image/src/test/java/ru/noties/markwon/image/ImagesPluginTest.java @@ -0,0 +1,177 @@ +package ru.noties.markwon.image; + +import android.support.annotation.NonNull; +import android.text.Spanned; +import android.widget.TextView; + +import org.commonmark.node.Image; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; + +import java.util.concurrent.ExecutorService; + +import ru.noties.markwon.MarkwonConfiguration; +import ru.noties.markwon.MarkwonSpansFactory; +import ru.noties.markwon.SpanFactory; +import ru.noties.markwon.image.data.DataUriSchemeHandler; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@RunWith(RobolectricTestRunner.class) +@Config(manifest = Config.NONE) +public class ImagesPluginTest { + + private ImagesPlugin plugin; + + @Before + public void before() { + plugin = ImagesPlugin.create(); + } + + @Test + public void build_state() { + // it's not possible to mutate images-plugin after `configureConfiguration` call + + // validate that it doesn't throw here + plugin.addSchemeHandler(DataUriSchemeHandler.create()); + + // mark the state + plugin.configureConfiguration(mock(MarkwonConfiguration.Builder.class)); + + final class Throws { + private void assertThrows(@NonNull Runnable action) { + //noinspection CatchMayIgnoreException + try { + action.run(); + fail(); + } catch (Throwable t) { + assertTrue(t.getMessage(), t.getMessage().contains("ImagesPlugin has already been configured")); + } + } + } + final Throws check = new Throws(); + + // executor-service + check.assertThrows(new Runnable() { + @Override + public void run() { + plugin.executorService(mock(ExecutorService.class)); + } + }); + + // add-scheme-handler + check.assertThrows(new Runnable() { + @Override + public void run() { + plugin.addSchemeHandler(mock(SchemeHandler.class)); + } + }); + + // add-media-decoder + check.assertThrows(new Runnable() { + @Override + public void run() { + plugin.addMediaDecoder(mock(MediaDecoder.class)); + } + }); + + // default-media-decoder + check.assertThrows(new Runnable() { + @Override + public void run() { + plugin.defaultMediaDecoder(mock(MediaDecoder.class)); + } + }); + + // remove-scheme-handler + check.assertThrows(new Runnable() { + @Override + public void run() { + plugin.removeSchemeHandler("mock"); + } + }); + + // remove-media-decoder + check.assertThrows(new Runnable() { + @Override + public void run() { + plugin.removeMediaDecoder("mock/type"); + } + }); + + // placeholder-provider + check.assertThrows(new Runnable() { + @Override + public void run() { + plugin.placeholderProvider(mock(ImagesPlugin.PlaceholderProvider.class)); + } + }); + + // error-handler + check.assertThrows(new Runnable() { + @Override + public void run() { + plugin.errorHandler(mock(ImagesPlugin.ErrorHandler.class)); + } + }); + + // final check if for actual `configureConfiguration` call (must be called only once) + check.assertThrows(new Runnable() { + @Override + public void run() { + plugin.configureConfiguration(mock(MarkwonConfiguration.Builder.class)); + } + }); + } + + @Test + public void image_span_factory_registered() { + + final MarkwonSpansFactory.Builder builder = mock(MarkwonSpansFactory.Builder.class); + + plugin.configureSpansFactory(builder); + + final ArgumentCaptor captor = ArgumentCaptor.forClass(SpanFactory.class); + + verify(builder, times(1)) + .setFactory(eq(Image.class), captor.capture()); + + assertNotNull(captor.getValue()); + } + + @Test + public void before_set_text() { + // verify that AsyncDrawableScheduler is called + + final TextView textView = mock(TextView.class); + + plugin.beforeSetText(textView, mock(Spanned.class)); + + verify(textView, times(1)) + .getTag(eq(R.id.markwon_drawables_scheduler_last_text_hashcode)); + } + + @Test + public void after_set_text() { + // verify that AsyncDrawableScheduler is called + + final TextView textView = mock(TextView.class); + when(textView.getText()).thenReturn("some text"); + + plugin.afterSetText(textView); + + verify(textView, times(1)) + .getTag(eq(R.id.markwon_drawables_scheduler_last_text_hashcode)); + } +} \ No newline at end of file diff --git a/markwon-linkify/README.md b/markwon-linkify/README.md new file mode 100644 index 00000000..62d2cc75 --- /dev/null +++ b/markwon-linkify/README.md @@ -0,0 +1,5 @@ +# Linkify + +Use this module (or take a hint from it) if you would need _linkify_ capabilities. Do not +use `TextView.setAutolinkMask` (or specify `autolink` in XML) because it will remove all +existing links and keep only the ones it creates. \ No newline at end of file diff --git a/markwon-linkify/src/main/java/ru/noties/markwon/linkify/LinkifyPlugin.java b/markwon-linkify/src/main/java/ru/noties/markwon/linkify/LinkifyPlugin.java index ff29c1a1..b24f3b49 100644 --- a/markwon-linkify/src/main/java/ru/noties/markwon/linkify/LinkifyPlugin.java +++ b/markwon-linkify/src/main/java/ru/noties/markwon/linkify/LinkifyPlugin.java @@ -18,8 +18,7 @@ public class LinkifyPlugin extends AbstractMarkwonPlugin { @IntDef(flag = true, value = { Linkify.EMAIL_ADDRESSES, Linkify.PHONE_NUMBERS, - Linkify.WEB_URLS, - Linkify.ALL + Linkify.WEB_URLS }) @Retention(RetentionPolicy.SOURCE) @interface LinkifyMask { From f3476ca5cc117b065e0e069a0629fb2ffc5cf696 Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Tue, 4 Jun 2019 15:41:05 +0300 Subject: [PATCH 11/42] Use Call.Factory instead of OkHttpClient in images module --- .../image/AsyncDrawableLoaderBuilder.java | 7 +- .../image/AsyncDrawableLoaderImpl.java | 156 ++++-------------- .../ru/noties/markwon/image/ImagesPlugin.java | 4 +- .../network/OkHttpNetworkSchemeHandler.java | 23 ++- .../image/AsyncDrawableLoaderImplTest.java | 99 +++++++++++ 5 files changed, 153 insertions(+), 136 deletions(-) create mode 100644 markwon-image/src/test/java/ru/noties/markwon/image/AsyncDrawableLoaderImplTest.java diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderBuilder.java b/markwon-image/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderBuilder.java index 57347b70..a57ca99b 100644 --- a/markwon-image/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderBuilder.java +++ b/markwon-image/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderBuilder.java @@ -29,6 +29,8 @@ class AsyncDrawableLoaderBuilder { // we should not use file-scheme as it's a bit complicated to assume file usage (lack of permissions) addSchemeHandler(DataUriSchemeHandler.create()); addSchemeHandler(NetworkSchemeHandler.create()); + + defaultMediaDecoder = DefaultImageMediaDecoder.create(); } void executorService(@NonNull ExecutorService executorService) { @@ -78,11 +80,6 @@ class AsyncDrawableLoaderBuilder { isBuilt = true; - // @since 4.0.0-SNAPSHOT - if (defaultMediaDecoder == null) { - defaultMediaDecoder = DefaultImageMediaDecoder.create(); - } - if (executorService == null) { executorService = Executors.newCachedThreadPool(); } diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderImpl.java b/markwon-image/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderImpl.java index a0226c48..01b12282 100644 --- a/markwon-image/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderImpl.java +++ b/markwon-image/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderImpl.java @@ -4,8 +4,10 @@ import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Handler; import android.os.Looper; +import android.os.SystemClock; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.support.annotation.VisibleForTesting; import android.util.Log; import java.lang.ref.WeakReference; @@ -24,126 +26,45 @@ class AsyncDrawableLoaderImpl extends AsyncDrawableLoader { private final ImagesPlugin.PlaceholderProvider placeholderProvider; private final ImagesPlugin.ErrorHandler errorHandler; - private final Handler mainThread; + private final Handler handler; - // @since 3.1.0-SNAPSHOT use a hash-map with a weak AsyncDrawable as key for multiple requests + // @since 4.0.0-SNAPSHOT use a hash-map with a AsyncDrawable as key for multiple requests // for the same destination - private final Map, Future> requests = new HashMap<>(2); + private final Map> requests = new HashMap<>(2); AsyncDrawableLoaderImpl(@NonNull AsyncDrawableLoaderBuilder builder) { + this(builder, new Handler(Looper.getMainLooper())); + } + + // @since 4.0.0-SNAPSHOT + @VisibleForTesting + AsyncDrawableLoaderImpl(@NonNull AsyncDrawableLoaderBuilder builder, @NonNull Handler handler) { this.executorService = builder.executorService; this.schemeHandlers = builder.schemeHandlers; this.mediaDecoders = builder.mediaDecoders; this.defaultMediaDecoder = builder.defaultMediaDecoder; this.placeholderProvider = builder.placeholderProvider; this.errorHandler = builder.errorHandler; - this.mainThread = new Handler(Looper.getMainLooper()); + this.handler = handler; } @Override public void load(@NonNull final AsyncDrawable drawable) { - - // primitive synchronization via main-thread - if (!isMainThread()) { - mainThread.post(new Runnable() { - @Override - public void run() { - load(drawable); - } - }); - return; + final Future future = requests.get(drawable); + if (future == null) { + requests.put(drawable, execute(drawable)); } - - // okay, if by some chance requested drawable already has a future associated -> no-op - // as AsyncDrawable cannot change `destination` (immutable field) - // @since 3.1.0-SNAPSHOT - if (hasTaskAssociated(drawable)) { - return; - } - - final WeakReference reference = new WeakReference<>(drawable); - requests.put(reference, execute(drawable.getDestination(), reference)); } @Override public void cancel(@NonNull final AsyncDrawable drawable) { - if (!isMainThread()) { - mainThread.post(new Runnable() { - @Override - public void run() { - cancel(drawable); - } - }); - return; + final Future future = requests.remove(drawable); + if (future != null) { + future.cancel(true); } - final Iterator, Future>> iterator = - requests.entrySet().iterator(); - - AsyncDrawable key; - Map.Entry, Future> entry; - - while (iterator.hasNext()) { - - entry = iterator.next(); - key = entry.getKey().get(); - - // if key is null or it contains requested AsyncDrawable -> cancel - if (shouldCleanUp(key) || key == drawable) { - entry.getValue().cancel(true); - iterator.remove(); - } - } - } - - private boolean hasTaskAssociated(@NonNull AsyncDrawable drawable) { - - final Iterator, Future>> iterator = - requests.entrySet().iterator(); - - boolean result = false; - - AsyncDrawable key; - Map.Entry, Future> entry; - - while (iterator.hasNext()) { - - entry = iterator.next(); - key = entry.getKey().get(); - - // clean-up - if (shouldCleanUp(key)) { - entry.getValue().cancel(true); - iterator.remove(); - } else if (key == drawable) { - result = true; - // do not break, let iteration continue to possibly clean-up the rest references - } - } - - return result; - } - - private void cleanUp() { - - final Iterator, Future>> iterator = - requests.entrySet().iterator(); - - AsyncDrawable key; - Map.Entry, Future> entry; - - while (iterator.hasNext()) { - - entry = iterator.next(); - key = entry.getKey().get(); - - // clean-up of already referenced or detached drawables - if (shouldCleanUp(key)) { - entry.getValue().cancel(true); - iterator.remove(); - } - } + handler.removeCallbacksAndMessages(drawable); } @Nullable @@ -155,7 +76,7 @@ class AsyncDrawableLoaderImpl extends AsyncDrawableLoader { } @NonNull - private Future execute(@NonNull final String destination, @NonNull final WeakReference reference) { + private Future execute(@NonNull final AsyncDrawable asyncDrawable) { // todo: more efficient DefaultImageMediaDecoder... BitmapFactory.decodeStream is a bit not optimal // for big images for sure. We _could_ introduce internal Drawable that will check for @@ -166,6 +87,8 @@ class AsyncDrawableLoaderImpl extends AsyncDrawableLoader { @Override public void run() { + final String destination = asyncDrawable.getDestination(); + final Uri uri = Uri.parse(destination); Drawable drawable = null; @@ -214,35 +137,22 @@ class AsyncDrawableLoaderImpl extends AsyncDrawableLoader { final Drawable out = drawable; - mainThread.post(new Runnable() { + handler.postAtTime(new Runnable() { @Override public void run() { - - if (out != null) { - // AsyncDrawable cannot change destination, so if it's - // attached and not garbage-collected, we can deliver the result. - // Note that there is no cache, so attach/detach of drawables - // will always request a new entry.. (comment @since 3.1.0-SNAPSHOT) - final AsyncDrawable asyncDrawable = reference.get(); - if (asyncDrawable != null && asyncDrawable.isAttached()) { - asyncDrawable.setResult(out); - } + // validate that + // * request was not cancelled + // * out-result is present + // * async-drawable is attached + final Future future = requests.remove(asyncDrawable); + if (future != null + && out != null + && asyncDrawable.isAttached()) { + asyncDrawable.setResult(out); } - - requests.remove(reference); - cleanUp(); } - }); + }, asyncDrawable, SystemClock.uptimeMillis()); } }); } - - private static boolean shouldCleanUp(@Nullable AsyncDrawable drawable) { - return drawable == null || !drawable.isAttached(); - } - - @SuppressWarnings("BooleanMethodIsAlwaysInverted") - private static boolean isMainThread() { - return Looper.myLooper() == Looper.getMainLooper(); - } } diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/ImagesPlugin.java b/markwon-image/src/main/java/ru/noties/markwon/image/ImagesPlugin.java index e5cac9b3..ee5d3cc9 100644 --- a/markwon-image/src/main/java/ru/noties/markwon/image/ImagesPlugin.java +++ b/markwon-image/src/main/java/ru/noties/markwon/image/ImagesPlugin.java @@ -107,13 +107,13 @@ public class ImagesPlugin extends AbstractMarkwonPlugin { /** * Please note that if not specified a {@link DefaultImageMediaDecoder} will be used. So - * if you need to disable default-image-media-decoder specify here own no-op implementation. + * if you need to disable default-image-media-decoder specify here own no-op implementation or null. * * @see DefaultImageMediaDecoder * @since 4.0.0-SNAPSHOT */ @NonNull - public ImagesPlugin defaultMediaDecoder(@NonNull MediaDecoder mediaDecoder) { + public ImagesPlugin defaultMediaDecoder(@Nullable MediaDecoder mediaDecoder) { checkBuilderState(); builder.defaultMediaDecoder(mediaDecoder); return this; diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/network/OkHttpNetworkSchemeHandler.java b/markwon-image/src/main/java/ru/noties/markwon/image/network/OkHttpNetworkSchemeHandler.java index 9feddd0f..b470841d 100644 --- a/markwon-image/src/main/java/ru/noties/markwon/image/network/OkHttpNetworkSchemeHandler.java +++ b/markwon-image/src/main/java/ru/noties/markwon/image/network/OkHttpNetworkSchemeHandler.java @@ -7,6 +7,7 @@ import java.io.InputStream; import java.util.Arrays; import java.util.Collection; +import okhttp3.Call; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; @@ -24,21 +25,31 @@ public class OkHttpNetworkSchemeHandler extends SchemeHandler { */ @NonNull public static OkHttpNetworkSchemeHandler create() { - return new OkHttpNetworkSchemeHandler(new OkHttpClient()); + return create(new OkHttpClient()); } @NonNull public static OkHttpNetworkSchemeHandler create(@NonNull OkHttpClient client) { - return new OkHttpNetworkSchemeHandler(client); + // explicit cast, otherwise a recursive call + return create((Call.Factory) client); + } + + /** + * @since 4.0.0-SNAPSHOT + */ + @NonNull + public static OkHttpNetworkSchemeHandler create(@NonNull Call.Factory factory) { + return new OkHttpNetworkSchemeHandler(factory); } private static final String HEADER_CONTENT_TYPE = "Content-Type"; - private final OkHttpClient client; + // @since 4.0.0-SNAPSHOT, previously just OkHttpClient + private final Call.Factory factory; @SuppressWarnings("WeakerAccess") - OkHttpNetworkSchemeHandler(@NonNull OkHttpClient client) { - this.client = client; + OkHttpNetworkSchemeHandler(@NonNull Call.Factory factory) { + this.factory = factory; } @NonNull @@ -52,7 +63,7 @@ public class OkHttpNetworkSchemeHandler extends SchemeHandler { final Response response; try { - response = client.newCall(request).execute(); + response = factory.newCall(request).execute(); } catch (Throwable t) { throw new IllegalStateException("Exception obtaining network resource: " + raw, t); } diff --git a/markwon-image/src/test/java/ru/noties/markwon/image/AsyncDrawableLoaderImplTest.java b/markwon-image/src/test/java/ru/noties/markwon/image/AsyncDrawableLoaderImplTest.java new file mode 100644 index 00000000..80e2bf53 --- /dev/null +++ b/markwon-image/src/test/java/ru/noties/markwon/image/AsyncDrawableLoaderImplTest.java @@ -0,0 +1,99 @@ +package ru.noties.markwon.image; + +import android.os.Handler; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; + +import java.util.concurrent.ExecutorService; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +@RunWith(RobolectricTestRunner.class) +@Config(manifest = Config.NONE) +public class AsyncDrawableLoaderImplTest { + + private BuilderImpl builder; + private AsyncDrawableLoaderImpl impl; + + @Before + public void before() { + builder = new BuilderImpl(); + } + + @Test + public void placeholder() { + final ImagesPlugin.PlaceholderProvider placeholderProvider = + mock(ImagesPlugin.PlaceholderProvider.class); + impl = builder.placeholderProvider(placeholderProvider) + .build(); + impl.placeholder(mock(AsyncDrawable.class)); + verify(placeholderProvider, times(1)) + .providePlaceholder(any(AsyncDrawable.class)); + } + + private static class BuilderImpl { + + AsyncDrawableLoaderBuilder builder; + Handler handler = mock(Handler.class); + + public BuilderImpl executorService(@NonNull ExecutorService executorService) { + builder.executorService(executorService); + return this; + } + + public BuilderImpl addSchemeHandler(@NonNull SchemeHandler schemeHandler) { + builder.addSchemeHandler(schemeHandler); + return this; + } + + public BuilderImpl addMediaDecoder(@NonNull MediaDecoder mediaDecoder) { + builder.addMediaDecoder(mediaDecoder); + return this; + } + + public BuilderImpl defaultMediaDecoder(@Nullable MediaDecoder mediaDecoder) { + builder.defaultMediaDecoder(mediaDecoder); + return this; + } + + public BuilderImpl removeSchemeHandler(@NonNull String scheme) { + builder.removeSchemeHandler(scheme); + return this; + } + + public BuilderImpl removeMediaDecoder(@NonNull String contentType) { + builder.removeMediaDecoder(contentType); + return this; + } + + public BuilderImpl placeholderProvider(@NonNull ImagesPlugin.PlaceholderProvider placeholderDrawableProvider) { + builder.placeholderProvider(placeholderDrawableProvider); + return this; + } + + public BuilderImpl errorHandler(@NonNull ImagesPlugin.ErrorHandler errorHandler) { + builder.errorHandler(errorHandler); + return this; + } + + @NonNull + public BuilderImpl handler(Handler handler) { + this.handler = handler; + return this; + } + + @NonNull + AsyncDrawableLoaderImpl build() { + return new AsyncDrawableLoaderImpl(builder, handler); + } + } +} \ No newline at end of file From df0177af95ba962311179aa0de793526070fced8 Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Tue, 4 Jun 2019 16:32:35 +0300 Subject: [PATCH 12/42] Move HTML specifics to html module --- _CHANGES.md | 4 +- .../noties/markwon/AbstractMarkwonPlugin.java | 5 - .../ru/noties/markwon/MarkwonBuilderImpl.java | 4 - .../noties/markwon/MarkwonConfiguration.java | 16 ++- .../java/ru/noties/markwon/MarkwonPlugin.java | 20 ++-- .../markwon/html/MarkwonHtmlRenderer.java | 38 +------ .../ru/noties/markwon/html/TagHandler.java | 9 ++ .../ru/noties/markwon/html/HtmlPlugin.java | 101 +++++++++--------- .../markwon/html/MarkwonHtmlParserImpl.java | 1 - .../markwon/html/MarkwonHtmlRendererImpl.java | 99 +++++++++++------ .../noties/markwon/html/TagHandlerNoOp.java | 43 ++++++++ .../markwon/html/tag/BlockquoteHandler.java | 9 ++ .../markwon/html/tag/EmphasisHandler.java | 9 ++ .../markwon/html/tag/HeadingHandler.java | 9 ++ .../noties/markwon/html/tag/ImageHandler.java | 9 ++ .../noties/markwon/html/tag/LinkHandler.java | 9 ++ .../noties/markwon/html/tag/ListHandler.java | 9 ++ .../markwon/html/tag/SimpleTagHandler.java | 7 ++ .../markwon/html/tag/StrikeHandler.java | 9 ++ .../html/tag/StrongEmphasisHandler.java | 9 ++ .../markwon/html/tag/SubScriptHandler.java | 9 ++ .../markwon/html/tag/SuperScriptHandler.java | 9 ++ .../markwon/html/tag/UnderlineHandler.java | 9 ++ 23 files changed, 307 insertions(+), 139 deletions(-) rename {markwon-core => markwon-html}/src/main/java/ru/noties/markwon/html/MarkwonHtmlRendererImpl.java (58%) create mode 100644 markwon-html/src/main/java/ru/noties/markwon/html/TagHandlerNoOp.java diff --git a/_CHANGES.md b/_CHANGES.md index 4695759f..28856328 100644 --- a/_CHANGES.md +++ b/_CHANGES.md @@ -6,4 +6,6 @@ internally caches latest state and skips scheduling if drawables are already processed * configure with registry * removed priority -* images-plugin moved to standalone again \ No newline at end of file +* images-plugin moved to standalone again +* removed MarkwonPlugin#configureHtmlRenderer -> now part of HtmlPlugin +* TagHandler now has `supportedTags()` method \ No newline at end of file diff --git a/markwon-core/src/main/java/ru/noties/markwon/AbstractMarkwonPlugin.java b/markwon-core/src/main/java/ru/noties/markwon/AbstractMarkwonPlugin.java index ae05550a..4fb39da0 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/AbstractMarkwonPlugin.java +++ b/markwon-core/src/main/java/ru/noties/markwon/AbstractMarkwonPlugin.java @@ -49,11 +49,6 @@ public abstract class AbstractMarkwonPlugin implements MarkwonPlugin { } - @Override - public void configureHtmlRenderer(@NonNull MarkwonHtmlRenderer.Builder builder) { - - } - @NonNull @Override public String processMarkdown(@NonNull String markdown) { diff --git a/markwon-core/src/main/java/ru/noties/markwon/MarkwonBuilderImpl.java b/markwon-core/src/main/java/ru/noties/markwon/MarkwonBuilderImpl.java index b650ff1b..863cfe30 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/MarkwonBuilderImpl.java +++ b/markwon-core/src/main/java/ru/noties/markwon/MarkwonBuilderImpl.java @@ -16,7 +16,6 @@ import java.util.List; import java.util.Set; import ru.noties.markwon.core.MarkwonTheme; -import ru.noties.markwon.html.MarkwonHtmlRenderer; /** * @since 3.0.0 @@ -84,7 +83,6 @@ class MarkwonBuilderImpl implements Markwon.Builder { final MarkwonConfiguration.Builder configurationBuilder = new MarkwonConfiguration.Builder(); final MarkwonVisitor.Builder visitorBuilder = new MarkwonVisitorImpl.BuilderImpl(); final MarkwonSpansFactory.Builder spanFactoryBuilder = new MarkwonSpansFactoryImpl.BuilderImpl(); - final MarkwonHtmlRenderer.Builder htmlRendererBuilder = MarkwonHtmlRenderer.builder(); for (MarkwonPlugin plugin : plugins) { plugin.configureParser(parserBuilder); @@ -92,12 +90,10 @@ class MarkwonBuilderImpl implements Markwon.Builder { plugin.configureConfiguration(configurationBuilder); plugin.configureVisitor(visitorBuilder); plugin.configureSpansFactory(spanFactoryBuilder); - plugin.configureHtmlRenderer(htmlRendererBuilder); } final MarkwonConfiguration configuration = configurationBuilder.build( themeBuilder.build(), - htmlRendererBuilder.build(), spanFactoryBuilder.build()); final RenderProps renderProps = new RenderPropsImpl(); diff --git a/markwon-core/src/main/java/ru/noties/markwon/MarkwonConfiguration.java b/markwon-core/src/main/java/ru/noties/markwon/MarkwonConfiguration.java index af65fdb4..66159da4 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/MarkwonConfiguration.java +++ b/markwon-core/src/main/java/ru/noties/markwon/MarkwonConfiguration.java @@ -122,6 +122,15 @@ public class MarkwonConfiguration { return this; } + /** + * @since 4.0.0-SNAPSHOT + */ + @NonNull + public Builder htmlRenderer(@NonNull MarkwonHtmlRenderer htmlRenderer) { + this.htmlRenderer = htmlRenderer; + return this; + } + @NonNull public Builder syntaxHighlight(@NonNull SyntaxHighlight syntaxHighlight) { this.syntaxHighlight = syntaxHighlight; @@ -158,11 +167,9 @@ public class MarkwonConfiguration { @NonNull public MarkwonConfiguration build( @NonNull MarkwonTheme theme, - @NonNull MarkwonHtmlRenderer htmlRenderer, @NonNull MarkwonSpansFactory spansFactory) { this.theme = theme; - this.htmlRenderer = htmlRenderer; this.spansFactory = spansFactory; // @since 4.0.0-SNAPSHOT @@ -170,6 +177,11 @@ public class MarkwonConfiguration { asyncDrawableLoader = AsyncDrawableLoader.noOp(); } + // @since 4.0.0-SNAPSHOT + if (htmlRenderer == null) { + htmlRenderer = MarkwonHtmlRenderer.noOp(); + } + if (syntaxHighlight == null) { syntaxHighlight = new SyntaxHighlightNoOp(); } diff --git a/markwon-core/src/main/java/ru/noties/markwon/MarkwonPlugin.java b/markwon-core/src/main/java/ru/noties/markwon/MarkwonPlugin.java index 8bc4dc8d..fb7f1022 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/MarkwonPlugin.java +++ b/markwon-core/src/main/java/ru/noties/markwon/MarkwonPlugin.java @@ -16,7 +16,7 @@ import ru.noties.markwon.html.MarkwonHtmlRenderer; * * @see AbstractMarkwonPlugin * @see ru.noties.markwon.core.CorePlugin - * @see ru.noties.markwon.image.ImagesPlugin + * @see ru.noties.markwon.movement.MovementMethodPlugin * @since 3.0.0 */ public interface MarkwonPlugin { @@ -88,13 +88,13 @@ public interface MarkwonPlugin { */ void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder); - /** - * Configure {@link MarkwonHtmlRenderer} to add or remove HTML {@link ru.noties.markwon.html.TagHandler}s - * - * @see MarkwonHtmlRenderer - * @see MarkwonHtmlRenderer.Builder - */ - void configureHtmlRenderer(@NonNull MarkwonHtmlRenderer.Builder builder); +// /** +// * Configure {@link MarkwonHtmlRenderer} to add or remove HTML {@link ru.noties.markwon.html.TagHandler}s +// * +// * @see MarkwonHtmlRenderer +// * @see MarkwonHtmlRenderer.Builder +// */ +// void configureHtmlRenderer(@NonNull MarkwonHtmlRenderer.Builder builder); /** * Process input markdown and return new string to be used in parsing stage further. @@ -128,7 +128,7 @@ public interface MarkwonPlugin { /** * This method will be called before calling TextView#setText. *

- * It can be useful to prepare a TextView for markdown. For example {@link ru.noties.markwon.image.ImagesPlugin} + * It can be useful to prepare a TextView for markdown. For example {@code ru.noties.markwon.image.ImagesPlugin} * uses this method to unregister previously registered {@link ru.noties.markwon.image.AsyncDrawableSpan} * (if there are such spans in this TextView at this point). Or {@link ru.noties.markwon.core.CorePlugin} * which measures ordered list numbers @@ -141,7 +141,7 @@ public interface MarkwonPlugin { /** * This method will be called after markdown was applied. *

- * It can be useful to trigger certain action on spans/textView. For example {@link ru.noties.markwon.image.ImagesPlugin} + * It can be useful to trigger certain action on spans/textView. For example {@code ru.noties.markwon.image.ImagesPlugin} * uses this method to register {@link ru.noties.markwon.image.AsyncDrawableSpan} and start * asynchronously loading images. *

diff --git a/markwon-core/src/main/java/ru/noties/markwon/html/MarkwonHtmlRenderer.java b/markwon-core/src/main/java/ru/noties/markwon/html/MarkwonHtmlRenderer.java index 93d0411d..88bf8709 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/html/MarkwonHtmlRenderer.java +++ b/markwon-core/src/main/java/ru/noties/markwon/html/MarkwonHtmlRenderer.java @@ -3,8 +3,6 @@ package ru.noties.markwon.html; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import java.util.Collection; - import ru.noties.markwon.MarkwonVisitor; /** @@ -12,9 +10,12 @@ import ru.noties.markwon.MarkwonVisitor; */ public abstract class MarkwonHtmlRenderer { + /** + * @since 4.0.0-SNAPSHOT + */ @NonNull - public static Builder builder() { - return new MarkwonHtmlRendererImpl.BuilderImpl(); + public static MarkwonHtmlRenderer noOp() { + return new MarkwonHtmlRendererNoOp(); } public abstract void render( @@ -24,33 +25,4 @@ public abstract class MarkwonHtmlRenderer { @Nullable public abstract TagHandler tagHandler(@NonNull String tagName); - - - /** - * @since 3.0.0 - */ - public interface Builder { - - /** - * @param allowNonClosedTags parameter to indicate that all non-closed HTML tags should be - * closed at the end of a document. if {@code true} all non-closed - * tags will be force-closed at the end. Otherwise these tags will be - * ignored and thus not rendered. - * @return self - */ - @NonNull - Builder allowNonClosedTags(boolean allowNonClosedTags); - - @NonNull - Builder setHandler(@NonNull String tagName, @Nullable TagHandler tagHandler); - - @NonNull - Builder setHandler(@NonNull Collection tagNames, @Nullable TagHandler tagHandler); - - @Nullable - TagHandler getHandler(@NonNull String tagName); - - @NonNull - MarkwonHtmlRenderer build(); - } } diff --git a/markwon-core/src/main/java/ru/noties/markwon/html/TagHandler.java b/markwon-core/src/main/java/ru/noties/markwon/html/TagHandler.java index 84122946..28c2c068 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/html/TagHandler.java +++ b/markwon-core/src/main/java/ru/noties/markwon/html/TagHandler.java @@ -2,6 +2,8 @@ package ru.noties.markwon.html; import android.support.annotation.NonNull; +import java.util.Collection; + import ru.noties.markwon.MarkwonVisitor; public abstract class TagHandler { @@ -12,6 +14,13 @@ public abstract class TagHandler { @NonNull HtmlTag tag ); + /** + * @since 4.0.0-SNAPSHOT + */ + @NonNull + public abstract Collection supportedTags(); + + protected static void visitChildren( @NonNull MarkwonVisitor visitor, @NonNull MarkwonHtmlRenderer renderer, diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/HtmlPlugin.java b/markwon-html/src/main/java/ru/noties/markwon/html/HtmlPlugin.java index d087058e..4fa633f4 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/HtmlPlugin.java +++ b/markwon-html/src/main/java/ru/noties/markwon/html/HtmlPlugin.java @@ -10,19 +10,6 @@ import org.commonmark.node.Node; import ru.noties.markwon.AbstractMarkwonPlugin; import ru.noties.markwon.MarkwonConfiguration; import ru.noties.markwon.MarkwonVisitor; -import ru.noties.markwon.html.tag.BlockquoteHandler; -import ru.noties.markwon.html.tag.EmphasisHandler; -import ru.noties.markwon.html.tag.HeadingHandler; -import ru.noties.markwon.html.tag.ImageHandler; -import ru.noties.markwon.html.tag.LinkHandler; -import ru.noties.markwon.html.tag.ListHandler; -import ru.noties.markwon.html.tag.StrikeHandler; -import ru.noties.markwon.html.tag.StrongEmphasisHandler; -import ru.noties.markwon.html.tag.SubScriptHandler; -import ru.noties.markwon.html.tag.SuperScriptHandler; -import ru.noties.markwon.html.tag.UnderlineHandler; - -import static java.util.Arrays.asList; /** * @since 3.0.0 @@ -36,48 +23,60 @@ public class HtmlPlugin extends AbstractMarkwonPlugin { public static final float SCRIPT_DEF_TEXT_SIZE_RATIO = .75F; - @Override - public void configureConfiguration(@NonNull MarkwonConfiguration.Builder builder) { - builder.htmlParser(MarkwonHtmlParserImpl.create()); + private final MarkwonHtmlRendererImpl.Builder builder; + + @SuppressWarnings("WeakerAccess") + HtmlPlugin() { + this.builder = new MarkwonHtmlRendererImpl.Builder(); + } + + /** + * @param allowNonClosedTags whether or not non-closed tags should be closed + * at the document end. By default `false` + * @since 4.0.0-SNAPSHOT + */ + @NonNull + public HtmlPlugin allowNonClosedTags(boolean allowNonClosedTags) { + builder.allowNonClosedTags(allowNonClosedTags); + return this; + } + + /** + * @since 4.0.0-SNAPSHOT + */ + @NonNull + public HtmlPlugin addHandler(@NonNull TagHandler tagHandler) { + builder.addHandler(tagHandler); + return this; + } + + /** + * @since 4.0.0-SNAPSHOT + */ + @Nullable + public TagHandler getHandler(@NonNull String tagName) { + return builder.getHandler(tagName); + } + + /** + * Indicate if HtmlPlugin should register default HTML tag handlers. Pass `true` to not + * include default handlers. By default default handlers are included. You can use + * {@link TagHandlerNoOp} to no-op certain default tags. + * + * @see TagHandlerNoOp + * @since 4.0.0-SNAPSHOT + */ + @NonNull + public HtmlPlugin excludeDefaults(boolean excludeDefaults) { + builder.excludeDefaults(excludeDefaults); + return this; } @Override - public void configureHtmlRenderer(@NonNull MarkwonHtmlRenderer.Builder builder) { - + public void configureConfiguration(@NonNull MarkwonConfiguration.Builder builder) { builder - .setHandler( - "img", - ImageHandler.create()) - .setHandler( - "a", - new LinkHandler()) - .setHandler( - "blockquote", - new BlockquoteHandler()) - .setHandler( - "sub", - new SubScriptHandler()) - .setHandler( - "sup", - new SuperScriptHandler()) - .setHandler( - asList("b", "strong"), - new StrongEmphasisHandler()) - .setHandler( - asList("s", "del"), - new StrikeHandler()) - .setHandler( - asList("u", "ins"), - new UnderlineHandler()) - .setHandler( - asList("ul", "ol"), - new ListHandler()) - .setHandler( - asList("i", "em", "cite", "dfn"), - new EmphasisHandler()) - .setHandler( - asList("h1", "h2", "h3", "h4", "h5", "h6"), - new HeadingHandler()); + .htmlRenderer(this.builder.build()) + .htmlParser(MarkwonHtmlParserImpl.create()); } @Override diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/MarkwonHtmlParserImpl.java b/markwon-html/src/main/java/ru/noties/markwon/html/MarkwonHtmlParserImpl.java index 6d715510..e0f4a9e3 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/MarkwonHtmlParserImpl.java +++ b/markwon-html/src/main/java/ru/noties/markwon/html/MarkwonHtmlParserImpl.java @@ -195,7 +195,6 @@ public class MarkwonHtmlParserImpl extends MarkwonHtmlParser { } } - //noinspection unchecked action.apply(Collections.unmodifiableList((List) inlineTags)); inlineTags.clear(); } else { diff --git a/markwon-core/src/main/java/ru/noties/markwon/html/MarkwonHtmlRendererImpl.java b/markwon-html/src/main/java/ru/noties/markwon/html/MarkwonHtmlRendererImpl.java similarity index 58% rename from markwon-core/src/main/java/ru/noties/markwon/html/MarkwonHtmlRendererImpl.java rename to markwon-html/src/main/java/ru/noties/markwon/html/MarkwonHtmlRendererImpl.java index 0f4c97e6..3699f5f5 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/html/MarkwonHtmlRendererImpl.java +++ b/markwon-html/src/main/java/ru/noties/markwon/html/MarkwonHtmlRendererImpl.java @@ -3,19 +3,30 @@ package ru.noties.markwon.html; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import ru.noties.markwon.MarkwonVisitor; +import ru.noties.markwon.html.tag.BlockquoteHandler; +import ru.noties.markwon.html.tag.EmphasisHandler; +import ru.noties.markwon.html.tag.HeadingHandler; +import ru.noties.markwon.html.tag.ImageHandler; +import ru.noties.markwon.html.tag.LinkHandler; +import ru.noties.markwon.html.tag.ListHandler; +import ru.noties.markwon.html.tag.StrikeHandler; +import ru.noties.markwon.html.tag.StrongEmphasisHandler; +import ru.noties.markwon.html.tag.SubScriptHandler; +import ru.noties.markwon.html.tag.SuperScriptHandler; +import ru.noties.markwon.html.tag.UnderlineHandler; class MarkwonHtmlRendererImpl extends MarkwonHtmlRenderer { private final boolean allowNonClosedTags; private final Map tagHandlers; + @SuppressWarnings("WeakerAccess") MarkwonHtmlRendererImpl(boolean allowNonClosedTags, @NonNull Map tagHandlers) { this.allowNonClosedTags = allowNonClosedTags; this.tagHandlers = tagHandlers; @@ -86,58 +97,82 @@ class MarkwonHtmlRendererImpl extends MarkwonHtmlRenderer { return tagHandlers.get(tagName); } - static class BuilderImpl implements Builder { + static class Builder { private final Map tagHandlers = new HashMap<>(2); private boolean allowNonClosedTags; + private boolean excludeDefaults; - @NonNull - @Override - public Builder allowNonClosedTags(boolean allowNonClosedTags) { + private boolean isBuilt; + + void allowNonClosedTags(boolean allowNonClosedTags) { + checkState(); this.allowNonClosedTags = allowNonClosedTags; - return this; } - @NonNull - @Override - public Builder setHandler(@NonNull String tagName, @Nullable TagHandler tagHandler) { - if (tagHandler == null) { - tagHandlers.remove(tagName); - } else { - tagHandlers.put(tagName, tagHandler); + void addHandler(@NonNull TagHandler tagHandler) { + checkState(); + for (String tag : tagHandler.supportedTags()) { + tagHandlers.put(tag, tagHandler); } - return this; - } - - @NonNull - @Override - public Builder setHandler(@NonNull Collection tagNames, @Nullable TagHandler tagHandler) { - if (tagHandler == null) { - for (String tagName : tagNames) { - tagHandlers.remove(tagName); - } - } else { - for (String tagName : tagNames) { - tagHandlers.put(tagName, tagHandler); - } - } - return this; } @Nullable - @Override - public TagHandler getHandler(@NonNull String tagName) { + TagHandler getHandler(@NonNull String tagName) { + checkState(); return tagHandlers.get(tagName); } + public void excludeDefaults(boolean excludeDefaults) { + checkState(); + this.excludeDefaults = excludeDefaults; + } + @NonNull - @Override public MarkwonHtmlRenderer build() { + + checkState(); + + isBuilt = true; + + if (!excludeDefaults) { + // register default handlers, check if a handler is present already for specified tag + registerDefaultHandlers(); + } + // okay, let's validate that we have at least one tagHandler registered // if we have none -> return no-op implementation return tagHandlers.size() > 0 ? new MarkwonHtmlRendererImpl(allowNonClosedTags, Collections.unmodifiableMap(tagHandlers)) : new MarkwonHtmlRendererNoOp(); } + + private void checkState() { + if (isBuilt) { + throw new IllegalStateException("Builder has been already built"); + } + } + + private void registerDefaultHandlers() { + add(ImageHandler.create()); + add(new LinkHandler()); + add(new BlockquoteHandler()); + add(new SubScriptHandler()); + add(new SuperScriptHandler()); + add(new StrongEmphasisHandler()); + add(new StrikeHandler()); + add(new UnderlineHandler()); + add(new ListHandler()); + add(new EmphasisHandler()); + add(new HeadingHandler()); + } + + private void add(@NonNull TagHandler tagHandler) { + for (String tag : tagHandler.supportedTags()) { + if (!tagHandlers.containsKey(tag)) { + tagHandlers.put(tag, tagHandler); + } + } + } } } diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/TagHandlerNoOp.java b/markwon-html/src/main/java/ru/noties/markwon/html/TagHandlerNoOp.java new file mode 100644 index 00000000..c96d6867 --- /dev/null +++ b/markwon-html/src/main/java/ru/noties/markwon/html/TagHandlerNoOp.java @@ -0,0 +1,43 @@ +package ru.noties.markwon.html; + +import android.support.annotation.NonNull; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; + +import ru.noties.markwon.MarkwonVisitor; + +/** + * @since 4.0.0-SNAPSHOT + */ +public class TagHandlerNoOp extends TagHandler { + + @NonNull + public static TagHandlerNoOp create(@NonNull String tag) { + return new TagHandlerNoOp(Collections.singleton(tag)); + } + + @NonNull + public static TagHandlerNoOp create(@NonNull String... tags) { + return new TagHandlerNoOp(Arrays.asList(tags)); + } + + private final Collection tags; + + @SuppressWarnings("WeakerAccess") + TagHandlerNoOp(Collection tags) { + this.tags = tags; + } + + @Override + public void handle(@NonNull MarkwonVisitor visitor, @NonNull MarkwonHtmlRenderer renderer, @NonNull HtmlTag tag) { + // no op + } + + @NonNull + @Override + public Collection supportedTags() { + return tags; + } +} diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/tag/BlockquoteHandler.java b/markwon-html/src/main/java/ru/noties/markwon/html/tag/BlockquoteHandler.java index 930a8dda..31ed4916 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/tag/BlockquoteHandler.java +++ b/markwon-html/src/main/java/ru/noties/markwon/html/tag/BlockquoteHandler.java @@ -4,6 +4,9 @@ import android.support.annotation.NonNull; import org.commonmark.node.BlockQuote; +import java.util.Collection; +import java.util.Collections; + import ru.noties.markwon.MarkwonConfiguration; import ru.noties.markwon.MarkwonVisitor; import ru.noties.markwon.SpanFactory; @@ -35,4 +38,10 @@ public class BlockquoteHandler extends TagHandler { ); } } + + @NonNull + @Override + public Collection supportedTags() { + return Collections.singleton("blockquote"); + } } diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/tag/EmphasisHandler.java b/markwon-html/src/main/java/ru/noties/markwon/html/tag/EmphasisHandler.java index fe546ee0..a5e62c40 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/tag/EmphasisHandler.java +++ b/markwon-html/src/main/java/ru/noties/markwon/html/tag/EmphasisHandler.java @@ -5,6 +5,9 @@ import android.support.annotation.Nullable; import org.commonmark.node.Emphasis; +import java.util.Arrays; +import java.util.Collection; + import ru.noties.markwon.MarkwonConfiguration; import ru.noties.markwon.RenderProps; import ru.noties.markwon.SpanFactory; @@ -23,4 +26,10 @@ public class EmphasisHandler extends SimpleTagHandler { } return spanFactory.getSpans(configuration, renderProps); } + + @NonNull + @Override + public Collection supportedTags() { + return Arrays.asList("i", "em", "cite", "dfn"); + } } diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/tag/HeadingHandler.java b/markwon-html/src/main/java/ru/noties/markwon/html/tag/HeadingHandler.java index a7de3a47..8c778f94 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/tag/HeadingHandler.java +++ b/markwon-html/src/main/java/ru/noties/markwon/html/tag/HeadingHandler.java @@ -5,6 +5,9 @@ import android.support.annotation.Nullable; import org.commonmark.node.Heading; +import java.util.Arrays; +import java.util.Collection; + import ru.noties.markwon.MarkwonConfiguration; import ru.noties.markwon.RenderProps; import ru.noties.markwon.SpanFactory; @@ -41,4 +44,10 @@ public class HeadingHandler extends SimpleTagHandler { return factory.getSpans(configuration, renderProps); } + + @NonNull + @Override + public Collection supportedTags() { + return Arrays.asList("h1", "h2", "h3", "h4", "h5", "h6"); + } } diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/tag/ImageHandler.java b/markwon-html/src/main/java/ru/noties/markwon/html/tag/ImageHandler.java index 4e7ffa54..04cbe46e 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/tag/ImageHandler.java +++ b/markwon-html/src/main/java/ru/noties/markwon/html/tag/ImageHandler.java @@ -6,6 +6,8 @@ import android.text.TextUtils; import org.commonmark.node.Image; +import java.util.Collection; +import java.util.Collections; import java.util.Map; import ru.noties.markwon.MarkwonConfiguration; @@ -18,6 +20,12 @@ import ru.noties.markwon.image.ImageSize; public class ImageHandler extends SimpleTagHandler { + @NonNull + @Override + public Collection supportedTags() { + return Collections.singleton("img"); + } + interface ImageSizeParser { @Nullable ImageSize parse(@NonNull Map attributes); @@ -30,6 +38,7 @@ public class ImageHandler extends SimpleTagHandler { private final ImageSizeParser imageSizeParser; + @SuppressWarnings("WeakerAccess") ImageHandler(@NonNull ImageSizeParser imageSizeParser) { this.imageSizeParser = imageSizeParser; } diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/tag/LinkHandler.java b/markwon-html/src/main/java/ru/noties/markwon/html/tag/LinkHandler.java index 04e768e9..a1687dd8 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/tag/LinkHandler.java +++ b/markwon-html/src/main/java/ru/noties/markwon/html/tag/LinkHandler.java @@ -6,6 +6,9 @@ import android.text.TextUtils; import org.commonmark.node.Link; +import java.util.Collection; +import java.util.Collections; + import ru.noties.markwon.MarkwonConfiguration; import ru.noties.markwon.RenderProps; import ru.noties.markwon.SpanFactory; @@ -30,4 +33,10 @@ public class LinkHandler extends SimpleTagHandler { } return null; } + + @NonNull + @Override + public Collection supportedTags() { + return Collections.singleton("a"); + } } diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/tag/ListHandler.java b/markwon-html/src/main/java/ru/noties/markwon/html/tag/ListHandler.java index 66f76cc0..a8f8df9d 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/tag/ListHandler.java +++ b/markwon-html/src/main/java/ru/noties/markwon/html/tag/ListHandler.java @@ -4,6 +4,9 @@ import android.support.annotation.NonNull; import org.commonmark.node.ListItem; +import java.util.Arrays; +import java.util.Collection; + import ru.noties.markwon.MarkwonConfiguration; import ru.noties.markwon.MarkwonVisitor; import ru.noties.markwon.RenderProps; @@ -65,6 +68,12 @@ public class ListHandler extends TagHandler { } } + @NonNull + @Override + public Collection supportedTags() { + return Arrays.asList("ol", "ul"); + } + private static int currentBulletListLevel(@NonNull HtmlTag.Block block) { int level = 0; while ((block = block.parent()) != null) { diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/tag/SimpleTagHandler.java b/markwon-html/src/main/java/ru/noties/markwon/html/tag/SimpleTagHandler.java index d5717c20..94341b2f 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/tag/SimpleTagHandler.java +++ b/markwon-html/src/main/java/ru/noties/markwon/html/tag/SimpleTagHandler.java @@ -3,6 +3,8 @@ package ru.noties.markwon.html.tag; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import java.util.Collection; + import ru.noties.markwon.MarkwonConfiguration; import ru.noties.markwon.MarkwonVisitor; import ru.noties.markwon.RenderProps; @@ -19,6 +21,11 @@ public abstract class SimpleTagHandler extends TagHandler { @NonNull RenderProps renderProps, @NonNull HtmlTag tag); + @NonNull + @Override + public abstract Collection supportedTags(); + + @Override public void handle(@NonNull MarkwonVisitor visitor, @NonNull MarkwonHtmlRenderer renderer, @NonNull HtmlTag tag) { final Object spans = getSpans(visitor.configuration(), visitor.renderProps(), tag); diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/tag/StrikeHandler.java b/markwon-html/src/main/java/ru/noties/markwon/html/tag/StrikeHandler.java index 2771501e..02dedc8a 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/tag/StrikeHandler.java +++ b/markwon-html/src/main/java/ru/noties/markwon/html/tag/StrikeHandler.java @@ -4,6 +4,9 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.text.style.StrikethroughSpan; +import java.util.Arrays; +import java.util.Collection; + import ru.noties.markwon.MarkwonConfiguration; import ru.noties.markwon.MarkwonVisitor; import ru.noties.markwon.SpanFactory; @@ -47,6 +50,12 @@ public class StrikeHandler extends TagHandler { ); } + @NonNull + @Override + public Collection supportedTags() { + return Arrays.asList("s", "del"); + } + @Nullable private static Object getMarkdownSpans(@NonNull MarkwonVisitor visitor) { final MarkwonConfiguration configuration = visitor.configuration(); diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/tag/StrongEmphasisHandler.java b/markwon-html/src/main/java/ru/noties/markwon/html/tag/StrongEmphasisHandler.java index 8e604b7f..486e43c4 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/tag/StrongEmphasisHandler.java +++ b/markwon-html/src/main/java/ru/noties/markwon/html/tag/StrongEmphasisHandler.java @@ -5,6 +5,9 @@ import android.support.annotation.Nullable; import org.commonmark.node.StrongEmphasis; +import java.util.Arrays; +import java.util.Collection; + import ru.noties.markwon.MarkwonConfiguration; import ru.noties.markwon.RenderProps; import ru.noties.markwon.SpanFactory; @@ -23,4 +26,10 @@ public class StrongEmphasisHandler extends SimpleTagHandler { } return spanFactory.getSpans(configuration, renderProps); } + + @NonNull + @Override + public Collection supportedTags() { + return Arrays.asList("b", "strong"); + } } diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/tag/SubScriptHandler.java b/markwon-html/src/main/java/ru/noties/markwon/html/tag/SubScriptHandler.java index 5ddc5697..5c99d963 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/tag/SubScriptHandler.java +++ b/markwon-html/src/main/java/ru/noties/markwon/html/tag/SubScriptHandler.java @@ -3,6 +3,9 @@ package ru.noties.markwon.html.tag; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import java.util.Collection; +import java.util.Collections; + import ru.noties.markwon.MarkwonConfiguration; import ru.noties.markwon.RenderProps; import ru.noties.markwon.html.HtmlTag; @@ -14,4 +17,10 @@ public class SubScriptHandler extends SimpleTagHandler { public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps renderProps, @NonNull HtmlTag tag) { return new SubScriptSpan(); } + + @NonNull + @Override + public Collection supportedTags() { + return Collections.singleton("sub"); + } } diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/tag/SuperScriptHandler.java b/markwon-html/src/main/java/ru/noties/markwon/html/tag/SuperScriptHandler.java index 77147c99..163a1735 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/tag/SuperScriptHandler.java +++ b/markwon-html/src/main/java/ru/noties/markwon/html/tag/SuperScriptHandler.java @@ -3,6 +3,9 @@ package ru.noties.markwon.html.tag; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import java.util.Collection; +import java.util.Collections; + import ru.noties.markwon.MarkwonConfiguration; import ru.noties.markwon.RenderProps; import ru.noties.markwon.html.HtmlTag; @@ -14,4 +17,10 @@ public class SuperScriptHandler extends SimpleTagHandler { public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps renderProps, @NonNull HtmlTag tag) { return new SuperScriptSpan(); } + + @NonNull + @Override + public Collection supportedTags() { + return Collections.singleton("sup"); + } } diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/tag/UnderlineHandler.java b/markwon-html/src/main/java/ru/noties/markwon/html/tag/UnderlineHandler.java index eaa397a6..bc2be951 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/tag/UnderlineHandler.java +++ b/markwon-html/src/main/java/ru/noties/markwon/html/tag/UnderlineHandler.java @@ -3,6 +3,9 @@ package ru.noties.markwon.html.tag; import android.support.annotation.NonNull; import android.text.style.UnderlineSpan; +import java.util.Arrays; +import java.util.Collection; + import ru.noties.markwon.MarkwonVisitor; import ru.noties.markwon.SpannableBuilder; import ru.noties.markwon.html.HtmlTag; @@ -31,4 +34,10 @@ public class UnderlineHandler extends TagHandler { tag.end() ); } + + @NonNull + @Override + public Collection supportedTags() { + return Arrays.asList("u", "ins"); + } } From dba07e3f3c21132d05fefc1eb0e9661751139b17 Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Tue, 4 Jun 2019 16:39:07 +0300 Subject: [PATCH 13/42] Linkify perf notice --- app/src/main/java/ru/noties/markwon/MarkdownRenderer.java | 2 -- markwon-linkify/README.md | 6 +++++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/ru/noties/markwon/MarkdownRenderer.java b/app/src/main/java/ru/noties/markwon/MarkdownRenderer.java index 73adc541..a55d82dc 100644 --- a/app/src/main/java/ru/noties/markwon/MarkdownRenderer.java +++ b/app/src/main/java/ru/noties/markwon/MarkdownRenderer.java @@ -25,7 +25,6 @@ import ru.noties.markwon.image.file.FileSchemeHandler; import ru.noties.markwon.image.gif.GifMediaDecoder; import ru.noties.markwon.image.network.OkHttpNetworkSchemeHandler; import ru.noties.markwon.image.svg.SvgMediaDecoder; -import ru.noties.markwon.linkify.LinkifyPlugin; import ru.noties.markwon.syntax.Prism4jTheme; import ru.noties.markwon.syntax.Prism4jThemeDarkula; import ru.noties.markwon.syntax.Prism4jThemeDefault; @@ -108,7 +107,6 @@ public class MarkdownRenderer { .addMediaDecoder(SvgMediaDecoder.create()); } })) - .usePlugin(LinkifyPlugin.create()) .usePlugin(SyntaxHighlightPlugin.create(prism4j, prism4jTheme)) .usePlugin(GifAwarePlugin.create(context)) .usePlugin(TablePlugin.create(context)) diff --git a/markwon-linkify/README.md b/markwon-linkify/README.md index 62d2cc75..12d90c14 100644 --- a/markwon-linkify/README.md +++ b/markwon-linkify/README.md @@ -2,4 +2,8 @@ Use this module (or take a hint from it) if you would need _linkify_ capabilities. Do not use `TextView.setAutolinkMask` (or specify `autolink` in XML) because it will remove all -existing links and keep only the ones it creates. \ No newline at end of file +existing links and keep only the ones it creates. + +Please note that usage of this plugin introduces significant performance drop due not +optimal implementation of underlying `android.text.util.Linkify`. If you have any ideas of how +to improve this - PR are welcome! \ No newline at end of file From 4b918bf09438389366cbedf4ac20576cddddcc17 Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Tue, 4 Jun 2019 17:18:42 +0300 Subject: [PATCH 14/42] Unified html and image modules --- gradle.properties | 2 +- .../ru/noties/markwon/html/HtmlPlugin.java | 37 +++++++++++++++++-- .../markwon/html/MarkwonHtmlRendererImpl.java | 36 +++--------------- .../image/AsyncDrawableLoaderBuilder.java | 17 +++++++++ .../ru/noties/markwon/image/ImagesPlugin.java | 16 -------- markwon-linkify/README.md | 2 +- 6 files changed, 58 insertions(+), 52 deletions(-) diff --git a/gradle.properties b/gradle.properties index abdc2b60..e3eb78c6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,7 +6,7 @@ org.gradle.configureondemand=true android.enableBuildCache=true android.buildCacheDir=build/pre-dex-cache -VERSION_NAME=3.1.0-SNAPSHOT +VERSION_NAME=4.0.0-SNAPSHOT GROUP=ru.noties.markwon POM_DESCRIPTION=Markwon markdown for Android diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/HtmlPlugin.java b/markwon-html/src/main/java/ru/noties/markwon/html/HtmlPlugin.java index 4fa633f4..fd9bad40 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/HtmlPlugin.java +++ b/markwon-html/src/main/java/ru/noties/markwon/html/HtmlPlugin.java @@ -10,6 +10,17 @@ import org.commonmark.node.Node; import ru.noties.markwon.AbstractMarkwonPlugin; import ru.noties.markwon.MarkwonConfiguration; import ru.noties.markwon.MarkwonVisitor; +import ru.noties.markwon.html.tag.BlockquoteHandler; +import ru.noties.markwon.html.tag.EmphasisHandler; +import ru.noties.markwon.html.tag.HeadingHandler; +import ru.noties.markwon.html.tag.ImageHandler; +import ru.noties.markwon.html.tag.LinkHandler; +import ru.noties.markwon.html.tag.ListHandler; +import ru.noties.markwon.html.tag.StrikeHandler; +import ru.noties.markwon.html.tag.StrongEmphasisHandler; +import ru.noties.markwon.html.tag.SubScriptHandler; +import ru.noties.markwon.html.tag.SuperScriptHandler; +import ru.noties.markwon.html.tag.UnderlineHandler; /** * @since 3.0.0 @@ -73,9 +84,29 @@ public class HtmlPlugin extends AbstractMarkwonPlugin { } @Override - public void configureConfiguration(@NonNull MarkwonConfiguration.Builder builder) { - builder - .htmlRenderer(this.builder.build()) + public void configureConfiguration(@NonNull MarkwonConfiguration.Builder configurationBuilder) { + + final MarkwonHtmlRendererImpl.Builder builder = this.builder; + + if (!builder.excludeDefaults()) { + // please note that it's better to not checkState for + // this method call (minor optimization), final `build` method call + // will check for the state and throw an exception if applicable + builder.addDefaultTagHandler(ImageHandler.create()); + builder.addDefaultTagHandler(new LinkHandler()); + builder.addDefaultTagHandler(new BlockquoteHandler()); + builder.addDefaultTagHandler(new SubScriptHandler()); + builder.addDefaultTagHandler(new SuperScriptHandler()); + builder.addDefaultTagHandler(new StrongEmphasisHandler()); + builder.addDefaultTagHandler(new StrikeHandler()); + builder.addDefaultTagHandler(new UnderlineHandler()); + builder.addDefaultTagHandler(new ListHandler()); + builder.addDefaultTagHandler(new EmphasisHandler()); + builder.addDefaultTagHandler(new HeadingHandler()); + } + + configurationBuilder + .htmlRenderer(builder.build()) .htmlParser(MarkwonHtmlParserImpl.create()); } diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/MarkwonHtmlRendererImpl.java b/markwon-html/src/main/java/ru/noties/markwon/html/MarkwonHtmlRendererImpl.java index 3699f5f5..dbde9035 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/MarkwonHtmlRendererImpl.java +++ b/markwon-html/src/main/java/ru/noties/markwon/html/MarkwonHtmlRendererImpl.java @@ -9,17 +9,6 @@ import java.util.List; import java.util.Map; import ru.noties.markwon.MarkwonVisitor; -import ru.noties.markwon.html.tag.BlockquoteHandler; -import ru.noties.markwon.html.tag.EmphasisHandler; -import ru.noties.markwon.html.tag.HeadingHandler; -import ru.noties.markwon.html.tag.ImageHandler; -import ru.noties.markwon.html.tag.LinkHandler; -import ru.noties.markwon.html.tag.ListHandler; -import ru.noties.markwon.html.tag.StrikeHandler; -import ru.noties.markwon.html.tag.StrongEmphasisHandler; -import ru.noties.markwon.html.tag.SubScriptHandler; -import ru.noties.markwon.html.tag.SuperScriptHandler; -import ru.noties.markwon.html.tag.UnderlineHandler; class MarkwonHtmlRendererImpl extends MarkwonHtmlRenderer { @@ -127,6 +116,10 @@ class MarkwonHtmlRendererImpl extends MarkwonHtmlRenderer { checkState(); this.excludeDefaults = excludeDefaults; } + + boolean excludeDefaults() { + return excludeDefaults; + } @NonNull public MarkwonHtmlRenderer build() { @@ -135,11 +128,6 @@ class MarkwonHtmlRendererImpl extends MarkwonHtmlRenderer { isBuilt = true; - if (!excludeDefaults) { - // register default handlers, check if a handler is present already for specified tag - registerDefaultHandlers(); - } - // okay, let's validate that we have at least one tagHandler registered // if we have none -> return no-op implementation return tagHandlers.size() > 0 @@ -153,21 +141,7 @@ class MarkwonHtmlRendererImpl extends MarkwonHtmlRenderer { } } - private void registerDefaultHandlers() { - add(ImageHandler.create()); - add(new LinkHandler()); - add(new BlockquoteHandler()); - add(new SubScriptHandler()); - add(new SuperScriptHandler()); - add(new StrongEmphasisHandler()); - add(new StrikeHandler()); - add(new UnderlineHandler()); - add(new ListHandler()); - add(new EmphasisHandler()); - add(new HeadingHandler()); - } - - private void add(@NonNull TagHandler tagHandler) { + void addDefaultTagHandler(@NonNull TagHandler tagHandler) { for (String tag : tagHandler.supportedTags()) { if (!tagHandlers.containsKey(tag)) { tagHandlers.put(tag, tagHandler); diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderBuilder.java b/markwon-image/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderBuilder.java index a57ca99b..59de548f 100644 --- a/markwon-image/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderBuilder.java +++ b/markwon-image/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderBuilder.java @@ -34,30 +34,36 @@ class AsyncDrawableLoaderBuilder { } void executorService(@NonNull ExecutorService executorService) { + checkState(); this.executorService = executorService; } void addSchemeHandler(@NonNull SchemeHandler schemeHandler) { + checkState(); for (String scheme : schemeHandler.supportedSchemes()) { schemeHandlers.put(scheme, schemeHandler); } } void addMediaDecoder(@NonNull MediaDecoder mediaDecoder) { + checkState(); for (String type : mediaDecoder.supportedTypes()) { mediaDecoders.put(type, mediaDecoder); } } void defaultMediaDecoder(@Nullable MediaDecoder mediaDecoder) { + checkState(); this.defaultMediaDecoder = mediaDecoder; } void removeSchemeHandler(@NonNull String scheme) { + checkState(); schemeHandlers.remove(scheme); } void removeMediaDecoder(@NonNull String contentType) { + checkState(); mediaDecoders.remove(contentType); } @@ -65,6 +71,7 @@ class AsyncDrawableLoaderBuilder { * @since 3.0.0 */ void placeholderProvider(@NonNull ImagesPlugin.PlaceholderProvider placeholderDrawableProvider) { + checkState(); this.placeholderProvider = placeholderDrawableProvider; } @@ -72,12 +79,15 @@ class AsyncDrawableLoaderBuilder { * @since 3.0.0 */ void errorHandler(@NonNull ImagesPlugin.ErrorHandler errorHandler) { + checkState(); this.errorHandler = errorHandler; } @NonNull AsyncDrawableLoader build() { + checkState(); + isBuilt = true; if (executorService == null) { @@ -86,4 +96,11 @@ class AsyncDrawableLoaderBuilder { return new AsyncDrawableLoaderImpl(this); } + + private void checkState() { + if (isBuilt) { + throw new IllegalStateException("ImagesPlugin has already been configured " + + "and cannot be modified any further"); + } + } } diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/ImagesPlugin.java b/markwon-image/src/main/java/ru/noties/markwon/image/ImagesPlugin.java index ee5d3cc9..ebb4cea0 100644 --- a/markwon-image/src/main/java/ru/noties/markwon/image/ImagesPlugin.java +++ b/markwon-image/src/main/java/ru/noties/markwon/image/ImagesPlugin.java @@ -72,7 +72,6 @@ public class ImagesPlugin extends AbstractMarkwonPlugin { */ @NonNull public ImagesPlugin executorService(@NonNull ExecutorService executorService) { - checkBuilderState(); builder.executorService(executorService); return this; } @@ -87,7 +86,6 @@ public class ImagesPlugin extends AbstractMarkwonPlugin { */ @NonNull public ImagesPlugin addSchemeHandler(@NonNull SchemeHandler schemeHandler) { - checkBuilderState(); builder.addSchemeHandler(schemeHandler); return this; } @@ -100,7 +98,6 @@ public class ImagesPlugin extends AbstractMarkwonPlugin { */ @NonNull public ImagesPlugin addMediaDecoder(@NonNull MediaDecoder mediaDecoder) { - checkBuilderState(); builder.addMediaDecoder(mediaDecoder); return this; } @@ -114,7 +111,6 @@ public class ImagesPlugin extends AbstractMarkwonPlugin { */ @NonNull public ImagesPlugin defaultMediaDecoder(@Nullable MediaDecoder mediaDecoder) { - checkBuilderState(); builder.defaultMediaDecoder(mediaDecoder); return this; } @@ -124,7 +120,6 @@ public class ImagesPlugin extends AbstractMarkwonPlugin { */ @NonNull public ImagesPlugin removeSchemeHandler(@NonNull String scheme) { - checkBuilderState(); builder.removeSchemeHandler(scheme); return this; } @@ -134,7 +129,6 @@ public class ImagesPlugin extends AbstractMarkwonPlugin { */ @NonNull public ImagesPlugin removeMediaDecoder(@NonNull String contentType) { - checkBuilderState(); builder.removeMediaDecoder(contentType); return this; } @@ -144,7 +138,6 @@ public class ImagesPlugin extends AbstractMarkwonPlugin { */ @NonNull public ImagesPlugin placeholderProvider(@NonNull PlaceholderProvider placeholderProvider) { - checkBuilderState(); builder.placeholderProvider(placeholderProvider); return this; } @@ -155,14 +148,12 @@ public class ImagesPlugin extends AbstractMarkwonPlugin { */ @NonNull public ImagesPlugin errorHandler(@NonNull ErrorHandler errorHandler) { - checkBuilderState(); builder.errorHandler(errorHandler); return this; } @Override public void configureConfiguration(@NonNull MarkwonConfiguration.Builder builder) { - checkBuilderState(); builder.asyncDrawableLoader(this.builder.build()); } @@ -180,11 +171,4 @@ public class ImagesPlugin extends AbstractMarkwonPlugin { public void afterSetText(@NonNull TextView textView) { AsyncDrawableScheduler.schedule(textView); } - - private void checkBuilderState() { - if (builder.isBuilt) { - throw new IllegalStateException("ImagesPlugin has already been configured " + - "and cannot be modified any further"); - } - } } diff --git a/markwon-linkify/README.md b/markwon-linkify/README.md index 12d90c14..ccc0c08e 100644 --- a/markwon-linkify/README.md +++ b/markwon-linkify/README.md @@ -4,6 +4,6 @@ Use this module (or take a hint from it) if you would need _linkify_ capabilitie use `TextView.setAutolinkMask` (or specify `autolink` in XML) because it will remove all existing links and keep only the ones it creates. -Please note that usage of this plugin introduces significant performance drop due not +Please note that usage of this plugin introduces significant performance drop due to not optimal implementation of underlying `android.text.util.Linkify`. If you have any ideas of how to improve this - PR are welcome! \ No newline at end of file From 79b99abb246d52915613ec1ac644a4e39a71ca3a Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Tue, 4 Jun 2019 23:44:52 +0300 Subject: [PATCH 15/42] Add HtmlConfigure for HtmlPlugin --- .../ru/noties/markwon/html/HtmlPlugin.java | 18 ++++ .../basicplugins/BasicPluginsActivity.java | 90 +++++++++++++++---- .../sample/recycler/RecyclerActivity.java | 4 +- 3 files changed, 91 insertions(+), 21 deletions(-) diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/HtmlPlugin.java b/markwon-html/src/main/java/ru/noties/markwon/html/HtmlPlugin.java index fd9bad40..8e437ac5 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/HtmlPlugin.java +++ b/markwon-html/src/main/java/ru/noties/markwon/html/HtmlPlugin.java @@ -27,11 +27,29 @@ import ru.noties.markwon.html.tag.UnderlineHandler; */ public class HtmlPlugin extends AbstractMarkwonPlugin { + /** + * @see #create(HtmlConfigure) + * @since 4.0.0-SNAPSHOT + */ + public interface HtmlConfigure { + void configureHtml(@NonNull HtmlPlugin plugin); + } + @NonNull public static HtmlPlugin create() { return new HtmlPlugin(); } + /** + * @since 4.0.0-SNAPSHOT + */ + @NonNull + public static HtmlPlugin create(@NonNull HtmlConfigure configure) { + final HtmlPlugin plugin = create(); + configure.configureHtml(plugin); + return plugin; + } + public static final float SCRIPT_DEF_TEXT_SIZE_RATIO = .75F; private final MarkwonHtmlRendererImpl.Builder builder; diff --git a/sample/src/main/java/ru/noties/markwon/sample/basicplugins/BasicPluginsActivity.java b/sample/src/main/java/ru/noties/markwon/sample/basicplugins/BasicPluginsActivity.java index 98596972..4d34db84 100644 --- a/sample/src/main/java/ru/noties/markwon/sample/basicplugins/BasicPluginsActivity.java +++ b/sample/src/main/java/ru/noties/markwon/sample/basicplugins/BasicPluginsActivity.java @@ -6,20 +6,33 @@ import android.net.Uri; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.text.Layout; import android.text.TextUtils; +import android.text.style.AlignmentSpan; import android.text.style.ForegroundColorSpan; import android.widget.TextView; import org.commonmark.node.Heading; import org.commonmark.node.Paragraph; +import java.util.Collection; +import java.util.Collections; + import ru.noties.markwon.AbstractMarkwonPlugin; import ru.noties.markwon.Markwon; import ru.noties.markwon.MarkwonConfiguration; import ru.noties.markwon.MarkwonPlugin; import ru.noties.markwon.MarkwonSpansFactory; import ru.noties.markwon.MarkwonVisitor; +import ru.noties.markwon.RenderProps; import ru.noties.markwon.core.MarkwonTheme; +import ru.noties.markwon.html.HtmlPlugin; +import ru.noties.markwon.html.HtmlTag; +import ru.noties.markwon.html.tag.SimpleTagHandler; +import ru.noties.markwon.image.ImageItem; +import ru.noties.markwon.image.ImagesPlugin; +import ru.noties.markwon.image.SchemeHandler; +import ru.noties.markwon.image.network.NetworkSchemeHandler; import ru.noties.markwon.movement.MovementMethodPlugin; public class BasicPluginsActivity extends Activity { @@ -42,6 +55,8 @@ public class BasicPluginsActivity extends Activity { step_4(); step_5(); + + step_6(); } /** @@ -167,30 +182,67 @@ public class BasicPluginsActivity extends Activity { final String markdown = "![image](myownscheme://en.wikipedia.org/static/images/project-logos/enwiki-2x.png)"; final Markwon markwon = Markwon.builder(this) -// .usePlugin(ImagesPlugin.create(this)) -// .usePlugin(new AbstractMarkwonPlugin() { -// @Override -// public void configureImages(@NonNull AsyncDrawableLoader.Builder builder) { -// // we can have a custom SchemeHandler -// // here we will just use networkSchemeHandler to redirect call -// builder.addSchemeHandler("myownscheme", new SchemeHandler() { -// -// final NetworkSchemeHandler networkSchemeHandler = NetworkSchemeHandler.create(); -// -// @Nullable -// @Override -// public ImageItem handle(@NonNull String raw, @NonNull Uri uri) { -// raw = raw.replace("myownscheme", "https"); -// return networkSchemeHandler.handle(raw, Uri.parse(raw)); -// } -// }); -// } -// }) + .usePlugin(ImagesPlugin.create()) + .usePlugin(new AbstractMarkwonPlugin() { + @Override + public void configure(@NonNull Registry registry) { + + // use registry.require to obtain a plugin, does also + // a runtime validation if this plugin is registered + registry.require(ImagesPlugin.class, plugin -> plugin.addSchemeHandler(new SchemeHandler() { + + // it's a sample only, most likely you won't need to + // use existing scheme-handler, this for demonstration purposes only + final NetworkSchemeHandler handler = NetworkSchemeHandler.create(); + + @NonNull + @Override + public ImageItem handle(@NonNull String raw, @NonNull Uri uri) { + final String url = raw.replace("myownscheme", "https"); + return handler.handle(url, Uri.parse(url)); + } + + @NonNull + @Override + public Collection supportedSchemes() { + return Collections.singleton("myownscheme"); + } + })); + } + }) + // or we can init plugin with this factory method +// .usePlugin(ImagesPlugin.create(plugin -> { +// plugin.addSchemeHandler(/**/) +// })) .build(); markwon.setMarkdown(textView, markdown); } + public void step_6() { + + final Markwon markwon = Markwon.builder(this) + .usePlugin(HtmlPlugin.create()) + .usePlugin(new AbstractMarkwonPlugin() { + @Override + public void configure(@NonNull Registry registry) { + registry.require(HtmlPlugin.class, plugin -> plugin.addHandler(new SimpleTagHandler() { + @Override + public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps renderProps, @NonNull HtmlTag tag) { + return new AlignmentSpan.Standard(Layout.Alignment.ALIGN_CENTER); + } + + @NonNull + @Override + public Collection supportedTags() { + return Collections.singleton("center"); + } + })); + } + }) + .build(); + } + // text lifecycle (after/before) // rendering lifecycle (before/after) // renderProps diff --git a/sample/src/main/java/ru/noties/markwon/sample/recycler/RecyclerActivity.java b/sample/src/main/java/ru/noties/markwon/sample/recycler/RecyclerActivity.java index 72409a5f..ff911a15 100644 --- a/sample/src/main/java/ru/noties/markwon/sample/recycler/RecyclerActivity.java +++ b/sample/src/main/java/ru/noties/markwon/sample/recycler/RecyclerActivity.java @@ -86,8 +86,8 @@ public class RecyclerActivity extends Activity { // .addSchemeHandler(OkHttpNetworkSchemeHandler.create()) // .addMediaDecoder(SvgMediaDecoder.create()); // })) -// .usePlugin(PicassoImagesPlugin.create(context)) - .usePlugin(GlideImagesPlugin.create(context)) + .usePlugin(PicassoImagesPlugin.create(context)) +// .usePlugin(GlideImagesPlugin.create(context)) // important to use TableEntryPlugin instead of TablePlugin .usePlugin(TableEntryPlugin.create(context)) .usePlugin(HtmlPlugin.create()) From 13536302cc0a42ae93ae8604435d9a5a3e0ebc5c Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Wed, 5 Jun 2019 00:20:36 +0300 Subject: [PATCH 16/42] Package name and maven group-id change io.noties.markwon --- README.md | 9 ++-- app/build.gradle | 2 +- .../debug/DebugCheckboxDrawableView.java | 6 +-- app/src/debug/res/layout/debug_checkbox.xml | 2 +- app/src/main/AndroidManifest.xml | 2 +- .../noties/markwon/app}/ActivityScope.java | 2 +- .../noties/markwon/app}/App.java | 2 +- .../noties/markwon/app}/AppBarItem.java | 2 +- .../noties/markwon/app}/AppComponent.java | 2 +- .../noties/markwon/app}/AppModule.java | 6 +-- .../noties/markwon/app}/MainActivity.java | 3 +- .../app}/MainActivitySubcomponent.java | 2 +- .../noties/markwon/app}/MarkdownLoader.java | 2 +- .../noties/markwon/app}/MarkdownRenderer.java | 39 +++++++------- .../noties/markwon/app}/Themes.java | 2 +- .../noties/markwon/app}/UriProcessor.java | 2 +- .../noties/markwon/app}/UriProcessorImpl.java | 2 +- .../app}/UrlProcessorInitialReadme.java | 6 +-- .../noties/markwon/app}/Views.java | 2 +- .../app}/gif/GifAwareAsyncDrawable.java | 10 ++-- .../markwon/app}/gif/GifAwarePlugin.java | 18 +++---- .../markwon/app}/gif/GifPlaceholder.java | 2 +- .../noties/markwon/app}/gif/GifProcessor.java | 4 +- app/src/main/res/layout/activity_main.xml | 1 - gradle.properties | 2 +- markwon-core/src/main/AndroidManifest.xml | 2 +- .../noties/markwon/AbstractMarkwonPlugin.java | 5 +- .../noties/markwon/LinkResolverDef.java | 4 +- .../{ru => io}/noties/markwon/Markwon.java | 4 +- .../noties/markwon/MarkwonBuilderImpl.java | 4 +- .../noties/markwon/MarkwonConfiguration.java | 24 ++++----- .../noties/markwon/MarkwonImpl.java | 2 +- .../noties/markwon/MarkwonNodeRenderer.java | 2 +- .../noties/markwon/MarkwonPlugin.java | 20 ++++---- .../noties/markwon/MarkwonReducer.java | 2 +- .../noties/markwon/MarkwonSpansFactory.java | 2 +- .../markwon/MarkwonSpansFactoryImpl.java | 2 +- .../noties/markwon/MarkwonVisitor.java | 2 +- .../noties/markwon/MarkwonVisitorImpl.java | 2 +- .../java/{ru => io}/noties/markwon/Prop.java | 2 +- .../noties/markwon/RenderProps.java | 2 +- .../noties/markwon/RenderPropsImpl.java | 2 +- .../noties/markwon/SpanFactory.java | 2 +- .../noties/markwon/SpannableBuilder.java | 2 +- .../noties/markwon/core/CorePlugin.java | 39 +++++++------- .../noties/markwon/core/CoreProps.java | 4 +- .../noties/markwon/core/MarkwonTheme.java | 15 +++--- .../markwon/core/SimpleBlockNodeVisitor.java | 6 +-- .../core/factory/BlockQuoteSpanFactory.java | 10 ++-- .../core/factory/CodeBlockSpanFactory.java | 10 ++-- .../markwon/core/factory/CodeSpanFactory.java | 10 ++-- .../core/factory/EmphasisSpanFactory.java | 10 ++-- .../core/factory/HeadingSpanFactory.java | 12 ++--- .../markwon/core/factory/LinkSpanFactory.java | 12 ++--- .../core/factory/ListItemSpanFactory.java | 14 ++--- .../factory/StrongEmphasisSpanFactory.java | 10 ++-- .../factory/ThematicBreakSpanFactory.java | 10 ++-- .../markwon/core/spans/BlockQuoteSpan.java | 4 +- .../core/spans/BulletListItemSpan.java | 6 +-- .../markwon/core/spans/CodeBlockSpan.java | 4 +- .../noties/markwon/core/spans/CodeSpan.java | 4 +- .../core/spans/CustomTypefaceSpan.java | 2 +- .../markwon/core/spans/EmphasisSpan.java | 2 +- .../markwon/core/spans/HeadingSpan.java | 6 +-- .../noties/markwon/core/spans/LinkSpan.java | 4 +- .../markwon/core/spans/ObjectsPool.java | 2 +- .../core/spans/OrderedListItemSpan.java | 6 +-- .../core/spans/StrongEmphasisSpan.java | 2 +- .../markwon/core/spans/ThematicBreakSpan.java | 4 +- .../noties/markwon/html/HtmlTag.java | 2 +- .../markwon/html/MarkwonHtmlParser.java | 2 +- .../markwon/html/MarkwonHtmlParserNoOp.java | 2 +- .../markwon/html/MarkwonHtmlRenderer.java | 4 +- .../markwon/html/MarkwonHtmlRendererNoOp.java | 4 +- .../noties/markwon/html/TagHandler.java | 4 +- .../noties/markwon/image/AsyncDrawable.java | 2 +- .../markwon/image/AsyncDrawableLoader.java | 2 +- .../image/AsyncDrawableLoaderNoOp.java | 2 +- .../markwon/image/AsyncDrawableScheduler.java | 4 +- .../markwon/image/AsyncDrawableSpan.java | 4 +- .../noties/markwon/image/DrawableUtils.java | 2 +- .../noties/markwon/image/ImageProps.java | 4 +- .../noties/markwon/image/ImageSize.java | 2 +- .../markwon/image/ImageSizeResolver.java | 2 +- .../markwon/image/ImageSizeResolverDef.java | 2 +- .../markwon/image/ImageSpanFactory.java | 8 +-- .../movement/MovementMethodPlugin.java | 4 +- .../markwon/syntax/SyntaxHighlight.java | 2 +- .../markwon/syntax/SyntaxHighlightNoOp.java | 2 +- .../markwon/urlprocessor/UrlProcessor.java | 2 +- .../UrlProcessorAndroidAssets.java | 2 +- .../urlprocessor/UrlProcessorNoOp.java | 2 +- .../UrlProcessorRelativeToAbsolute.java | 2 +- .../noties/markwon/utils/ColorUtils.java | 2 +- .../{ru => io}/noties/markwon/utils/Dip.java | 2 +- .../noties/markwon/utils/DrawableUtils.java | 4 +- .../noties/markwon/utils/DumpNodes.java | 2 +- .../markwon/utils/LeadingMarginUtils.java | 2 +- .../markwon/utils/NoCopySpannableFactory.java | 2 +- .../markwon/AbstractMarkwonPluginTest.java | 2 +- .../markwon/AbstractMarkwonVisitorImpl.java | 2 +- .../markwon/MarkwonBuilderImplTest.java | 6 +-- .../noties/markwon/MarkwonImplTest.java | 2 +- .../markwon/MarkwonSpansFactoryImplTest.java | 2 +- .../markwon/MarkwonSpansFactoryTest.java | 2 +- .../markwon/MarkwonVisitorImplTest.java | 2 +- .../{ru => io}/noties/markwon/PropTest.java | 2 +- .../noties/markwon/RenderPropsImplTest.java | 2 +- .../noties/markwon/SpannableBuilderTest.java | 6 +-- .../noties/markwon/core/CorePluginBridge.java | 4 +- .../noties/markwon/core/CorePluginTest.java | 14 ++--- .../noties/markwon/core/CoreTest.java | 24 ++++----- .../noties/markwon/core/suite/.editorconfig | 0 .../markwon/core/suite/BaseSuiteTest.java | 26 +++++----- .../markwon/core/suite/BlockquoteTest.java | 10 ++-- .../markwon/core/suite/BoldItalicTest.java | 10 ++-- .../noties/markwon/core/suite/CodeTest.java | 12 ++--- .../markwon/core/suite/DeeplyNestedTest.java | 12 ++--- .../markwon/core/suite/EmphasisTest.java | 10 ++-- .../noties/markwon/core/suite/FirstTest.java | 12 ++--- .../markwon/core/suite/HeadingTest.java | 12 ++--- .../noties/markwon/core/suite/LinkTest.java | 12 ++--- .../markwon/core/suite/NoParagraphsTest.java | 8 +-- .../markwon/core/suite/OrderedListTest.java | 12 ++--- .../markwon/core/suite/ParagraphTest.java | 10 ++-- .../noties/markwon/core/suite/SecondTest.java | 12 ++--- .../markwon/core/suite/SoftBreakTest.java | 8 +-- .../core/suite/StrongEmphasisTest.java | 10 ++-- .../markwon/core/suite/ThematicBreakTest.java | 10 ++-- .../markwon/core/suite/UnOrderedListTest.java | 12 ++--- .../markwon/image/AsyncDrawableTest.java | 2 +- .../image/ImageSizeResolverDefTest.java | 24 ++++----- .../noties/markwon/image/ImageTest.java | 28 +++++----- .../markwon/syntax/SyntaxHighlightTest.java | 22 ++++---- .../UrlProcessorAndroidAssetsTest.java | 6 +-- .../UrlProcessorRelativeToAbsoluteTest.java | 4 +- .../src/main/AndroidManifest.xml | 2 +- .../markwon/ext/latex/JLatexMathBlock.java | 2 +- .../ext/latex/JLatexMathBlockParser.java | 2 +- .../markwon/ext/latex/JLatexMathPlugin.java | 18 +++---- markwon-ext-strikethrough/README.md | 2 +- .../src/main/AndroidManifest.xml | 2 +- .../strikethrough/StrikethroughPlugin.java | 14 ++--- .../StrikethroughPluginTest.java | 28 +++++----- markwon-ext-tables/README.md | 2 +- .../src/main/AndroidManifest.xml | 2 +- .../noties/markwon/ext/tables/Table.java | 4 +- .../markwon/ext/tables/TablePlugin.java | 8 +-- .../markwon/ext/tables/TableRowSpan.java | 2 +- .../ext/tables/TableRowsScheduler.java | 2 +- .../noties/markwon/ext/tables/TableTheme.java | 6 +-- .../src/main/AndroidManifest.xml | 2 +- .../markwon/ext/tasklist/TaskListBlock.java | 2 +- .../ext/tasklist/TaskListBlockParser.java | 2 +- .../ext/tasklist/TaskListDrawable.java | 2 +- .../markwon/ext/tasklist/TaskListItem.java | 2 +- .../markwon/ext/tasklist/TaskListPlugin.java | 12 ++--- .../markwon/ext/tasklist/TaskListProps.java | 4 +- .../markwon/ext/tasklist/TaskListSpan.java | 6 +-- .../ext/tasklist/TaskListSpanFactory.java | 8 +-- .../markwon/ext/tasklist/TaskListTest.java | 51 +++++++++---------- markwon-html/src/main/AndroidManifest.xml | 2 +- .../noties/markwon/html/AppendableUtils.java | 2 +- .../markwon/html/CssInlineStyleParser.java | 2 +- .../noties/markwon/html/CssProperty.java | 2 +- .../markwon/html/HtmlEmptyTagReplacement.java | 2 +- .../noties/markwon/html/HtmlPlugin.java | 30 +++++------ .../noties/markwon/html/HtmlTagImpl.java | 2 +- .../markwon/html/MarkwonHtmlParserImpl.java | 42 ++++++++------- .../markwon/html/MarkwonHtmlRendererImpl.java | 4 +- .../noties/markwon/html/TagHandlerNoOp.java | 4 +- .../noties/markwon/html/TrimmingAppender.java | 4 +- .../html/jsoup/UncheckedIOException.java | 2 +- .../markwon/html/jsoup/helper/Normalizer.java | 2 +- .../markwon/html/jsoup/helper/Validate.java | 2 +- .../markwon/html/jsoup/nodes/Attribute.java | 4 +- .../markwon/html/jsoup/nodes/Attributes.java | 6 +-- .../html/jsoup/nodes/CommonMarkEntities.java | 2 +- .../html/jsoup/nodes/DocumentType.java | 2 +- .../html/jsoup/parser/CharacterReader.java | 6 +-- .../markwon/html/jsoup/parser/ParseError.java | 2 +- .../html/jsoup/parser/ParseErrorList.java | 2 +- .../markwon/html/jsoup/parser/Token.java | 8 +-- .../markwon/html/jsoup/parser/Tokeniser.java | 6 +-- .../html/jsoup/parser/TokeniserState.java | 4 +- .../markwon/html/span/SubScriptSpan.java | 4 +- .../markwon/html/span/SuperScriptSpan.java | 4 +- .../markwon/html/tag/BlockquoteHandler.java | 16 +++--- .../markwon/html/tag/EmphasisHandler.java | 10 ++-- .../markwon/html/tag/HeadingHandler.java | 12 ++--- .../noties/markwon/html/tag/ImageHandler.java | 16 +++--- .../markwon/html/tag/ImageSizeParserImpl.java | 8 +-- .../noties/markwon/html/tag/LinkHandler.java | 12 ++--- .../noties/markwon/html/tag/ListHandler.java | 20 ++++---- .../markwon/html/tag/SimpleTagHandler.java | 16 +++--- .../markwon/html/tag/StrikeHandler.java | 16 +++--- .../html/tag/StrongEmphasisHandler.java | 10 ++-- .../markwon/html/tag/SubScriptHandler.java | 10 ++-- .../markwon/html/tag/SuperScriptHandler.java | 10 ++-- .../markwon/html/tag/UnderlineHandler.java | 12 ++--- .../html/CssInlineStyleParserTest.java | 2 +- .../html/HtmlEmptyTagReplacementTest.java | 4 +- .../html/MarkwonHtmlParserImplTest.java | 2 +- .../markwon/html/TrimmingAppenderTest.java | 4 +- .../jsoup/nodes/CommonMarkEntitiesTest.java | 2 +- .../html/tag/ImageSizeParserImplTest.java | 6 +-- .../src/main/AndroidManifest.xml | 2 +- .../image/glide/GlideImagesPlugin.java | 18 +++---- .../src/main/AndroidManifest.xml | 2 +- .../image/picasso/PicassoImagesPlugin.java | 18 +++---- markwon-image/src/main/AndroidManifest.xml | 2 +- .../image/AsyncDrawableLoaderBuilder.java | 6 +-- .../image/AsyncDrawableLoaderImpl.java | 4 +- .../image/DefaultImageMediaDecoder.java | 2 +- .../noties/markwon/image/ImageItem.java | 2 +- .../noties/markwon/image/ImagesPlugin.java | 29 +++++++---- .../noties/markwon/image/MediaDecoder.java | 2 +- .../noties/markwon/image/SchemeHandler.java | 2 +- .../noties/markwon/image/data/DataUri.java | 2 +- .../markwon/image/data/DataUriDecoder.java | 2 +- .../markwon/image/data/DataUriParser.java | 2 +- .../image/data/DataUriSchemeHandler.java | 6 +-- .../markwon/image/file/FileSchemeHandler.java | 11 ++-- .../markwon/image/gif/GifMediaDecoder.java | 6 +-- .../image/network/NetworkSchemeHandler.java | 6 +-- .../network/OkHttpNetworkSchemeHandler.java | 6 +-- .../markwon/image/svg/SvgMediaDecoder.java | 6 +-- .../image/AsyncDrawableLoaderBuilderTest.java | 6 +-- .../image/AsyncDrawableLoaderImplTest.java | 2 +- .../markwon/image/ImagesPluginTest.java | 14 ++--- .../markwon/image/data/DataUriParserTest.java | 2 +- .../image/data/DataUriSchemeHandlerTest.java | 4 +- markwon-linkify/src/main/AndroidManifest.xml | 2 +- .../noties/markwon/linkify/LinkifyPlugin.java | 10 ++-- .../src/main/AndroidManifest.xml | 2 +- .../recycler/table/TableBorderDrawable.java | 2 +- .../markwon/recycler/table/TableEntry.java | 10 ++-- .../recycler/table/TableEntryPlugin.java | 10 ++-- .../recycler/table/TableEntryTheme.java | 6 +-- .../recycler/table/TableEntryTest.java | 4 +- markwon-recycler/src/main/AndroidManifest.xml | 2 +- .../markwon/recycler/MarkwonAdapter.java | 6 +-- .../markwon/recycler/MarkwonAdapterImpl.java | 6 +-- .../noties/markwon/recycler/SimpleEntry.java | 6 +-- .../src/main/AndroidManifest.xml | 2 +- .../syntax/Prism4jSyntaxHighlight.java | 2 +- .../markwon/syntax/Prism4jSyntaxVisitor.java | 2 +- .../noties/markwon/syntax/Prism4jTheme.java | 2 +- .../markwon/syntax/Prism4jThemeBase.java | 2 +- .../markwon/syntax/Prism4jThemeDarkula.java | 6 +-- .../markwon/syntax/Prism4jThemeDefault.java | 6 +-- .../markwon/syntax/SyntaxHighlightPlugin.java | 8 +-- .../src/main/AndroidManifest.xml | 2 +- .../noties/markwon/test/TestSpan.java | 2 +- .../noties/markwon/test/TestSpanDocument.java | 2 +- .../markwon/test/TestSpanEnumerator.java | 2 +- .../noties/markwon/test/TestSpanMatcher.java | 2 +- .../noties/markwon/test/TestSpanSpan.java | 2 +- .../noties/markwon/test/TestSpanText.java | 2 +- .../noties/markwon/test/TestSpanTest.java | 21 +++----- sample/build.gradle | 2 +- sample/src/main/AndroidManifest.xml | 16 +++--- .../noties/markwon/sample/MainActivity.java | 14 ++--- .../noties/markwon/sample/SampleItem.java | 2 +- .../markwon/sample/SampleItemDecoration.java | 2 +- .../noties/markwon/sample/SampleItemView.java | 6 +-- .../basicplugins/BasicPluginsActivity.java | 34 ++++++------- .../markwon/sample/core/CoreActivity.java | 6 +-- .../CustomExtensionActivity.java | 6 +-- .../sample/customextension/IconGroupNode.java | 2 +- .../sample/customextension/IconNode.java | 2 +- .../sample/customextension/IconPlugin.java | 6 +-- .../sample/customextension/IconProcessor.java | 2 +- .../sample/customextension/IconSpan.java | 2 +- .../customextension/IconSpanProvider.java | 2 +- .../markwon/sample/latex/LatexActivity.java | 8 +-- .../sample/recycler/RecyclerActivity.java | 37 ++++++-------- .../markwon/sample/theme/ThemeActivity.java | 4 +- .../markwon/sample/MainActivityTest.java | 2 +- 279 files changed, 913 insertions(+), 927 deletions(-) rename app/src/debug/java/{ru => io}/noties/markwon/debug/DebugCheckboxDrawableView.java (94%) rename app/src/main/java/{ru/noties/markwon => io/noties/markwon/app}/ActivityScope.java (67%) rename app/src/main/java/{ru/noties/markwon => io/noties/markwon/app}/App.java (95%) rename app/src/main/java/{ru/noties/markwon => io/noties/markwon/app}/AppBarItem.java (97%) rename app/src/main/java/{ru/noties/markwon => io/noties/markwon/app}/AppComponent.java (86%) rename app/src/main/java/{ru/noties/markwon => io/noties/markwon/app}/AppModule.java (93%) rename app/src/main/java/{ru/noties/markwon => io/noties/markwon/app}/MainActivity.java (98%) rename app/src/main/java/{ru/noties/markwon => io/noties/markwon/app}/MainActivitySubcomponent.java (81%) rename app/src/main/java/{ru/noties/markwon => io/noties/markwon/app}/MarkdownLoader.java (99%) rename app/src/main/java/{ru/noties/markwon => io/noties/markwon/app}/MarkdownRenderer.java (81%) rename app/src/main/java/{ru/noties/markwon => io/noties/markwon/app}/Themes.java (97%) rename app/src/main/java/{ru/noties/markwon => io/noties/markwon/app}/UriProcessor.java (84%) rename app/src/main/java/{ru/noties/markwon => io/noties/markwon/app}/UriProcessorImpl.java (97%) rename app/src/main/java/{ru/noties/markwon => io/noties/markwon/app}/UrlProcessorInitialReadme.java (83%) rename app/src/main/java/{ru/noties/markwon => io/noties/markwon/app}/Views.java (95%) rename app/src/main/java/{ru/noties/markwon => io/noties/markwon/app}/gif/GifAwareAsyncDrawable.java (88%) rename app/src/main/java/{ru/noties/markwon => io/noties/markwon/app}/gif/GifAwarePlugin.java (82%) rename app/src/main/java/{ru/noties/markwon => io/noties/markwon/app}/gif/GifPlaceholder.java (98%) rename app/src/main/java/{ru/noties/markwon => io/noties/markwon/app}/gif/GifProcessor.java (98%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/AbstractMarkwonPlugin.java (92%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/LinkResolverDef.java (92%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/Markwon.java (98%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/MarkwonBuilderImpl.java (98%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/MarkwonConfiguration.java (90%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/MarkwonImpl.java (99%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/MarkwonNodeRenderer.java (99%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/MarkwonPlugin.java (91%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/MarkwonReducer.java (98%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/MarkwonSpansFactory.java (98%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/MarkwonSpansFactoryImpl.java (99%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/MarkwonVisitor.java (99%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/MarkwonVisitorImpl.java (99%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/Prop.java (98%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/RenderProps.java (93%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/RenderPropsImpl.java (97%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/SpanFactory.java (91%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/SpannableBuilder.java (99%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/core/CorePlugin.java (94%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/core/CoreProps.java (92%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/core/MarkwonTheme.java (98%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/core/SimpleBlockNodeVisitor.java (84%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/core/factory/BlockQuoteSpanFactory.java (61%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/core/factory/CodeBlockSpanFactory.java (61%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/core/factory/CodeSpanFactory.java (61%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/core/factory/EmphasisSpanFactory.java (60%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/core/factory/HeadingSpanFactory.java (62%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/core/factory/LinkSpanFactory.java (65%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/core/factory/ListItemSpanFactory.java (77%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/core/factory/StrongEmphasisSpanFactory.java (60%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/core/factory/ThematicBreakSpanFactory.java (61%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/core/spans/BlockQuoteSpan.java (94%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/core/spans/BulletListItemSpan.java (96%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/core/spans/CodeBlockSpan.java (95%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/core/spans/CodeSpan.java (89%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/core/spans/CustomTypefaceSpan.java (96%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/core/spans/EmphasisSpan.java (90%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/core/spans/HeadingSpan.java (94%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/core/spans/LinkSpan.java (90%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/core/spans/ObjectsPool.java (95%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/core/spans/OrderedListItemSpan.java (96%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/core/spans/StrongEmphasisSpan.java (90%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/core/spans/ThematicBreakSpan.java (94%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/html/HtmlTag.java (98%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/html/MarkwonHtmlParser.java (98%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/html/MarkwonHtmlParserNoOp.java (95%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/html/MarkwonHtmlRenderer.java (87%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/html/MarkwonHtmlRendererNoOp.java (84%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/html/TagHandler.java (93%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/image/AsyncDrawable.java (99%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/image/AsyncDrawableLoader.java (95%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/image/AsyncDrawableLoaderNoOp.java (93%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/image/AsyncDrawableScheduler.java (98%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/image/AsyncDrawableSpan.java (98%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/image/DrawableUtils.java (96%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/image/ImageProps.java (85%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/image/ImageSize.java (96%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/image/ImageSizeResolver.java (95%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/image/ImageSizeResolverDef.java (98%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/image/ImageSpanFactory.java (83%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/movement/MovementMethodPlugin.java (93%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/syntax/SyntaxHighlight.java (87%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/syntax/SyntaxHighlightNoOp.java (89%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/urlprocessor/UrlProcessor.java (77%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/urlprocessor/UrlProcessorAndroidAssets.java (97%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/urlprocessor/UrlProcessorNoOp.java (84%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/urlprocessor/UrlProcessorRelativeToAbsolute.java (96%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/utils/ColorUtils.java (85%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/utils/Dip.java (94%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/utils/DrawableUtils.java (78%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/utils/DumpNodes.java (99%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/utils/LeadingMarginUtils.java (94%) rename markwon-core/src/main/java/{ru => io}/noties/markwon/utils/NoCopySpannableFactory.java (95%) rename markwon-core/src/test/java/{ru => io}/noties/markwon/AbstractMarkwonPluginTest.java (95%) rename markwon-core/src/test/java/{ru => io}/noties/markwon/AbstractMarkwonVisitorImpl.java (95%) rename markwon-core/src/test/java/{ru => io}/noties/markwon/MarkwonBuilderImplTest.java (96%) rename markwon-core/src/test/java/{ru => io}/noties/markwon/MarkwonImplTest.java (99%) rename markwon-core/src/test/java/{ru => io}/noties/markwon/MarkwonSpansFactoryImplTest.java (99%) rename markwon-core/src/test/java/{ru => io}/noties/markwon/MarkwonSpansFactoryTest.java (98%) rename markwon-core/src/test/java/{ru => io}/noties/markwon/MarkwonVisitorImplTest.java (99%) rename markwon-core/src/test/java/{ru => io}/noties/markwon/PropTest.java (98%) rename markwon-core/src/test/java/{ru => io}/noties/markwon/RenderPropsImplTest.java (99%) rename markwon-core/src/test/java/{ru => io}/noties/markwon/SpannableBuilderTest.java (98%) rename markwon-core/src/test/java/{ru => io}/noties/markwon/core/CorePluginBridge.java (86%) rename markwon-core/src/test/java/{ru => io}/noties/markwon/core/CorePluginTest.java (97%) rename markwon-core/src/test/java/{ru => io}/noties/markwon/core/CoreTest.java (78%) rename markwon-core/src/test/java/{ru => io}/noties/markwon/core/suite/.editorconfig (100%) rename markwon-core/src/test/java/{ru => io}/noties/markwon/core/suite/BaseSuiteTest.java (90%) rename markwon-core/src/test/java/{ru => io}/noties/markwon/core/suite/BlockquoteTest.java (76%) rename markwon-core/src/test/java/{ru => io}/noties/markwon/core/suite/BoldItalicTest.java (66%) rename markwon-core/src/test/java/{ru => io}/noties/markwon/core/suite/CodeTest.java (80%) rename markwon-core/src/test/java/{ru => io}/noties/markwon/core/suite/DeeplyNestedTest.java (71%) rename markwon-core/src/test/java/{ru => io}/noties/markwon/core/suite/EmphasisTest.java (64%) rename markwon-core/src/test/java/{ru => io}/noties/markwon/core/suite/FirstTest.java (71%) rename markwon-core/src/test/java/{ru => io}/noties/markwon/core/suite/HeadingTest.java (71%) rename markwon-core/src/test/java/{ru => io}/noties/markwon/core/suite/LinkTest.java (59%) rename markwon-core/src/test/java/{ru => io}/noties/markwon/core/suite/NoParagraphsTest.java (75%) rename markwon-core/src/test/java/{ru => io}/noties/markwon/core/suite/OrderedListTest.java (86%) rename markwon-core/src/test/java/{ru => io}/noties/markwon/core/suite/ParagraphTest.java (73%) rename markwon-core/src/test/java/{ru => io}/noties/markwon/core/suite/SecondTest.java (78%) rename markwon-core/src/test/java/{ru => io}/noties/markwon/core/suite/SoftBreakTest.java (72%) rename markwon-core/src/test/java/{ru => io}/noties/markwon/core/suite/StrongEmphasisTest.java (65%) rename markwon-core/src/test/java/{ru => io}/noties/markwon/core/suite/ThematicBreakTest.java (66%) rename markwon-core/src/test/java/{ru => io}/noties/markwon/core/suite/UnOrderedListTest.java (83%) rename markwon-core/src/test/java/{ru => io}/noties/markwon/image/AsyncDrawableTest.java (98%) rename markwon-core/src/test/java/{ru => io}/noties/markwon/image/ImageSizeResolverDefTest.java (80%) rename markwon-core/src/test/java/{ru => io}/noties/markwon/image/ImageTest.java (70%) rename markwon-core/src/test/java/{ru => io}/noties/markwon/syntax/SyntaxHighlightTest.java (90%) rename markwon-core/src/test/java/{ru => io}/noties/markwon/urlprocessor/UrlProcessorAndroidAssetsTest.java (87%) rename markwon-core/src/test/java/{ru => io}/noties/markwon/urlprocessor/UrlProcessorRelativeToAbsoluteTest.java (95%) rename markwon-ext-latex/src/main/java/{ru => io}/noties/markwon/ext/latex/JLatexMathBlock.java (87%) rename markwon-ext-latex/src/main/java/{ru => io}/noties/markwon/ext/latex/JLatexMathBlockParser.java (98%) rename markwon-ext-latex/src/main/java/{ru => io}/noties/markwon/ext/latex/JLatexMathPlugin.java (95%) rename markwon-ext-strikethrough/src/main/java/{ru => io}/noties/markwon/ext/strikethrough/StrikethroughPlugin.java (85%) rename markwon-ext-strikethrough/src/test/java/{ru => io}/noties/markwon/ext/strikethrough/StrikethroughPluginTest.java (87%) rename markwon-ext-tables/src/main/java/{ru => io}/noties/markwon/ext/tables/Table.java (98%) rename markwon-ext-tables/src/main/java/{ru => io}/noties/markwon/ext/tables/TablePlugin.java (97%) rename markwon-ext-tables/src/main/java/{ru => io}/noties/markwon/ext/tables/TableRowSpan.java (99%) rename markwon-ext-tables/src/main/java/{ru => io}/noties/markwon/ext/tables/TableRowsScheduler.java (98%) rename markwon-ext-tables/src/main/java/{ru => io}/noties/markwon/ext/tables/TableTheme.java (97%) rename markwon-ext-tasklist/src/main/java/{ru => io}/noties/markwon/ext/tasklist/TaskListBlock.java (74%) rename markwon-ext-tasklist/src/main/java/{ru => io}/noties/markwon/ext/tasklist/TaskListBlockParser.java (99%) rename markwon-ext-tasklist/src/main/java/{ru => io}/noties/markwon/ext/tasklist/TaskListDrawable.java (99%) rename markwon-ext-tasklist/src/main/java/{ru => io}/noties/markwon/ext/tasklist/TaskListItem.java (92%) rename markwon-ext-tasklist/src/main/java/{ru => io}/noties/markwon/ext/tasklist/TaskListPlugin.java (93%) rename markwon-ext-tasklist/src/main/java/{ru => io}/noties/markwon/ext/tasklist/TaskListProps.java (78%) rename markwon-ext-tasklist/src/main/java/{ru => io}/noties/markwon/ext/tasklist/TaskListSpan.java (95%) rename markwon-ext-tasklist/src/main/java/{ru => io}/noties/markwon/ext/tasklist/TaskListSpanFactory.java (80%) rename markwon-ext-tasklist/src/test/java/{ru => io}/noties/markwon/ext/tasklist/TaskListTest.java (56%) rename markwon-html/src/main/java/{ru => io}/noties/markwon/html/AppendableUtils.java (96%) rename markwon-html/src/main/java/{ru => io}/noties/markwon/html/CssInlineStyleParser.java (99%) rename markwon-html/src/main/java/{ru => io}/noties/markwon/html/CssProperty.java (96%) rename markwon-html/src/main/java/{ru => io}/noties/markwon/html/HtmlEmptyTagReplacement.java (98%) rename markwon-html/src/main/java/{ru => io}/noties/markwon/html/HtmlPlugin.java (86%) rename markwon-html/src/main/java/{ru => io}/noties/markwon/html/HtmlTagImpl.java (99%) rename markwon-html/src/main/java/{ru => io}/noties/markwon/html/MarkwonHtmlParserImpl.java (93%) rename markwon-html/src/main/java/{ru => io}/noties/markwon/html/MarkwonHtmlRendererImpl.java (98%) rename markwon-html/src/main/java/{ru => io}/noties/markwon/html/TagHandlerNoOp.java (92%) rename markwon-html/src/main/java/{ru => io}/noties/markwon/html/TrimmingAppender.java (95%) rename markwon-html/src/main/java/{ru => io}/noties/markwon/html/jsoup/UncheckedIOException.java (87%) rename markwon-html/src/main/java/{ru => io}/noties/markwon/html/jsoup/helper/Normalizer.java (90%) rename markwon-html/src/main/java/{ru => io}/noties/markwon/html/jsoup/helper/Validate.java (98%) rename markwon-html/src/main/java/{ru => io}/noties/markwon/html/jsoup/nodes/Attribute.java (98%) rename markwon-html/src/main/java/{ru => io}/noties/markwon/html/jsoup/nodes/Attributes.java (98%) rename markwon-html/src/main/java/{ru => io}/noties/markwon/html/jsoup/nodes/CommonMarkEntities.java (97%) rename markwon-html/src/main/java/{ru => io}/noties/markwon/html/jsoup/nodes/DocumentType.java (98%) rename markwon-html/src/main/java/{ru => io}/noties/markwon/html/jsoup/parser/CharacterReader.java (98%) rename markwon-html/src/main/java/{ru => io}/noties/markwon/html/jsoup/parser/ParseError.java (95%) rename markwon-html/src/main/java/{ru => io}/noties/markwon/html/jsoup/parser/ParseErrorList.java (94%) rename markwon-html/src/main/java/{ru => io}/noties/markwon/html/jsoup/parser/Token.java (98%) rename markwon-html/src/main/java/{ru => io}/noties/markwon/html/jsoup/parser/Tokeniser.java (98%) rename markwon-html/src/main/java/{ru => io}/noties/markwon/html/jsoup/parser/TokeniserState.java (99%) rename markwon-html/src/main/java/{ru => io}/noties/markwon/html/span/SubScriptSpan.java (87%) rename markwon-html/src/main/java/{ru => io}/noties/markwon/html/span/SuperScriptSpan.java (87%) rename markwon-html/src/main/java/{ru => io}/noties/markwon/html/tag/BlockquoteHandler.java (75%) rename markwon-html/src/main/java/{ru => io}/noties/markwon/html/tag/EmphasisHandler.java (80%) rename markwon-html/src/main/java/{ru => io}/noties/markwon/html/tag/HeadingHandler.java (82%) rename markwon-html/src/main/java/{ru => io}/noties/markwon/html/tag/ImageHandler.java (86%) rename markwon-html/src/main/java/{ru => io}/noties/markwon/html/tag/ImageSizeParserImpl.java (94%) rename markwon-html/src/main/java/{ru => io}/noties/markwon/html/tag/LinkHandler.java (81%) rename markwon-html/src/main/java/{ru => io}/noties/markwon/html/tag/ListHandler.java (84%) rename markwon-html/src/main/java/{ru => io}/noties/markwon/html/tag/SimpleTagHandler.java (70%) rename markwon-html/src/main/java/{ru => io}/noties/markwon/html/tag/StrikeHandler.java (84%) rename markwon-html/src/main/java/{ru => io}/noties/markwon/html/tag/StrongEmphasisHandler.java (80%) rename markwon-html/src/main/java/{ru => io}/noties/markwon/html/tag/SubScriptHandler.java (71%) rename markwon-html/src/main/java/{ru => io}/noties/markwon/html/tag/SuperScriptHandler.java (71%) rename markwon-html/src/main/java/{ru => io}/noties/markwon/html/tag/UnderlineHandler.java (78%) rename markwon-html/src/test/java/{ru => io}/noties/markwon/html/CssInlineStyleParserTest.java (99%) rename markwon-html/src/test/java/{ru => io}/noties/markwon/html/HtmlEmptyTagReplacementTest.java (92%) rename markwon-html/src/test/java/{ru => io}/noties/markwon/html/MarkwonHtmlParserImplTest.java (99%) rename markwon-html/src/test/java/{ru => io}/noties/markwon/html/TrimmingAppenderTest.java (93%) rename markwon-html/src/test/java/{ru => io}/noties/markwon/html/jsoup/nodes/CommonMarkEntitiesTest.java (92%) rename markwon-html/src/test/java/{ru => io}/noties/markwon/html/tag/ImageSizeParserImplTest.java (97%) rename markwon-image-glide/src/main/java/{ru => io}/noties/markwon/image/glide/GlideImagesPlugin.java (93%) rename markwon-image-picasso/src/main/java/{ru => io}/noties/markwon/image/picasso/PicassoImagesPlugin.java (92%) rename markwon-image/src/main/java/{ru => io}/noties/markwon/image/AsyncDrawableLoaderBuilder.java (95%) rename markwon-image/src/main/java/{ru => io}/noties/markwon/image/AsyncDrawableLoaderImpl.java (98%) rename markwon-image/src/main/java/{ru => io}/noties/markwon/image/DefaultImageMediaDecoder.java (98%) rename markwon-image/src/main/java/{ru => io}/noties/markwon/image/ImageItem.java (99%) rename markwon-image/src/main/java/{ru => io}/noties/markwon/image/ImagesPlugin.java (84%) rename markwon-image/src/main/java/{ru => io}/noties/markwon/image/MediaDecoder.java (95%) rename markwon-image/src/main/java/{ru => io}/noties/markwon/image/SchemeHandler.java (95%) rename markwon-image/src/main/java/{ru => io}/noties/markwon/image/data/DataUri.java (97%) rename markwon-image/src/main/java/{ru => io}/noties/markwon/image/data/DataUriDecoder.java (96%) rename markwon-image/src/main/java/{ru => io}/noties/markwon/image/data/DataUriParser.java (98%) rename markwon-image/src/main/java/{ru => io}/noties/markwon/image/data/DataUriSchemeHandler.java (93%) rename markwon-image/src/main/java/{ru => io}/noties/markwon/image/file/FileSchemeHandler.java (93%) rename markwon-image/src/main/java/{ru => io}/noties/markwon/image/gif/GifMediaDecoder.java (95%) rename markwon-image/src/main/java/{ru => io}/noties/markwon/image/network/NetworkSchemeHandler.java (94%) rename markwon-image/src/main/java/{ru => io}/noties/markwon/image/network/OkHttpNetworkSchemeHandler.java (95%) rename markwon-image/src/main/java/{ru => io}/noties/markwon/image/svg/SvgMediaDecoder.java (95%) rename markwon-image/src/test/java/{ru => io}/noties/markwon/image/AsyncDrawableLoaderBuilderTest.java (97%) rename markwon-image/src/test/java/{ru => io}/noties/markwon/image/AsyncDrawableLoaderImplTest.java (98%) rename markwon-image/src/test/java/{ru => io}/noties/markwon/image/ImagesPluginTest.java (92%) rename markwon-image/src/test/java/{ru => io}/noties/markwon/image/data/DataUriParserTest.java (98%) rename markwon-image/src/test/java/{ru => io}/noties/markwon/image/data/DataUriSchemeHandlerTest.java (97%) rename markwon-linkify/src/main/java/{ru => io}/noties/markwon/linkify/LinkifyPlugin.java (92%) rename markwon-recycler-table/src/main/java/{ru => io}/noties/markwon/recycler/table/TableBorderDrawable.java (96%) rename markwon-recycler-table/src/main/java/{ru => io}/noties/markwon/recycler/table/TableEntry.java (98%) rename markwon-recycler-table/src/main/java/{ru => io}/noties/markwon/recycler/table/TableEntryPlugin.java (86%) rename markwon-recycler-table/src/main/java/{ru => io}/noties/markwon/recycler/table/TableEntryTheme.java (92%) rename markwon-recycler-table/src/test/java/{ru => io}/noties/markwon/recycler/table/TableEntryTest.java (97%) rename markwon-recycler/src/main/java/{ru => io}/noties/markwon/recycler/MarkwonAdapter.java (98%) rename markwon-recycler/src/main/java/{ru => io}/noties/markwon/recycler/MarkwonAdapterImpl.java (97%) rename markwon-recycler/src/main/java/{ru => io}/noties/markwon/recycler/SimpleEntry.java (95%) rename markwon-syntax-highlight/src/main/java/{ru => io}/noties/markwon/syntax/Prism4jSyntaxHighlight.java (98%) rename markwon-syntax-highlight/src/main/java/{ru => io}/noties/markwon/syntax/Prism4jSyntaxVisitor.java (96%) rename markwon-syntax-highlight/src/main/java/{ru => io}/noties/markwon/syntax/Prism4jTheme.java (93%) rename markwon-syntax-highlight/src/main/java/{ru => io}/noties/markwon/syntax/Prism4jThemeBase.java (99%) rename markwon-syntax-highlight/src/main/java/{ru => io}/noties/markwon/syntax/Prism4jThemeDarkula.java (94%) rename markwon-syntax-highlight/src/main/java/{ru => io}/noties/markwon/syntax/Prism4jThemeDefault.java (95%) rename markwon-syntax-highlight/src/main/java/{ru => io}/noties/markwon/syntax/SyntaxHighlightPlugin.java (89%) rename markwon-test-span/src/main/java/{ru => io}/noties/markwon/test/TestSpan.java (99%) rename markwon-test-span/src/main/java/{ru => io}/noties/markwon/test/TestSpanDocument.java (97%) rename markwon-test-span/src/main/java/{ru => io}/noties/markwon/test/TestSpanEnumerator.java (96%) rename markwon-test-span/src/main/java/{ru => io}/noties/markwon/test/TestSpanMatcher.java (99%) rename markwon-test-span/src/main/java/{ru => io}/noties/markwon/test/TestSpanSpan.java (97%) rename markwon-test-span/src/main/java/{ru => io}/noties/markwon/test/TestSpanText.java (96%) rename markwon-test-span/src/test/java/{ru => io}/noties/markwon/test/TestSpanTest.java (70%) rename sample/src/main/java/{ru => io}/noties/markwon/sample/MainActivity.java (89%) rename sample/src/main/java/{ru => io}/noties/markwon/sample/SampleItem.java (94%) rename sample/src/main/java/{ru => io}/noties/markwon/sample/SampleItemDecoration.java (98%) rename sample/src/main/java/{ru => io}/noties/markwon/sample/SampleItemView.java (94%) rename sample/src/main/java/{ru => io}/noties/markwon/sample/basicplugins/BasicPluginsActivity.java (92%) rename sample/src/main/java/{ru => io}/noties/markwon/sample/core/CoreActivity.java (96%) rename sample/src/main/java/{ru => io}/noties/markwon/sample/customextension/CustomExtensionActivity.java (91%) rename sample/src/main/java/{ru => io}/noties/markwon/sample/customextension/IconGroupNode.java (71%) rename sample/src/main/java/{ru => io}/noties/markwon/sample/customextension/IconNode.java (96%) rename sample/src/main/java/{ru => io}/noties/markwon/sample/customextension/IconPlugin.java (93%) rename sample/src/main/java/{ru => io}/noties/markwon/sample/customextension/IconProcessor.java (98%) rename sample/src/main/java/{ru => io}/noties/markwon/sample/customextension/IconSpan.java (97%) rename sample/src/main/java/{ru => io}/noties/markwon/sample/customextension/IconSpanProvider.java (97%) rename sample/src/main/java/{ru => io}/noties/markwon/sample/latex/LatexActivity.java (94%) rename sample/src/main/java/{ru => io}/noties/markwon/sample/recycler/RecyclerActivity.java (86%) rename sample/src/main/java/{ru => io}/noties/markwon/sample/theme/ThemeActivity.java (81%) rename sample/src/test/java/{ru => io}/noties/markwon/sample/MainActivityTest.java (95%) diff --git a/README.md b/README.md index dd379ae3..34db2572 100644 --- a/README.md +++ b/README.md @@ -28,11 +28,11 @@ features listed in [commonmark-spec] are supported ## Installation -![stable](https://img.shields.io/maven-central/v/ru.noties.markwon/core.svg?label=stable) -![snapshot](https://img.shields.io/nexus/s/https/oss.sonatype.org/ru.noties.markwon/core.svg?label=snapshot) +![stable](https://img.shields.io/maven-central/v/io.noties.markwon/core.svg?label=stable) +![snapshot](https://img.shields.io/nexus/s/https/oss.sonatype.org/io.noties.markwon/core.svg?label=snapshot) ```groovy -implementation "ru.noties.markwon:core:${markwonVersion}" +implementation "io.noties.markwon:core:${markwonVersion}" ``` Full list of available artifacts is present in the [install section](https://noties.github.io/Markwon/docs/v3/install.html) @@ -217,7 +217,6 @@ public static Parser createParser() { android:layout_margin="16dip" android:lineSpacingExtra="2dip" android:textSize="16sp" - tools:context="ru.noties.markwon.MainActivity" tools:text="yo\nman" /> @@ -296,7 +295,7 @@ Underscores (`_`) ## License ``` - Copyright 2017 Dimitry Ivanov (mail@dimitryivanov.ru) + Copyright 2019 Dimitry Ivanov (legal@noties.io) Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/app/build.gradle b/app/build.gradle index ffa43c25..c17e0fa6 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -6,7 +6,7 @@ android { buildToolsVersion config['build-tools'] defaultConfig { - applicationId "ru.noties.markwon" + applicationId "io.noties.markwon" minSdkVersion config['min-sdk'] targetSdkVersion config['target-sdk'] versionCode 1 diff --git a/app/src/debug/java/ru/noties/markwon/debug/DebugCheckboxDrawableView.java b/app/src/debug/java/io/noties/markwon/debug/DebugCheckboxDrawableView.java similarity index 94% rename from app/src/debug/java/ru/noties/markwon/debug/DebugCheckboxDrawableView.java rename to app/src/debug/java/io/noties/markwon/debug/DebugCheckboxDrawableView.java index 4c9027cc..759ab4dc 100644 --- a/app/src/debug/java/ru/noties/markwon/debug/DebugCheckboxDrawableView.java +++ b/app/src/debug/java/io/noties/markwon/debug/DebugCheckboxDrawableView.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.debug; +package io.noties.markwon.debug; import android.content.Context; import android.content.res.TypedArray; @@ -8,8 +8,8 @@ import android.support.annotation.Nullable; import android.util.AttributeSet; import android.view.View; -import ru.noties.markwon.R; -import ru.noties.markwon.ext.tasklist.TaskListDrawable; +import io.noties.markwon.app.R; +import io.noties.markwon.ext.tasklist.TaskListDrawable; public class DebugCheckboxDrawableView extends View { diff --git a/app/src/debug/res/layout/debug_checkbox.xml b/app/src/debug/res/layout/debug_checkbox.xml index bf56ec39..3e5d19eb 100644 --- a/app/src/debug/res/layout/debug_checkbox.xml +++ b/app/src/debug/res/layout/debug_checkbox.xml @@ -4,7 +4,7 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - + package="io.noties.markwon.app"> diff --git a/app/src/main/java/ru/noties/markwon/ActivityScope.java b/app/src/main/java/io/noties/markwon/app/ActivityScope.java similarity index 67% rename from app/src/main/java/ru/noties/markwon/ActivityScope.java rename to app/src/main/java/io/noties/markwon/app/ActivityScope.java index de2920a7..38f20d61 100644 --- a/app/src/main/java/ru/noties/markwon/ActivityScope.java +++ b/app/src/main/java/io/noties/markwon/app/ActivityScope.java @@ -1,4 +1,4 @@ -package ru.noties.markwon; +package io.noties.markwon.app; import javax.inject.Scope; diff --git a/app/src/main/java/ru/noties/markwon/App.java b/app/src/main/java/io/noties/markwon/app/App.java similarity index 95% rename from app/src/main/java/ru/noties/markwon/App.java rename to app/src/main/java/io/noties/markwon/app/App.java index 5c9b3157..ce64314a 100644 --- a/app/src/main/java/ru/noties/markwon/App.java +++ b/app/src/main/java/io/noties/markwon/app/App.java @@ -1,4 +1,4 @@ -package ru.noties.markwon; +package io.noties.markwon.app; import android.app.Application; import android.content.Context; diff --git a/app/src/main/java/ru/noties/markwon/AppBarItem.java b/app/src/main/java/io/noties/markwon/app/AppBarItem.java similarity index 97% rename from app/src/main/java/ru/noties/markwon/AppBarItem.java rename to app/src/main/java/io/noties/markwon/app/AppBarItem.java index bf83e658..ce6094c3 100644 --- a/app/src/main/java/ru/noties/markwon/AppBarItem.java +++ b/app/src/main/java/io/noties/markwon/app/AppBarItem.java @@ -1,4 +1,4 @@ -package ru.noties.markwon; +package io.noties.markwon.app; import android.support.annotation.NonNull; import android.text.TextUtils; diff --git a/app/src/main/java/ru/noties/markwon/AppComponent.java b/app/src/main/java/io/noties/markwon/app/AppComponent.java similarity index 86% rename from app/src/main/java/ru/noties/markwon/AppComponent.java rename to app/src/main/java/io/noties/markwon/app/AppComponent.java index 1ff78c29..6f657b1c 100644 --- a/app/src/main/java/ru/noties/markwon/AppComponent.java +++ b/app/src/main/java/io/noties/markwon/app/AppComponent.java @@ -1,4 +1,4 @@ -package ru.noties.markwon; +package io.noties.markwon.app; import javax.inject.Singleton; diff --git a/app/src/main/java/ru/noties/markwon/AppModule.java b/app/src/main/java/io/noties/markwon/app/AppModule.java similarity index 93% rename from app/src/main/java/ru/noties/markwon/AppModule.java rename to app/src/main/java/io/noties/markwon/app/AppModule.java index 32d3e931..4e4acc5a 100644 --- a/app/src/main/java/ru/noties/markwon/AppModule.java +++ b/app/src/main/java/io/noties/markwon/app/AppModule.java @@ -1,4 +1,4 @@ -package ru.noties.markwon; +package io.noties.markwon.app; import android.content.Context; import android.content.res.Resources; @@ -12,10 +12,10 @@ import javax.inject.Singleton; import dagger.Module; import dagger.Provides; +import io.noties.markwon.syntax.Prism4jThemeDarkula; +import io.noties.markwon.syntax.Prism4jThemeDefault; import okhttp3.Cache; import okhttp3.OkHttpClient; -import ru.noties.markwon.syntax.Prism4jThemeDarkula; -import ru.noties.markwon.syntax.Prism4jThemeDefault; import ru.noties.prism4j.Prism4j; import ru.noties.prism4j.annotations.PrismBundle; diff --git a/app/src/main/java/ru/noties/markwon/MainActivity.java b/app/src/main/java/io/noties/markwon/app/MainActivity.java similarity index 98% rename from app/src/main/java/ru/noties/markwon/MainActivity.java rename to app/src/main/java/io/noties/markwon/app/MainActivity.java index fd3965b6..85594e59 100644 --- a/app/src/main/java/ru/noties/markwon/MainActivity.java +++ b/app/src/main/java/io/noties/markwon/app/MainActivity.java @@ -1,4 +1,4 @@ -package ru.noties.markwon; +package io.noties.markwon.app; import android.app.Activity; import android.content.Intent; @@ -12,6 +12,7 @@ import android.widget.TextView; import javax.inject.Inject; +import io.noties.markwon.Markwon; import ru.noties.debug.Debug; public class MainActivity extends Activity { diff --git a/app/src/main/java/ru/noties/markwon/MainActivitySubcomponent.java b/app/src/main/java/io/noties/markwon/app/MainActivitySubcomponent.java similarity index 81% rename from app/src/main/java/ru/noties/markwon/MainActivitySubcomponent.java rename to app/src/main/java/io/noties/markwon/app/MainActivitySubcomponent.java index 077fcd31..24d67488 100644 --- a/app/src/main/java/ru/noties/markwon/MainActivitySubcomponent.java +++ b/app/src/main/java/io/noties/markwon/app/MainActivitySubcomponent.java @@ -1,4 +1,4 @@ -package ru.noties.markwon; +package io.noties.markwon.app; import dagger.Subcomponent; diff --git a/app/src/main/java/ru/noties/markwon/MarkdownLoader.java b/app/src/main/java/io/noties/markwon/app/MarkdownLoader.java similarity index 99% rename from app/src/main/java/ru/noties/markwon/MarkdownLoader.java rename to app/src/main/java/io/noties/markwon/app/MarkdownLoader.java index 02bb902d..b08d8d25 100644 --- a/app/src/main/java/ru/noties/markwon/MarkdownLoader.java +++ b/app/src/main/java/io/noties/markwon/app/MarkdownLoader.java @@ -1,4 +1,4 @@ -package ru.noties.markwon; +package io.noties.markwon.app; import android.content.ContentResolver; import android.content.Context; diff --git a/app/src/main/java/ru/noties/markwon/MarkdownRenderer.java b/app/src/main/java/io/noties/markwon/app/MarkdownRenderer.java similarity index 81% rename from app/src/main/java/ru/noties/markwon/MarkdownRenderer.java rename to app/src/main/java/io/noties/markwon/app/MarkdownRenderer.java index a55d82dc..a924cedd 100644 --- a/app/src/main/java/ru/noties/markwon/MarkdownRenderer.java +++ b/app/src/main/java/io/noties/markwon/app/MarkdownRenderer.java @@ -1,4 +1,4 @@ -package ru.noties.markwon; +package io.noties.markwon.app; import android.content.Context; import android.net.Uri; @@ -13,24 +13,27 @@ import java.util.concurrent.Future; import javax.inject.Inject; +import io.noties.markwon.AbstractMarkwonPlugin; +import io.noties.markwon.Markwon; +import io.noties.markwon.MarkwonConfiguration; +import io.noties.markwon.ext.strikethrough.StrikethroughPlugin; +import io.noties.markwon.ext.tables.TablePlugin; +import io.noties.markwon.ext.tasklist.TaskListPlugin; +import io.noties.markwon.app.gif.GifAwarePlugin; +import io.noties.markwon.html.HtmlPlugin; +import io.noties.markwon.image.ImagesPlugin; +import io.noties.markwon.image.data.DataUriSchemeHandler; +import io.noties.markwon.image.file.FileSchemeHandler; +import io.noties.markwon.image.gif.GifMediaDecoder; +import io.noties.markwon.image.network.OkHttpNetworkSchemeHandler; +import io.noties.markwon.image.svg.SvgMediaDecoder; +import io.noties.markwon.syntax.Prism4jTheme; +import io.noties.markwon.syntax.Prism4jThemeDarkula; +import io.noties.markwon.syntax.Prism4jThemeDefault; +import io.noties.markwon.syntax.SyntaxHighlightPlugin; +import io.noties.markwon.urlprocessor.UrlProcessor; +import io.noties.markwon.urlprocessor.UrlProcessorRelativeToAbsolute; import ru.noties.debug.Debug; -import ru.noties.markwon.ext.strikethrough.StrikethroughPlugin; -import ru.noties.markwon.ext.tables.TablePlugin; -import ru.noties.markwon.ext.tasklist.TaskListPlugin; -import ru.noties.markwon.gif.GifAwarePlugin; -import ru.noties.markwon.html.HtmlPlugin; -import ru.noties.markwon.image.ImagesPlugin; -import ru.noties.markwon.image.data.DataUriSchemeHandler; -import ru.noties.markwon.image.file.FileSchemeHandler; -import ru.noties.markwon.image.gif.GifMediaDecoder; -import ru.noties.markwon.image.network.OkHttpNetworkSchemeHandler; -import ru.noties.markwon.image.svg.SvgMediaDecoder; -import ru.noties.markwon.syntax.Prism4jTheme; -import ru.noties.markwon.syntax.Prism4jThemeDarkula; -import ru.noties.markwon.syntax.Prism4jThemeDefault; -import ru.noties.markwon.syntax.SyntaxHighlightPlugin; -import ru.noties.markwon.urlprocessor.UrlProcessor; -import ru.noties.markwon.urlprocessor.UrlProcessorRelativeToAbsolute; import ru.noties.prism4j.Prism4j; @ActivityScope diff --git a/app/src/main/java/ru/noties/markwon/Themes.java b/app/src/main/java/io/noties/markwon/app/Themes.java similarity index 97% rename from app/src/main/java/ru/noties/markwon/Themes.java rename to app/src/main/java/io/noties/markwon/app/Themes.java index 85ab846c..f2dc5571 100644 --- a/app/src/main/java/ru/noties/markwon/Themes.java +++ b/app/src/main/java/io/noties/markwon/app/Themes.java @@ -1,4 +1,4 @@ -package ru.noties.markwon; +package io.noties.markwon.app; import android.content.Context; import android.content.SharedPreferences; diff --git a/app/src/main/java/ru/noties/markwon/UriProcessor.java b/app/src/main/java/io/noties/markwon/app/UriProcessor.java similarity index 84% rename from app/src/main/java/ru/noties/markwon/UriProcessor.java rename to app/src/main/java/io/noties/markwon/app/UriProcessor.java index a4fb5b85..4fcc48dd 100644 --- a/app/src/main/java/ru/noties/markwon/UriProcessor.java +++ b/app/src/main/java/io/noties/markwon/app/UriProcessor.java @@ -1,4 +1,4 @@ -package ru.noties.markwon; +package io.noties.markwon.app; import android.net.Uri; import android.support.annotation.NonNull; diff --git a/app/src/main/java/ru/noties/markwon/UriProcessorImpl.java b/app/src/main/java/io/noties/markwon/app/UriProcessorImpl.java similarity index 97% rename from app/src/main/java/ru/noties/markwon/UriProcessorImpl.java rename to app/src/main/java/io/noties/markwon/app/UriProcessorImpl.java index 03d29353..843a2403 100644 --- a/app/src/main/java/ru/noties/markwon/UriProcessorImpl.java +++ b/app/src/main/java/io/noties/markwon/app/UriProcessorImpl.java @@ -1,4 +1,4 @@ -package ru.noties.markwon; +package io.noties.markwon.app; import android.net.Uri; import android.support.annotation.NonNull; diff --git a/app/src/main/java/ru/noties/markwon/UrlProcessorInitialReadme.java b/app/src/main/java/io/noties/markwon/app/UrlProcessorInitialReadme.java similarity index 83% rename from app/src/main/java/ru/noties/markwon/UrlProcessorInitialReadme.java rename to app/src/main/java/io/noties/markwon/app/UrlProcessorInitialReadme.java index d9690574..535a4810 100644 --- a/app/src/main/java/ru/noties/markwon/UrlProcessorInitialReadme.java +++ b/app/src/main/java/io/noties/markwon/app/UrlProcessorInitialReadme.java @@ -1,11 +1,11 @@ -package ru.noties.markwon; +package io.noties.markwon.app; import android.net.Uri; import android.support.annotation.NonNull; import android.text.TextUtils; -import ru.noties.markwon.urlprocessor.UrlProcessor; -import ru.noties.markwon.urlprocessor.UrlProcessorRelativeToAbsolute; +import io.noties.markwon.urlprocessor.UrlProcessor; +import io.noties.markwon.urlprocessor.UrlProcessorRelativeToAbsolute; class UrlProcessorInitialReadme implements UrlProcessor { diff --git a/app/src/main/java/ru/noties/markwon/Views.java b/app/src/main/java/io/noties/markwon/app/Views.java similarity index 95% rename from app/src/main/java/ru/noties/markwon/Views.java rename to app/src/main/java/io/noties/markwon/app/Views.java index 3c172e4b..db438375 100644 --- a/app/src/main/java/ru/noties/markwon/Views.java +++ b/app/src/main/java/io/noties/markwon/app/Views.java @@ -1,4 +1,4 @@ -package ru.noties.markwon; +package io.noties.markwon.app; import android.support.annotation.IntDef; import android.support.annotation.NonNull; diff --git a/app/src/main/java/ru/noties/markwon/gif/GifAwareAsyncDrawable.java b/app/src/main/java/io/noties/markwon/app/gif/GifAwareAsyncDrawable.java similarity index 88% rename from app/src/main/java/ru/noties/markwon/gif/GifAwareAsyncDrawable.java rename to app/src/main/java/io/noties/markwon/app/gif/GifAwareAsyncDrawable.java index b5ba34ce..553bcd90 100644 --- a/app/src/main/java/ru/noties/markwon/gif/GifAwareAsyncDrawable.java +++ b/app/src/main/java/io/noties/markwon/app/gif/GifAwareAsyncDrawable.java @@ -1,15 +1,15 @@ -package ru.noties.markwon.gif; +package io.noties.markwon.app.gif; import android.graphics.Canvas; import android.graphics.drawable.Drawable; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import io.noties.markwon.image.AsyncDrawable; +import io.noties.markwon.image.AsyncDrawableLoader; +import io.noties.markwon.image.ImageSize; +import io.noties.markwon.image.ImageSizeResolver; import pl.droidsonroids.gif.GifDrawable; -import ru.noties.markwon.image.AsyncDrawableLoader; -import ru.noties.markwon.image.ImageSize; -import ru.noties.markwon.image.ImageSizeResolver; -import ru.noties.markwon.image.AsyncDrawable; public class GifAwareAsyncDrawable extends AsyncDrawable { diff --git a/app/src/main/java/ru/noties/markwon/gif/GifAwarePlugin.java b/app/src/main/java/io/noties/markwon/app/gif/GifAwarePlugin.java similarity index 82% rename from app/src/main/java/ru/noties/markwon/gif/GifAwarePlugin.java rename to app/src/main/java/io/noties/markwon/app/gif/GifAwarePlugin.java index 95509525..ad5ab813 100644 --- a/app/src/main/java/ru/noties/markwon/gif/GifAwarePlugin.java +++ b/app/src/main/java/io/noties/markwon/app/gif/GifAwarePlugin.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.gif; +package io.noties.markwon.app.gif; import android.content.Context; import android.support.annotation.NonNull; @@ -6,14 +6,14 @@ import android.widget.TextView; import org.commonmark.node.Image; -import ru.noties.markwon.AbstractMarkwonPlugin; -import ru.noties.markwon.MarkwonConfiguration; -import ru.noties.markwon.MarkwonSpansFactory; -import ru.noties.markwon.R; -import ru.noties.markwon.RenderProps; -import ru.noties.markwon.SpanFactory; -import ru.noties.markwon.image.AsyncDrawableSpan; -import ru.noties.markwon.image.ImageProps; +import io.noties.markwon.AbstractMarkwonPlugin; +import io.noties.markwon.MarkwonConfiguration; +import io.noties.markwon.MarkwonSpansFactory; +import io.noties.markwon.RenderProps; +import io.noties.markwon.SpanFactory; +import io.noties.markwon.app.R; +import io.noties.markwon.image.AsyncDrawableSpan; +import io.noties.markwon.image.ImageProps; public class GifAwarePlugin extends AbstractMarkwonPlugin { diff --git a/app/src/main/java/ru/noties/markwon/gif/GifPlaceholder.java b/app/src/main/java/io/noties/markwon/app/gif/GifPlaceholder.java similarity index 98% rename from app/src/main/java/ru/noties/markwon/gif/GifPlaceholder.java rename to app/src/main/java/io/noties/markwon/app/gif/GifPlaceholder.java index 7d6dcbe1..326d1b22 100644 --- a/app/src/main/java/ru/noties/markwon/gif/GifPlaceholder.java +++ b/app/src/main/java/io/noties/markwon/app/gif/GifPlaceholder.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.gif; +package io.noties.markwon.app.gif; import android.graphics.Canvas; import android.graphics.ColorFilter; diff --git a/app/src/main/java/ru/noties/markwon/gif/GifProcessor.java b/app/src/main/java/io/noties/markwon/app/gif/GifProcessor.java similarity index 98% rename from app/src/main/java/ru/noties/markwon/gif/GifProcessor.java rename to app/src/main/java/io/noties/markwon/app/gif/GifProcessor.java index 8cdb1da5..266c5a03 100644 --- a/app/src/main/java/ru/noties/markwon/gif/GifProcessor.java +++ b/app/src/main/java/io/noties/markwon/app/gif/GifProcessor.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.gif; +package io.noties.markwon.app.gif; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -8,8 +8,8 @@ import android.text.style.ClickableSpan; import android.view.View; import android.widget.TextView; +import io.noties.markwon.image.AsyncDrawableSpan; import pl.droidsonroids.gif.GifDrawable; -import ru.noties.markwon.image.AsyncDrawableSpan; public abstract class GifProcessor { diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 0bd1c6ac..da49a67b 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -20,7 +20,6 @@ android:layout_height="wrap_content" android:lineSpacingExtra="2dip" android:textSize="16sp" - tools:context="ru.noties.markwon.MainActivity" tools:text="yo\nman" /> diff --git a/gradle.properties b/gradle.properties index e3eb78c6..59be8bf9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,7 +8,7 @@ android.buildCacheDir=build/pre-dex-cache VERSION_NAME=4.0.0-SNAPSHOT -GROUP=ru.noties.markwon +GROUP=io.noties.markwon POM_DESCRIPTION=Markwon markdown for Android POM_URL=https://github.com/noties/Markwon POM_SCM_URL=https://github.com/noties/Markwon diff --git a/markwon-core/src/main/AndroidManifest.xml b/markwon-core/src/main/AndroidManifest.xml index c3f0b404..52c9768c 100644 --- a/markwon-core/src/main/AndroidManifest.xml +++ b/markwon-core/src/main/AndroidManifest.xml @@ -1 +1 @@ - + diff --git a/markwon-core/src/main/java/ru/noties/markwon/AbstractMarkwonPlugin.java b/markwon-core/src/main/java/io/noties/markwon/AbstractMarkwonPlugin.java similarity index 92% rename from markwon-core/src/main/java/ru/noties/markwon/AbstractMarkwonPlugin.java rename to markwon-core/src/main/java/io/noties/markwon/AbstractMarkwonPlugin.java index 4fb39da0..d7d9f744 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/AbstractMarkwonPlugin.java +++ b/markwon-core/src/main/java/io/noties/markwon/AbstractMarkwonPlugin.java @@ -1,4 +1,4 @@ -package ru.noties.markwon; +package io.noties.markwon; import android.support.annotation.NonNull; import android.text.Spanned; @@ -7,8 +7,7 @@ import android.widget.TextView; import org.commonmark.node.Node; import org.commonmark.parser.Parser; -import ru.noties.markwon.core.MarkwonTheme; -import ru.noties.markwon.html.MarkwonHtmlRenderer; +import io.noties.markwon.core.MarkwonTheme; /** * Class that extends {@link MarkwonPlugin} with all methods implemented (empty body) diff --git a/markwon-core/src/main/java/ru/noties/markwon/LinkResolverDef.java b/markwon-core/src/main/java/io/noties/markwon/LinkResolverDef.java similarity index 92% rename from markwon-core/src/main/java/ru/noties/markwon/LinkResolverDef.java rename to markwon-core/src/main/java/io/noties/markwon/LinkResolverDef.java index 4f893761..da08c9fc 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/LinkResolverDef.java +++ b/markwon-core/src/main/java/io/noties/markwon/LinkResolverDef.java @@ -1,4 +1,4 @@ -package ru.noties.markwon; +package io.noties.markwon; import android.content.ActivityNotFoundException; import android.content.Context; @@ -9,7 +9,7 @@ import android.support.annotation.NonNull; import android.util.Log; import android.view.View; -import ru.noties.markwon.core.spans.LinkSpan; +import io.noties.markwon.core.spans.LinkSpan; public class LinkResolverDef implements LinkSpan.Resolver { @Override diff --git a/markwon-core/src/main/java/ru/noties/markwon/Markwon.java b/markwon-core/src/main/java/io/noties/markwon/Markwon.java similarity index 98% rename from markwon-core/src/main/java/ru/noties/markwon/Markwon.java rename to markwon-core/src/main/java/io/noties/markwon/Markwon.java index 17f4af24..6f7af7bf 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/Markwon.java +++ b/markwon-core/src/main/java/io/noties/markwon/Markwon.java @@ -1,4 +1,4 @@ -package ru.noties.markwon; +package io.noties.markwon; import android.content.Context; import android.support.annotation.NonNull; @@ -8,7 +8,7 @@ import android.widget.TextView; import org.commonmark.node.Node; -import ru.noties.markwon.core.CorePlugin; +import io.noties.markwon.core.CorePlugin; /** * Class to parse and render markdown. Since version 3.0.0 instance specific (previously consisted diff --git a/markwon-core/src/main/java/ru/noties/markwon/MarkwonBuilderImpl.java b/markwon-core/src/main/java/io/noties/markwon/MarkwonBuilderImpl.java similarity index 98% rename from markwon-core/src/main/java/ru/noties/markwon/MarkwonBuilderImpl.java rename to markwon-core/src/main/java/io/noties/markwon/MarkwonBuilderImpl.java index 863cfe30..7166aedc 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/MarkwonBuilderImpl.java +++ b/markwon-core/src/main/java/io/noties/markwon/MarkwonBuilderImpl.java @@ -1,4 +1,4 @@ -package ru.noties.markwon; +package io.noties.markwon; import android.content.Context; import android.support.annotation.NonNull; @@ -15,7 +15,7 @@ import java.util.Iterator; import java.util.List; import java.util.Set; -import ru.noties.markwon.core.MarkwonTheme; +import io.noties.markwon.core.MarkwonTheme; /** * @since 3.0.0 diff --git a/markwon-core/src/main/java/ru/noties/markwon/MarkwonConfiguration.java b/markwon-core/src/main/java/io/noties/markwon/MarkwonConfiguration.java similarity index 90% rename from markwon-core/src/main/java/ru/noties/markwon/MarkwonConfiguration.java rename to markwon-core/src/main/java/io/noties/markwon/MarkwonConfiguration.java index 66159da4..9b4ffb95 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/MarkwonConfiguration.java +++ b/markwon-core/src/main/java/io/noties/markwon/MarkwonConfiguration.java @@ -1,18 +1,18 @@ -package ru.noties.markwon; +package io.noties.markwon; import android.support.annotation.NonNull; -import ru.noties.markwon.core.MarkwonTheme; -import ru.noties.markwon.core.spans.LinkSpan; -import ru.noties.markwon.html.MarkwonHtmlParser; -import ru.noties.markwon.html.MarkwonHtmlRenderer; -import ru.noties.markwon.image.AsyncDrawableLoader; -import ru.noties.markwon.image.ImageSizeResolver; -import ru.noties.markwon.image.ImageSizeResolverDef; -import ru.noties.markwon.syntax.SyntaxHighlight; -import ru.noties.markwon.syntax.SyntaxHighlightNoOp; -import ru.noties.markwon.urlprocessor.UrlProcessor; -import ru.noties.markwon.urlprocessor.UrlProcessorNoOp; +import io.noties.markwon.core.MarkwonTheme; +import io.noties.markwon.core.spans.LinkSpan; +import io.noties.markwon.html.MarkwonHtmlParser; +import io.noties.markwon.html.MarkwonHtmlRenderer; +import io.noties.markwon.image.AsyncDrawableLoader; +import io.noties.markwon.image.ImageSizeResolver; +import io.noties.markwon.image.ImageSizeResolverDef; +import io.noties.markwon.syntax.SyntaxHighlight; +import io.noties.markwon.syntax.SyntaxHighlightNoOp; +import io.noties.markwon.urlprocessor.UrlProcessor; +import io.noties.markwon.urlprocessor.UrlProcessorNoOp; /** * since 3.0.0 renamed `SpannableConfiguration` -> `MarkwonConfiguration` diff --git a/markwon-core/src/main/java/ru/noties/markwon/MarkwonImpl.java b/markwon-core/src/main/java/io/noties/markwon/MarkwonImpl.java similarity index 99% rename from markwon-core/src/main/java/ru/noties/markwon/MarkwonImpl.java rename to markwon-core/src/main/java/io/noties/markwon/MarkwonImpl.java index e90b7898..d76925ae 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/MarkwonImpl.java +++ b/markwon-core/src/main/java/io/noties/markwon/MarkwonImpl.java @@ -1,4 +1,4 @@ -package ru.noties.markwon; +package io.noties.markwon; import android.support.annotation.NonNull; import android.support.annotation.Nullable; diff --git a/markwon-core/src/main/java/ru/noties/markwon/MarkwonNodeRenderer.java b/markwon-core/src/main/java/io/noties/markwon/MarkwonNodeRenderer.java similarity index 99% rename from markwon-core/src/main/java/ru/noties/markwon/MarkwonNodeRenderer.java rename to markwon-core/src/main/java/io/noties/markwon/MarkwonNodeRenderer.java index 94de3c20..7038a620 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/MarkwonNodeRenderer.java +++ b/markwon-core/src/main/java/io/noties/markwon/MarkwonNodeRenderer.java @@ -1,4 +1,4 @@ -package ru.noties.markwon; +package io.noties.markwon; import android.content.Context; import android.support.annotation.IdRes; diff --git a/markwon-core/src/main/java/ru/noties/markwon/MarkwonPlugin.java b/markwon-core/src/main/java/io/noties/markwon/MarkwonPlugin.java similarity index 91% rename from markwon-core/src/main/java/ru/noties/markwon/MarkwonPlugin.java rename to markwon-core/src/main/java/io/noties/markwon/MarkwonPlugin.java index fb7f1022..f84ab62a 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/MarkwonPlugin.java +++ b/markwon-core/src/main/java/io/noties/markwon/MarkwonPlugin.java @@ -1,4 +1,4 @@ -package ru.noties.markwon; +package io.noties.markwon; import android.support.annotation.NonNull; import android.text.Spanned; @@ -7,16 +7,18 @@ import android.widget.TextView; import org.commonmark.node.Node; import org.commonmark.parser.Parser; -import ru.noties.markwon.core.MarkwonTheme; -import ru.noties.markwon.html.MarkwonHtmlRenderer; +import io.noties.markwon.core.CorePlugin; +import io.noties.markwon.core.MarkwonTheme; +import io.noties.markwon.image.AsyncDrawableSpan; +import io.noties.markwon.movement.MovementMethodPlugin; /** * Class represents a plugin (extension) to Markwon to configure how parsing and rendering * of markdown is carried on. * * @see AbstractMarkwonPlugin - * @see ru.noties.markwon.core.CorePlugin - * @see ru.noties.markwon.movement.MovementMethodPlugin + * @see CorePlugin + * @see MovementMethodPlugin * @since 3.0.0 */ public interface MarkwonPlugin { @@ -89,7 +91,7 @@ public interface MarkwonPlugin { void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder); // /** -// * Configure {@link MarkwonHtmlRenderer} to add or remove HTML {@link ru.noties.markwon.html.TagHandler}s +// * Configure {@link MarkwonHtmlRenderer} to add or remove HTML {@link TagHandler}s // * // * @see MarkwonHtmlRenderer // * @see MarkwonHtmlRenderer.Builder @@ -129,8 +131,8 @@ public interface MarkwonPlugin { * This method will be called before calling TextView#setText. *

* It can be useful to prepare a TextView for markdown. For example {@code ru.noties.markwon.image.ImagesPlugin} - * uses this method to unregister previously registered {@link ru.noties.markwon.image.AsyncDrawableSpan} - * (if there are such spans in this TextView at this point). Or {@link ru.noties.markwon.core.CorePlugin} + * uses this method to unregister previously registered {@link AsyncDrawableSpan} + * (if there are such spans in this TextView at this point). Or {@link CorePlugin} * which measures ordered list numbers * * @param textView TextView to which markdown will be applied @@ -142,7 +144,7 @@ public interface MarkwonPlugin { * This method will be called after markdown was applied. *

* It can be useful to trigger certain action on spans/textView. For example {@code ru.noties.markwon.image.ImagesPlugin} - * uses this method to register {@link ru.noties.markwon.image.AsyncDrawableSpan} and start + * uses this method to register {@link AsyncDrawableSpan} and start * asynchronously loading images. *

* Unlike {@link #beforeSetText(TextView, Spanned)} this method does not receive parsed markdown diff --git a/markwon-core/src/main/java/ru/noties/markwon/MarkwonReducer.java b/markwon-core/src/main/java/io/noties/markwon/MarkwonReducer.java similarity index 98% rename from markwon-core/src/main/java/ru/noties/markwon/MarkwonReducer.java rename to markwon-core/src/main/java/io/noties/markwon/MarkwonReducer.java index a139e3f1..82a61963 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/MarkwonReducer.java +++ b/markwon-core/src/main/java/io/noties/markwon/MarkwonReducer.java @@ -1,4 +1,4 @@ -package ru.noties.markwon; +package io.noties.markwon; import android.support.annotation.NonNull; diff --git a/markwon-core/src/main/java/ru/noties/markwon/MarkwonSpansFactory.java b/markwon-core/src/main/java/io/noties/markwon/MarkwonSpansFactory.java similarity index 98% rename from markwon-core/src/main/java/ru/noties/markwon/MarkwonSpansFactory.java rename to markwon-core/src/main/java/io/noties/markwon/MarkwonSpansFactory.java index 2ef3f47f..2dd6b156 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/MarkwonSpansFactory.java +++ b/markwon-core/src/main/java/io/noties/markwon/MarkwonSpansFactory.java @@ -1,4 +1,4 @@ -package ru.noties.markwon; +package io.noties.markwon; import android.support.annotation.NonNull; import android.support.annotation.Nullable; diff --git a/markwon-core/src/main/java/ru/noties/markwon/MarkwonSpansFactoryImpl.java b/markwon-core/src/main/java/io/noties/markwon/MarkwonSpansFactoryImpl.java similarity index 99% rename from markwon-core/src/main/java/ru/noties/markwon/MarkwonSpansFactoryImpl.java rename to markwon-core/src/main/java/io/noties/markwon/MarkwonSpansFactoryImpl.java index 85a4ab33..66c3823d 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/MarkwonSpansFactoryImpl.java +++ b/markwon-core/src/main/java/io/noties/markwon/MarkwonSpansFactoryImpl.java @@ -1,4 +1,4 @@ -package ru.noties.markwon; +package io.noties.markwon; import android.support.annotation.NonNull; import android.support.annotation.Nullable; diff --git a/markwon-core/src/main/java/ru/noties/markwon/MarkwonVisitor.java b/markwon-core/src/main/java/io/noties/markwon/MarkwonVisitor.java similarity index 99% rename from markwon-core/src/main/java/ru/noties/markwon/MarkwonVisitor.java rename to markwon-core/src/main/java/io/noties/markwon/MarkwonVisitor.java index e7a83db0..b2dd95c2 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/MarkwonVisitor.java +++ b/markwon-core/src/main/java/io/noties/markwon/MarkwonVisitor.java @@ -1,4 +1,4 @@ -package ru.noties.markwon; +package io.noties.markwon; import android.support.annotation.NonNull; import android.support.annotation.Nullable; diff --git a/markwon-core/src/main/java/ru/noties/markwon/MarkwonVisitorImpl.java b/markwon-core/src/main/java/io/noties/markwon/MarkwonVisitorImpl.java similarity index 99% rename from markwon-core/src/main/java/ru/noties/markwon/MarkwonVisitorImpl.java rename to markwon-core/src/main/java/io/noties/markwon/MarkwonVisitorImpl.java index d4f0bce6..f443bcd4 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/MarkwonVisitorImpl.java +++ b/markwon-core/src/main/java/io/noties/markwon/MarkwonVisitorImpl.java @@ -1,4 +1,4 @@ -package ru.noties.markwon; +package io.noties.markwon; import android.support.annotation.NonNull; import android.support.annotation.Nullable; diff --git a/markwon-core/src/main/java/ru/noties/markwon/Prop.java b/markwon-core/src/main/java/io/noties/markwon/Prop.java similarity index 98% rename from markwon-core/src/main/java/ru/noties/markwon/Prop.java rename to markwon-core/src/main/java/io/noties/markwon/Prop.java index 91b4515b..552a4340 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/Prop.java +++ b/markwon-core/src/main/java/io/noties/markwon/Prop.java @@ -1,4 +1,4 @@ -package ru.noties.markwon; +package io.noties.markwon; import android.support.annotation.NonNull; import android.support.annotation.Nullable; diff --git a/markwon-core/src/main/java/ru/noties/markwon/RenderProps.java b/markwon-core/src/main/java/io/noties/markwon/RenderProps.java similarity index 93% rename from markwon-core/src/main/java/ru/noties/markwon/RenderProps.java rename to markwon-core/src/main/java/io/noties/markwon/RenderProps.java index e28edbaf..61442969 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/RenderProps.java +++ b/markwon-core/src/main/java/io/noties/markwon/RenderProps.java @@ -1,4 +1,4 @@ -package ru.noties.markwon; +package io.noties.markwon; import android.support.annotation.NonNull; import android.support.annotation.Nullable; diff --git a/markwon-core/src/main/java/ru/noties/markwon/RenderPropsImpl.java b/markwon-core/src/main/java/io/noties/markwon/RenderPropsImpl.java similarity index 97% rename from markwon-core/src/main/java/ru/noties/markwon/RenderPropsImpl.java rename to markwon-core/src/main/java/io/noties/markwon/RenderPropsImpl.java index 24557975..9b0fc241 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/RenderPropsImpl.java +++ b/markwon-core/src/main/java/io/noties/markwon/RenderPropsImpl.java @@ -1,4 +1,4 @@ -package ru.noties.markwon; +package io.noties.markwon; import android.support.annotation.NonNull; import android.support.annotation.Nullable; diff --git a/markwon-core/src/main/java/ru/noties/markwon/SpanFactory.java b/markwon-core/src/main/java/io/noties/markwon/SpanFactory.java similarity index 91% rename from markwon-core/src/main/java/ru/noties/markwon/SpanFactory.java rename to markwon-core/src/main/java/io/noties/markwon/SpanFactory.java index 76e251e7..6a90a533 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/SpanFactory.java +++ b/markwon-core/src/main/java/io/noties/markwon/SpanFactory.java @@ -1,4 +1,4 @@ -package ru.noties.markwon; +package io.noties.markwon; import android.support.annotation.NonNull; import android.support.annotation.Nullable; diff --git a/markwon-core/src/main/java/ru/noties/markwon/SpannableBuilder.java b/markwon-core/src/main/java/io/noties/markwon/SpannableBuilder.java similarity index 99% rename from markwon-core/src/main/java/ru/noties/markwon/SpannableBuilder.java rename to markwon-core/src/main/java/io/noties/markwon/SpannableBuilder.java index 3c10f779..a9f3a48d 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/SpannableBuilder.java +++ b/markwon-core/src/main/java/io/noties/markwon/SpannableBuilder.java @@ -1,4 +1,4 @@ -package ru.noties.markwon; +package io.noties.markwon; import android.support.annotation.NonNull; import android.support.annotation.Nullable; diff --git a/markwon-core/src/main/java/ru/noties/markwon/core/CorePlugin.java b/markwon-core/src/main/java/io/noties/markwon/core/CorePlugin.java similarity index 94% rename from markwon-core/src/main/java/ru/noties/markwon/core/CorePlugin.java rename to markwon-core/src/main/java/io/noties/markwon/core/CorePlugin.java index 506da2b9..2604ecdc 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/core/CorePlugin.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/CorePlugin.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.core; +package io.noties.markwon.core; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -30,23 +30,24 @@ import org.commonmark.node.ThematicBreak; import java.util.ArrayList; import java.util.List; -import ru.noties.markwon.AbstractMarkwonPlugin; -import ru.noties.markwon.MarkwonConfiguration; -import ru.noties.markwon.MarkwonSpansFactory; -import ru.noties.markwon.MarkwonVisitor; -import ru.noties.markwon.RenderProps; -import ru.noties.markwon.SpanFactory; -import ru.noties.markwon.core.factory.BlockQuoteSpanFactory; -import ru.noties.markwon.core.factory.CodeBlockSpanFactory; -import ru.noties.markwon.core.factory.CodeSpanFactory; -import ru.noties.markwon.core.factory.EmphasisSpanFactory; -import ru.noties.markwon.core.factory.HeadingSpanFactory; -import ru.noties.markwon.core.factory.LinkSpanFactory; -import ru.noties.markwon.core.factory.ListItemSpanFactory; -import ru.noties.markwon.core.factory.StrongEmphasisSpanFactory; -import ru.noties.markwon.core.factory.ThematicBreakSpanFactory; -import ru.noties.markwon.core.spans.OrderedListItemSpan; -import ru.noties.markwon.image.ImageProps; +import io.noties.markwon.SpannableBuilder; +import io.noties.markwon.core.spans.OrderedListItemSpan; +import io.noties.markwon.image.ImageProps; +import io.noties.markwon.AbstractMarkwonPlugin; +import io.noties.markwon.MarkwonConfiguration; +import io.noties.markwon.MarkwonSpansFactory; +import io.noties.markwon.MarkwonVisitor; +import io.noties.markwon.RenderProps; +import io.noties.markwon.SpanFactory; +import io.noties.markwon.core.factory.BlockQuoteSpanFactory; +import io.noties.markwon.core.factory.CodeBlockSpanFactory; +import io.noties.markwon.core.factory.CodeSpanFactory; +import io.noties.markwon.core.factory.EmphasisSpanFactory; +import io.noties.markwon.core.factory.HeadingSpanFactory; +import io.noties.markwon.core.factory.LinkSpanFactory; +import io.noties.markwon.core.factory.ListItemSpanFactory; +import io.noties.markwon.core.factory.StrongEmphasisSpanFactory; +import io.noties.markwon.core.factory.ThematicBreakSpanFactory; /** * @see CoreProps @@ -61,7 +62,7 @@ public class CorePlugin extends AbstractMarkwonPlugin { public interface OnTextAddedListener { /** - * Will be called when new text is added to resulting {@link ru.noties.markwon.SpannableBuilder}. + * Will be called when new text is added to resulting {@link SpannableBuilder}. * Please note that only text represented by {@link Text} node will trigger this callback * (text inside code and code-blocks won\'t trigger it). *

diff --git a/markwon-core/src/main/java/ru/noties/markwon/core/CoreProps.java b/markwon-core/src/main/java/io/noties/markwon/core/CoreProps.java similarity index 92% rename from markwon-core/src/main/java/ru/noties/markwon/core/CoreProps.java rename to markwon-core/src/main/java/io/noties/markwon/core/CoreProps.java index 4a722b0f..1da57e24 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/core/CoreProps.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/CoreProps.java @@ -1,6 +1,6 @@ -package ru.noties.markwon.core; +package io.noties.markwon.core; -import ru.noties.markwon.Prop; +import io.noties.markwon.Prop; /** * @since 3.0.0 diff --git a/markwon-core/src/main/java/ru/noties/markwon/core/MarkwonTheme.java b/markwon-core/src/main/java/io/noties/markwon/core/MarkwonTheme.java similarity index 98% rename from markwon-core/src/main/java/ru/noties/markwon/core/MarkwonTheme.java rename to markwon-core/src/main/java/io/noties/markwon/core/MarkwonTheme.java index f01df083..8a9dcee6 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/core/MarkwonTheme.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/MarkwonTheme.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.core; +package io.noties.markwon.core; import android.content.Context; import android.graphics.Paint; @@ -13,8 +13,9 @@ import android.text.TextPaint; import java.util.Arrays; import java.util.Locale; -import ru.noties.markwon.utils.ColorUtils; -import ru.noties.markwon.utils.Dip; +import io.noties.markwon.MarkwonPlugin; +import io.noties.markwon.utils.ColorUtils; +import io.noties.markwon.utils.Dip; /** * Class to hold theming information for rending of markdown. @@ -23,14 +24,14 @@ import ru.noties.markwon.utils.Dip; * information holds data for core features only. But based on this other components can still use it * to display markdown consistently. *

- * Since version 3.0.0 this class should not be instantiated manually. Instead a {@link ru.noties.markwon.MarkwonPlugin} - * should be used: {@link ru.noties.markwon.MarkwonPlugin#configureTheme(Builder)} + * Since version 3.0.0 this class should not be instantiated manually. Instead a {@link MarkwonPlugin} + * should be used: {@link MarkwonPlugin#configureTheme(Builder)} *

* Since version 3.0.0 properties related to strike-through, tables and HTML * are moved to specific plugins in independent artifacts * * @see CorePlugin - * @see ru.noties.markwon.MarkwonPlugin#configureTheme(Builder) + * @see MarkwonPlugin#configureTheme(Builder) */ @SuppressWarnings("WeakerAccess") public class MarkwonTheme { @@ -52,7 +53,7 @@ public class MarkwonTheme { * Create an empty instance of {@link Builder} with no default values applied *

* Since version 3.0.0 manual construction of {@link MarkwonTheme} is not required, instead a - * {@link ru.noties.markwon.MarkwonPlugin#configureTheme(Builder)} should be used in order + * {@link MarkwonPlugin#configureTheme(Builder)} should be used in order * to change certain theme properties * * @since 3.0.0 diff --git a/markwon-core/src/main/java/ru/noties/markwon/core/SimpleBlockNodeVisitor.java b/markwon-core/src/main/java/io/noties/markwon/core/SimpleBlockNodeVisitor.java similarity index 84% rename from markwon-core/src/main/java/ru/noties/markwon/core/SimpleBlockNodeVisitor.java rename to markwon-core/src/main/java/io/noties/markwon/core/SimpleBlockNodeVisitor.java index 31f04081..03ffaeff 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/core/SimpleBlockNodeVisitor.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/SimpleBlockNodeVisitor.java @@ -1,13 +1,13 @@ -package ru.noties.markwon.core; +package io.noties.markwon.core; import android.support.annotation.NonNull; import org.commonmark.node.Node; -import ru.noties.markwon.MarkwonVisitor; +import io.noties.markwon.MarkwonVisitor; /** - * A {@link ru.noties.markwon.MarkwonVisitor.NodeVisitor} that ensures that a markdown + * A {@link MarkwonVisitor.NodeVisitor} that ensures that a markdown * block starts with a new line, all children are visited and if further content available * ensures a new line after self. Does not render any spans * diff --git a/markwon-core/src/main/java/ru/noties/markwon/core/factory/BlockQuoteSpanFactory.java b/markwon-core/src/main/java/io/noties/markwon/core/factory/BlockQuoteSpanFactory.java similarity index 61% rename from markwon-core/src/main/java/ru/noties/markwon/core/factory/BlockQuoteSpanFactory.java rename to markwon-core/src/main/java/io/noties/markwon/core/factory/BlockQuoteSpanFactory.java index cbe86db6..30fa2853 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/core/factory/BlockQuoteSpanFactory.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/factory/BlockQuoteSpanFactory.java @@ -1,12 +1,12 @@ -package ru.noties.markwon.core.factory; +package io.noties.markwon.core.factory; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import ru.noties.markwon.MarkwonConfiguration; -import ru.noties.markwon.RenderProps; -import ru.noties.markwon.SpanFactory; -import ru.noties.markwon.core.spans.BlockQuoteSpan; +import io.noties.markwon.core.spans.BlockQuoteSpan; +import io.noties.markwon.MarkwonConfiguration; +import io.noties.markwon.RenderProps; +import io.noties.markwon.SpanFactory; public class BlockQuoteSpanFactory implements SpanFactory { @Nullable diff --git a/markwon-core/src/main/java/ru/noties/markwon/core/factory/CodeBlockSpanFactory.java b/markwon-core/src/main/java/io/noties/markwon/core/factory/CodeBlockSpanFactory.java similarity index 61% rename from markwon-core/src/main/java/ru/noties/markwon/core/factory/CodeBlockSpanFactory.java rename to markwon-core/src/main/java/io/noties/markwon/core/factory/CodeBlockSpanFactory.java index 2bf9383e..352a0e1f 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/core/factory/CodeBlockSpanFactory.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/factory/CodeBlockSpanFactory.java @@ -1,12 +1,12 @@ -package ru.noties.markwon.core.factory; +package io.noties.markwon.core.factory; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import ru.noties.markwon.MarkwonConfiguration; -import ru.noties.markwon.RenderProps; -import ru.noties.markwon.SpanFactory; -import ru.noties.markwon.core.spans.CodeBlockSpan; +import io.noties.markwon.core.spans.CodeBlockSpan; +import io.noties.markwon.MarkwonConfiguration; +import io.noties.markwon.RenderProps; +import io.noties.markwon.SpanFactory; public class CodeBlockSpanFactory implements SpanFactory { @Nullable diff --git a/markwon-core/src/main/java/ru/noties/markwon/core/factory/CodeSpanFactory.java b/markwon-core/src/main/java/io/noties/markwon/core/factory/CodeSpanFactory.java similarity index 61% rename from markwon-core/src/main/java/ru/noties/markwon/core/factory/CodeSpanFactory.java rename to markwon-core/src/main/java/io/noties/markwon/core/factory/CodeSpanFactory.java index 944556fb..9c4f0aef 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/core/factory/CodeSpanFactory.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/factory/CodeSpanFactory.java @@ -1,12 +1,12 @@ -package ru.noties.markwon.core.factory; +package io.noties.markwon.core.factory; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import ru.noties.markwon.MarkwonConfiguration; -import ru.noties.markwon.RenderProps; -import ru.noties.markwon.SpanFactory; -import ru.noties.markwon.core.spans.CodeSpan; +import io.noties.markwon.core.spans.CodeSpan; +import io.noties.markwon.MarkwonConfiguration; +import io.noties.markwon.RenderProps; +import io.noties.markwon.SpanFactory; public class CodeSpanFactory implements SpanFactory { @Nullable diff --git a/markwon-core/src/main/java/ru/noties/markwon/core/factory/EmphasisSpanFactory.java b/markwon-core/src/main/java/io/noties/markwon/core/factory/EmphasisSpanFactory.java similarity index 60% rename from markwon-core/src/main/java/ru/noties/markwon/core/factory/EmphasisSpanFactory.java rename to markwon-core/src/main/java/io/noties/markwon/core/factory/EmphasisSpanFactory.java index d9d8331d..3942b8b1 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/core/factory/EmphasisSpanFactory.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/factory/EmphasisSpanFactory.java @@ -1,12 +1,12 @@ -package ru.noties.markwon.core.factory; +package io.noties.markwon.core.factory; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import ru.noties.markwon.MarkwonConfiguration; -import ru.noties.markwon.RenderProps; -import ru.noties.markwon.SpanFactory; -import ru.noties.markwon.core.spans.EmphasisSpan; +import io.noties.markwon.core.spans.EmphasisSpan; +import io.noties.markwon.MarkwonConfiguration; +import io.noties.markwon.RenderProps; +import io.noties.markwon.SpanFactory; public class EmphasisSpanFactory implements SpanFactory { @Nullable diff --git a/markwon-core/src/main/java/ru/noties/markwon/core/factory/HeadingSpanFactory.java b/markwon-core/src/main/java/io/noties/markwon/core/factory/HeadingSpanFactory.java similarity index 62% rename from markwon-core/src/main/java/ru/noties/markwon/core/factory/HeadingSpanFactory.java rename to markwon-core/src/main/java/io/noties/markwon/core/factory/HeadingSpanFactory.java index bd675edd..f96ab110 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/core/factory/HeadingSpanFactory.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/factory/HeadingSpanFactory.java @@ -1,13 +1,13 @@ -package ru.noties.markwon.core.factory; +package io.noties.markwon.core.factory; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import ru.noties.markwon.MarkwonConfiguration; -import ru.noties.markwon.RenderProps; -import ru.noties.markwon.SpanFactory; -import ru.noties.markwon.core.CoreProps; -import ru.noties.markwon.core.spans.HeadingSpan; +import io.noties.markwon.core.CoreProps; +import io.noties.markwon.core.spans.HeadingSpan; +import io.noties.markwon.MarkwonConfiguration; +import io.noties.markwon.RenderProps; +import io.noties.markwon.SpanFactory; public class HeadingSpanFactory implements SpanFactory { @Nullable diff --git a/markwon-core/src/main/java/ru/noties/markwon/core/factory/LinkSpanFactory.java b/markwon-core/src/main/java/io/noties/markwon/core/factory/LinkSpanFactory.java similarity index 65% rename from markwon-core/src/main/java/ru/noties/markwon/core/factory/LinkSpanFactory.java rename to markwon-core/src/main/java/io/noties/markwon/core/factory/LinkSpanFactory.java index ee97ba34..345e4e15 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/core/factory/LinkSpanFactory.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/factory/LinkSpanFactory.java @@ -1,13 +1,13 @@ -package ru.noties.markwon.core.factory; +package io.noties.markwon.core.factory; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import ru.noties.markwon.MarkwonConfiguration; -import ru.noties.markwon.RenderProps; -import ru.noties.markwon.SpanFactory; -import ru.noties.markwon.core.CoreProps; -import ru.noties.markwon.core.spans.LinkSpan; +import io.noties.markwon.core.CoreProps; +import io.noties.markwon.core.spans.LinkSpan; +import io.noties.markwon.MarkwonConfiguration; +import io.noties.markwon.RenderProps; +import io.noties.markwon.SpanFactory; public class LinkSpanFactory implements SpanFactory { @Nullable diff --git a/markwon-core/src/main/java/ru/noties/markwon/core/factory/ListItemSpanFactory.java b/markwon-core/src/main/java/io/noties/markwon/core/factory/ListItemSpanFactory.java similarity index 77% rename from markwon-core/src/main/java/ru/noties/markwon/core/factory/ListItemSpanFactory.java rename to markwon-core/src/main/java/io/noties/markwon/core/factory/ListItemSpanFactory.java index 06d73d2e..fd55e9a4 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/core/factory/ListItemSpanFactory.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/factory/ListItemSpanFactory.java @@ -1,14 +1,14 @@ -package ru.noties.markwon.core.factory; +package io.noties.markwon.core.factory; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import ru.noties.markwon.MarkwonConfiguration; -import ru.noties.markwon.RenderProps; -import ru.noties.markwon.SpanFactory; -import ru.noties.markwon.core.CoreProps; -import ru.noties.markwon.core.spans.BulletListItemSpan; -import ru.noties.markwon.core.spans.OrderedListItemSpan; +import io.noties.markwon.core.CoreProps; +import io.noties.markwon.core.spans.BulletListItemSpan; +import io.noties.markwon.core.spans.OrderedListItemSpan; +import io.noties.markwon.MarkwonConfiguration; +import io.noties.markwon.RenderProps; +import io.noties.markwon.SpanFactory; public class ListItemSpanFactory implements SpanFactory { diff --git a/markwon-core/src/main/java/ru/noties/markwon/core/factory/StrongEmphasisSpanFactory.java b/markwon-core/src/main/java/io/noties/markwon/core/factory/StrongEmphasisSpanFactory.java similarity index 60% rename from markwon-core/src/main/java/ru/noties/markwon/core/factory/StrongEmphasisSpanFactory.java rename to markwon-core/src/main/java/io/noties/markwon/core/factory/StrongEmphasisSpanFactory.java index c81d6121..029d3d25 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/core/factory/StrongEmphasisSpanFactory.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/factory/StrongEmphasisSpanFactory.java @@ -1,12 +1,12 @@ -package ru.noties.markwon.core.factory; +package io.noties.markwon.core.factory; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import ru.noties.markwon.MarkwonConfiguration; -import ru.noties.markwon.RenderProps; -import ru.noties.markwon.SpanFactory; -import ru.noties.markwon.core.spans.StrongEmphasisSpan; +import io.noties.markwon.core.spans.StrongEmphasisSpan; +import io.noties.markwon.MarkwonConfiguration; +import io.noties.markwon.RenderProps; +import io.noties.markwon.SpanFactory; public class StrongEmphasisSpanFactory implements SpanFactory { @Nullable diff --git a/markwon-core/src/main/java/ru/noties/markwon/core/factory/ThematicBreakSpanFactory.java b/markwon-core/src/main/java/io/noties/markwon/core/factory/ThematicBreakSpanFactory.java similarity index 61% rename from markwon-core/src/main/java/ru/noties/markwon/core/factory/ThematicBreakSpanFactory.java rename to markwon-core/src/main/java/io/noties/markwon/core/factory/ThematicBreakSpanFactory.java index ecd20f32..6f5659fc 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/core/factory/ThematicBreakSpanFactory.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/factory/ThematicBreakSpanFactory.java @@ -1,12 +1,12 @@ -package ru.noties.markwon.core.factory; +package io.noties.markwon.core.factory; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import ru.noties.markwon.MarkwonConfiguration; -import ru.noties.markwon.RenderProps; -import ru.noties.markwon.SpanFactory; -import ru.noties.markwon.core.spans.ThematicBreakSpan; +import io.noties.markwon.core.spans.ThematicBreakSpan; +import io.noties.markwon.MarkwonConfiguration; +import io.noties.markwon.RenderProps; +import io.noties.markwon.SpanFactory; public class ThematicBreakSpanFactory implements SpanFactory { @Nullable diff --git a/markwon-core/src/main/java/ru/noties/markwon/core/spans/BlockQuoteSpan.java b/markwon-core/src/main/java/io/noties/markwon/core/spans/BlockQuoteSpan.java similarity index 94% rename from markwon-core/src/main/java/ru/noties/markwon/core/spans/BlockQuoteSpan.java rename to markwon-core/src/main/java/io/noties/markwon/core/spans/BlockQuoteSpan.java index ea4e353c..0a7c7615 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/core/spans/BlockQuoteSpan.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/spans/BlockQuoteSpan.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.core.spans; +package io.noties.markwon.core.spans; import android.graphics.Canvas; import android.graphics.Paint; @@ -7,7 +7,7 @@ import android.support.annotation.NonNull; import android.text.Layout; import android.text.style.LeadingMarginSpan; -import ru.noties.markwon.core.MarkwonTheme; +import io.noties.markwon.core.MarkwonTheme; public class BlockQuoteSpan implements LeadingMarginSpan { diff --git a/markwon-core/src/main/java/ru/noties/markwon/core/spans/BulletListItemSpan.java b/markwon-core/src/main/java/io/noties/markwon/core/spans/BulletListItemSpan.java similarity index 96% rename from markwon-core/src/main/java/ru/noties/markwon/core/spans/BulletListItemSpan.java rename to markwon-core/src/main/java/io/noties/markwon/core/spans/BulletListItemSpan.java index 86a6c81b..59681b5a 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/core/spans/BulletListItemSpan.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/spans/BulletListItemSpan.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.core.spans; +package io.noties.markwon.core.spans; import android.graphics.Canvas; import android.graphics.Paint; @@ -9,8 +9,8 @@ import android.support.annotation.NonNull; import android.text.Layout; import android.text.style.LeadingMarginSpan; -import ru.noties.markwon.core.MarkwonTheme; -import ru.noties.markwon.utils.LeadingMarginUtils; +import io.noties.markwon.core.MarkwonTheme; +import io.noties.markwon.utils.LeadingMarginUtils; public class BulletListItemSpan implements LeadingMarginSpan { diff --git a/markwon-core/src/main/java/ru/noties/markwon/core/spans/CodeBlockSpan.java b/markwon-core/src/main/java/io/noties/markwon/core/spans/CodeBlockSpan.java similarity index 95% rename from markwon-core/src/main/java/ru/noties/markwon/core/spans/CodeBlockSpan.java rename to markwon-core/src/main/java/io/noties/markwon/core/spans/CodeBlockSpan.java index 00109766..24626f12 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/core/spans/CodeBlockSpan.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/spans/CodeBlockSpan.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.core.spans; +package io.noties.markwon.core.spans; import android.graphics.Canvas; import android.graphics.Paint; @@ -9,7 +9,7 @@ import android.text.TextPaint; import android.text.style.LeadingMarginSpan; import android.text.style.MetricAffectingSpan; -import ru.noties.markwon.core.MarkwonTheme; +import io.noties.markwon.core.MarkwonTheme; /** * @since 3.0.0 split inline and block spans diff --git a/markwon-core/src/main/java/ru/noties/markwon/core/spans/CodeSpan.java b/markwon-core/src/main/java/io/noties/markwon/core/spans/CodeSpan.java similarity index 89% rename from markwon-core/src/main/java/ru/noties/markwon/core/spans/CodeSpan.java rename to markwon-core/src/main/java/io/noties/markwon/core/spans/CodeSpan.java index 856d5807..8e2b1051 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/core/spans/CodeSpan.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/spans/CodeSpan.java @@ -1,10 +1,10 @@ -package ru.noties.markwon.core.spans; +package io.noties.markwon.core.spans; import android.support.annotation.NonNull; import android.text.TextPaint; import android.text.style.MetricAffectingSpan; -import ru.noties.markwon.core.MarkwonTheme; +import io.noties.markwon.core.MarkwonTheme; /** * @since 3.0.0 split inline and block spans diff --git a/markwon-core/src/main/java/ru/noties/markwon/core/spans/CustomTypefaceSpan.java b/markwon-core/src/main/java/io/noties/markwon/core/spans/CustomTypefaceSpan.java similarity index 96% rename from markwon-core/src/main/java/ru/noties/markwon/core/spans/CustomTypefaceSpan.java rename to markwon-core/src/main/java/io/noties/markwon/core/spans/CustomTypefaceSpan.java index 99ae2111..083c35f7 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/core/spans/CustomTypefaceSpan.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/spans/CustomTypefaceSpan.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.core.spans; +package io.noties.markwon.core.spans; import android.graphics.Typeface; import android.support.annotation.NonNull; diff --git a/markwon-core/src/main/java/ru/noties/markwon/core/spans/EmphasisSpan.java b/markwon-core/src/main/java/io/noties/markwon/core/spans/EmphasisSpan.java similarity index 90% rename from markwon-core/src/main/java/ru/noties/markwon/core/spans/EmphasisSpan.java rename to markwon-core/src/main/java/io/noties/markwon/core/spans/EmphasisSpan.java index cb7f9ac6..f0275228 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/core/spans/EmphasisSpan.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/spans/EmphasisSpan.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.core.spans; +package io.noties.markwon.core.spans; import android.text.TextPaint; import android.text.style.MetricAffectingSpan; diff --git a/markwon-core/src/main/java/ru/noties/markwon/core/spans/HeadingSpan.java b/markwon-core/src/main/java/io/noties/markwon/core/spans/HeadingSpan.java similarity index 94% rename from markwon-core/src/main/java/ru/noties/markwon/core/spans/HeadingSpan.java rename to markwon-core/src/main/java/io/noties/markwon/core/spans/HeadingSpan.java index a942cc64..9d4e8e72 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/core/spans/HeadingSpan.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/spans/HeadingSpan.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.core.spans; +package io.noties.markwon.core.spans; import android.graphics.Canvas; import android.graphics.Paint; @@ -10,8 +10,8 @@ import android.text.TextPaint; import android.text.style.LeadingMarginSpan; import android.text.style.MetricAffectingSpan; -import ru.noties.markwon.core.MarkwonTheme; -import ru.noties.markwon.utils.LeadingMarginUtils; +import io.noties.markwon.core.MarkwonTheme; +import io.noties.markwon.utils.LeadingMarginUtils; public class HeadingSpan extends MetricAffectingSpan implements LeadingMarginSpan { diff --git a/markwon-core/src/main/java/ru/noties/markwon/core/spans/LinkSpan.java b/markwon-core/src/main/java/io/noties/markwon/core/spans/LinkSpan.java similarity index 90% rename from markwon-core/src/main/java/ru/noties/markwon/core/spans/LinkSpan.java rename to markwon-core/src/main/java/io/noties/markwon/core/spans/LinkSpan.java index e8f7d8f7..32108b0c 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/core/spans/LinkSpan.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/spans/LinkSpan.java @@ -1,11 +1,11 @@ -package ru.noties.markwon.core.spans; +package io.noties.markwon.core.spans; import android.support.annotation.NonNull; import android.text.TextPaint; import android.text.style.URLSpan; import android.view.View; -import ru.noties.markwon.core.MarkwonTheme; +import io.noties.markwon.core.MarkwonTheme; public class LinkSpan extends URLSpan { diff --git a/markwon-core/src/main/java/ru/noties/markwon/core/spans/ObjectsPool.java b/markwon-core/src/main/java/io/noties/markwon/core/spans/ObjectsPool.java similarity index 95% rename from markwon-core/src/main/java/ru/noties/markwon/core/spans/ObjectsPool.java rename to markwon-core/src/main/java/io/noties/markwon/core/spans/ObjectsPool.java index de6f0671..aa1b0818 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/core/spans/ObjectsPool.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/spans/ObjectsPool.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.core.spans; +package io.noties.markwon.core.spans; import android.graphics.Paint; import android.graphics.Rect; diff --git a/markwon-core/src/main/java/ru/noties/markwon/core/spans/OrderedListItemSpan.java b/markwon-core/src/main/java/io/noties/markwon/core/spans/OrderedListItemSpan.java similarity index 96% rename from markwon-core/src/main/java/ru/noties/markwon/core/spans/OrderedListItemSpan.java rename to markwon-core/src/main/java/io/noties/markwon/core/spans/OrderedListItemSpan.java index 6be46fd5..0109c14c 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/core/spans/OrderedListItemSpan.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/spans/OrderedListItemSpan.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.core.spans; +package io.noties.markwon.core.spans; import android.graphics.Canvas; import android.graphics.Paint; @@ -9,8 +9,8 @@ import android.text.TextPaint; import android.text.style.LeadingMarginSpan; import android.widget.TextView; -import ru.noties.markwon.core.MarkwonTheme; -import ru.noties.markwon.utils.LeadingMarginUtils; +import io.noties.markwon.core.MarkwonTheme; +import io.noties.markwon.utils.LeadingMarginUtils; public class OrderedListItemSpan implements LeadingMarginSpan { diff --git a/markwon-core/src/main/java/ru/noties/markwon/core/spans/StrongEmphasisSpan.java b/markwon-core/src/main/java/io/noties/markwon/core/spans/StrongEmphasisSpan.java similarity index 90% rename from markwon-core/src/main/java/ru/noties/markwon/core/spans/StrongEmphasisSpan.java rename to markwon-core/src/main/java/io/noties/markwon/core/spans/StrongEmphasisSpan.java index d74ee63e..6b837fea 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/core/spans/StrongEmphasisSpan.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/spans/StrongEmphasisSpan.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.core.spans; +package io.noties.markwon.core.spans; import android.text.TextPaint; import android.text.style.MetricAffectingSpan; diff --git a/markwon-core/src/main/java/ru/noties/markwon/core/spans/ThematicBreakSpan.java b/markwon-core/src/main/java/io/noties/markwon/core/spans/ThematicBreakSpan.java similarity index 94% rename from markwon-core/src/main/java/ru/noties/markwon/core/spans/ThematicBreakSpan.java rename to markwon-core/src/main/java/io/noties/markwon/core/spans/ThematicBreakSpan.java index 0e06537b..aa3f4259 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/core/spans/ThematicBreakSpan.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/spans/ThematicBreakSpan.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.core.spans; +package io.noties.markwon.core.spans; import android.graphics.Canvas; import android.graphics.Paint; @@ -7,7 +7,7 @@ import android.support.annotation.NonNull; import android.text.Layout; import android.text.style.LeadingMarginSpan; -import ru.noties.markwon.core.MarkwonTheme; +import io.noties.markwon.core.MarkwonTheme; public class ThematicBreakSpan implements LeadingMarginSpan { diff --git a/markwon-core/src/main/java/ru/noties/markwon/html/HtmlTag.java b/markwon-core/src/main/java/io/noties/markwon/html/HtmlTag.java similarity index 98% rename from markwon-core/src/main/java/ru/noties/markwon/html/HtmlTag.java rename to markwon-core/src/main/java/io/noties/markwon/html/HtmlTag.java index fbe417e9..a44ccd82 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/html/HtmlTag.java +++ b/markwon-core/src/main/java/io/noties/markwon/html/HtmlTag.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.html; +package io.noties.markwon.html; import android.support.annotation.NonNull; import android.support.annotation.Nullable; diff --git a/markwon-core/src/main/java/ru/noties/markwon/html/MarkwonHtmlParser.java b/markwon-core/src/main/java/io/noties/markwon/html/MarkwonHtmlParser.java similarity index 98% rename from markwon-core/src/main/java/ru/noties/markwon/html/MarkwonHtmlParser.java rename to markwon-core/src/main/java/io/noties/markwon/html/MarkwonHtmlParser.java index 01bea86a..ec3b32c8 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/html/MarkwonHtmlParser.java +++ b/markwon-core/src/main/java/io/noties/markwon/html/MarkwonHtmlParser.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.html; +package io.noties.markwon.html; import android.support.annotation.NonNull; diff --git a/markwon-core/src/main/java/ru/noties/markwon/html/MarkwonHtmlParserNoOp.java b/markwon-core/src/main/java/io/noties/markwon/html/MarkwonHtmlParserNoOp.java similarity index 95% rename from markwon-core/src/main/java/ru/noties/markwon/html/MarkwonHtmlParserNoOp.java rename to markwon-core/src/main/java/io/noties/markwon/html/MarkwonHtmlParserNoOp.java index ecf6e423..9057630b 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/html/MarkwonHtmlParserNoOp.java +++ b/markwon-core/src/main/java/io/noties/markwon/html/MarkwonHtmlParserNoOp.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.html; +package io.noties.markwon.html; import android.support.annotation.NonNull; diff --git a/markwon-core/src/main/java/ru/noties/markwon/html/MarkwonHtmlRenderer.java b/markwon-core/src/main/java/io/noties/markwon/html/MarkwonHtmlRenderer.java similarity index 87% rename from markwon-core/src/main/java/ru/noties/markwon/html/MarkwonHtmlRenderer.java rename to markwon-core/src/main/java/io/noties/markwon/html/MarkwonHtmlRenderer.java index 88bf8709..26970f2a 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/html/MarkwonHtmlRenderer.java +++ b/markwon-core/src/main/java/io/noties/markwon/html/MarkwonHtmlRenderer.java @@ -1,9 +1,9 @@ -package ru.noties.markwon.html; +package io.noties.markwon.html; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import ru.noties.markwon.MarkwonVisitor; +import io.noties.markwon.MarkwonVisitor; /** * @since 2.0.0 diff --git a/markwon-core/src/main/java/ru/noties/markwon/html/MarkwonHtmlRendererNoOp.java b/markwon-core/src/main/java/io/noties/markwon/html/MarkwonHtmlRendererNoOp.java similarity index 84% rename from markwon-core/src/main/java/ru/noties/markwon/html/MarkwonHtmlRendererNoOp.java rename to markwon-core/src/main/java/io/noties/markwon/html/MarkwonHtmlRendererNoOp.java index 1a6ac51f..f8194ca3 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/html/MarkwonHtmlRendererNoOp.java +++ b/markwon-core/src/main/java/io/noties/markwon/html/MarkwonHtmlRendererNoOp.java @@ -1,9 +1,9 @@ -package ru.noties.markwon.html; +package io.noties.markwon.html; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import ru.noties.markwon.MarkwonVisitor; +import io.noties.markwon.MarkwonVisitor; class MarkwonHtmlRendererNoOp extends MarkwonHtmlRenderer { diff --git a/markwon-core/src/main/java/ru/noties/markwon/html/TagHandler.java b/markwon-core/src/main/java/io/noties/markwon/html/TagHandler.java similarity index 93% rename from markwon-core/src/main/java/ru/noties/markwon/html/TagHandler.java rename to markwon-core/src/main/java/io/noties/markwon/html/TagHandler.java index 28c2c068..60332b61 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/html/TagHandler.java +++ b/markwon-core/src/main/java/io/noties/markwon/html/TagHandler.java @@ -1,10 +1,10 @@ -package ru.noties.markwon.html; +package io.noties.markwon.html; import android.support.annotation.NonNull; import java.util.Collection; -import ru.noties.markwon.MarkwonVisitor; +import io.noties.markwon.MarkwonVisitor; public abstract class TagHandler { diff --git a/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawable.java b/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawable.java similarity index 99% rename from markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawable.java rename to markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawable.java index 10e4d45d..422f4923 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawable.java +++ b/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawable.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.image; +package io.noties.markwon.image; import android.graphics.Canvas; import android.graphics.ColorFilter; diff --git a/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableLoader.java b/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawableLoader.java similarity index 95% rename from markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableLoader.java rename to markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawableLoader.java index 314e537f..3a3a7d31 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableLoader.java +++ b/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawableLoader.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.image; +package io.noties.markwon.image; import android.graphics.drawable.Drawable; import android.support.annotation.NonNull; diff --git a/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderNoOp.java b/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderNoOp.java similarity index 93% rename from markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderNoOp.java rename to markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderNoOp.java index e3a6331a..c7d06d7b 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderNoOp.java +++ b/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderNoOp.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.image; +package io.noties.markwon.image; import android.graphics.drawable.Drawable; import android.support.annotation.NonNull; diff --git a/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableScheduler.java b/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawableScheduler.java similarity index 98% rename from markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableScheduler.java rename to markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawableScheduler.java index 83a4b150..251f9937 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableScheduler.java +++ b/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawableScheduler.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.image; +package io.noties.markwon.image; import android.graphics.Rect; import android.graphics.drawable.Drawable; @@ -10,7 +10,7 @@ import android.text.Spanned; import android.view.View; import android.widget.TextView; -import ru.noties.markwon.renderer.R; +import io.noties.markwon.R; public abstract class AsyncDrawableScheduler { diff --git a/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableSpan.java b/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawableSpan.java similarity index 98% rename from markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableSpan.java rename to markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawableSpan.java index a268ef19..d7b7aaf7 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/image/AsyncDrawableSpan.java +++ b/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawableSpan.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.image; +package io.noties.markwon.image; import android.graphics.Canvas; import android.graphics.Paint; @@ -12,7 +12,7 @@ import android.text.style.ReplacementSpan; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import ru.noties.markwon.core.MarkwonTheme; +import io.noties.markwon.core.MarkwonTheme; @SuppressWarnings("WeakerAccess") public class AsyncDrawableSpan extends ReplacementSpan { diff --git a/markwon-core/src/main/java/ru/noties/markwon/image/DrawableUtils.java b/markwon-core/src/main/java/io/noties/markwon/image/DrawableUtils.java similarity index 96% rename from markwon-core/src/main/java/ru/noties/markwon/image/DrawableUtils.java rename to markwon-core/src/main/java/io/noties/markwon/image/DrawableUtils.java index a5134d52..2cecf8c0 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/image/DrawableUtils.java +++ b/markwon-core/src/main/java/io/noties/markwon/image/DrawableUtils.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.image; +package io.noties.markwon.image; import android.graphics.Rect; import android.graphics.drawable.Drawable; diff --git a/markwon-core/src/main/java/ru/noties/markwon/image/ImageProps.java b/markwon-core/src/main/java/io/noties/markwon/image/ImageProps.java similarity index 85% rename from markwon-core/src/main/java/ru/noties/markwon/image/ImageProps.java rename to markwon-core/src/main/java/io/noties/markwon/image/ImageProps.java index 7bb9bfd1..2c1343c3 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/image/ImageProps.java +++ b/markwon-core/src/main/java/io/noties/markwon/image/ImageProps.java @@ -1,6 +1,6 @@ -package ru.noties.markwon.image; +package io.noties.markwon.image; -import ru.noties.markwon.Prop; +import io.noties.markwon.Prop; /** * @since 3.0.0 diff --git a/markwon-core/src/main/java/ru/noties/markwon/image/ImageSize.java b/markwon-core/src/main/java/io/noties/markwon/image/ImageSize.java similarity index 96% rename from markwon-core/src/main/java/ru/noties/markwon/image/ImageSize.java rename to markwon-core/src/main/java/io/noties/markwon/image/ImageSize.java index ec44ed76..f06ec6d3 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/image/ImageSize.java +++ b/markwon-core/src/main/java/io/noties/markwon/image/ImageSize.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.image; +package io.noties.markwon.image; import android.support.annotation.Nullable; diff --git a/markwon-core/src/main/java/ru/noties/markwon/image/ImageSizeResolver.java b/markwon-core/src/main/java/io/noties/markwon/image/ImageSizeResolver.java similarity index 95% rename from markwon-core/src/main/java/ru/noties/markwon/image/ImageSizeResolver.java rename to markwon-core/src/main/java/io/noties/markwon/image/ImageSizeResolver.java index 57284a41..85b5f44b 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/image/ImageSizeResolver.java +++ b/markwon-core/src/main/java/io/noties/markwon/image/ImageSizeResolver.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.image; +package io.noties.markwon.image; import android.graphics.Rect; import android.support.annotation.NonNull; diff --git a/markwon-core/src/main/java/ru/noties/markwon/image/ImageSizeResolverDef.java b/markwon-core/src/main/java/io/noties/markwon/image/ImageSizeResolverDef.java similarity index 98% rename from markwon-core/src/main/java/ru/noties/markwon/image/ImageSizeResolverDef.java rename to markwon-core/src/main/java/io/noties/markwon/image/ImageSizeResolverDef.java index bdf7ae48..9788b7fe 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/image/ImageSizeResolverDef.java +++ b/markwon-core/src/main/java/io/noties/markwon/image/ImageSizeResolverDef.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.image; +package io.noties.markwon.image; import android.graphics.Rect; import android.support.annotation.NonNull; diff --git a/markwon-core/src/main/java/ru/noties/markwon/image/ImageSpanFactory.java b/markwon-core/src/main/java/io/noties/markwon/image/ImageSpanFactory.java similarity index 83% rename from markwon-core/src/main/java/ru/noties/markwon/image/ImageSpanFactory.java rename to markwon-core/src/main/java/io/noties/markwon/image/ImageSpanFactory.java index 5af5b0ec..df2dce06 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/image/ImageSpanFactory.java +++ b/markwon-core/src/main/java/io/noties/markwon/image/ImageSpanFactory.java @@ -1,11 +1,11 @@ -package ru.noties.markwon.image; +package io.noties.markwon.image; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import ru.noties.markwon.MarkwonConfiguration; -import ru.noties.markwon.RenderProps; -import ru.noties.markwon.SpanFactory; +import io.noties.markwon.MarkwonConfiguration; +import io.noties.markwon.RenderProps; +import io.noties.markwon.SpanFactory; public class ImageSpanFactory implements SpanFactory { @Nullable diff --git a/markwon-core/src/main/java/ru/noties/markwon/movement/MovementMethodPlugin.java b/markwon-core/src/main/java/io/noties/markwon/movement/MovementMethodPlugin.java similarity index 93% rename from markwon-core/src/main/java/ru/noties/markwon/movement/MovementMethodPlugin.java rename to markwon-core/src/main/java/io/noties/markwon/movement/MovementMethodPlugin.java index 59dd04ab..fd672783 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/movement/MovementMethodPlugin.java +++ b/markwon-core/src/main/java/io/noties/markwon/movement/MovementMethodPlugin.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.movement; +package io.noties.markwon.movement; import android.support.annotation.NonNull; import android.text.Spanned; @@ -6,7 +6,7 @@ import android.text.method.LinkMovementMethod; import android.text.method.MovementMethod; import android.widget.TextView; -import ru.noties.markwon.AbstractMarkwonPlugin; +import io.noties.markwon.AbstractMarkwonPlugin; /** * @since 3.0.0 diff --git a/markwon-core/src/main/java/ru/noties/markwon/syntax/SyntaxHighlight.java b/markwon-core/src/main/java/io/noties/markwon/syntax/SyntaxHighlight.java similarity index 87% rename from markwon-core/src/main/java/ru/noties/markwon/syntax/SyntaxHighlight.java rename to markwon-core/src/main/java/io/noties/markwon/syntax/SyntaxHighlight.java index cf6921ee..925fd1df 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/syntax/SyntaxHighlight.java +++ b/markwon-core/src/main/java/io/noties/markwon/syntax/SyntaxHighlight.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.syntax; +package io.noties.markwon.syntax; import android.support.annotation.NonNull; import android.support.annotation.Nullable; diff --git a/markwon-core/src/main/java/ru/noties/markwon/syntax/SyntaxHighlightNoOp.java b/markwon-core/src/main/java/io/noties/markwon/syntax/SyntaxHighlightNoOp.java similarity index 89% rename from markwon-core/src/main/java/ru/noties/markwon/syntax/SyntaxHighlightNoOp.java rename to markwon-core/src/main/java/io/noties/markwon/syntax/SyntaxHighlightNoOp.java index 48a80ee2..e3931244 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/syntax/SyntaxHighlightNoOp.java +++ b/markwon-core/src/main/java/io/noties/markwon/syntax/SyntaxHighlightNoOp.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.syntax; +package io.noties.markwon.syntax; import android.support.annotation.NonNull; import android.support.annotation.Nullable; diff --git a/markwon-core/src/main/java/ru/noties/markwon/urlprocessor/UrlProcessor.java b/markwon-core/src/main/java/io/noties/markwon/urlprocessor/UrlProcessor.java similarity index 77% rename from markwon-core/src/main/java/ru/noties/markwon/urlprocessor/UrlProcessor.java rename to markwon-core/src/main/java/io/noties/markwon/urlprocessor/UrlProcessor.java index 9ea7919e..03f1995d 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/urlprocessor/UrlProcessor.java +++ b/markwon-core/src/main/java/io/noties/markwon/urlprocessor/UrlProcessor.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.urlprocessor; +package io.noties.markwon.urlprocessor; import android.support.annotation.NonNull; diff --git a/markwon-core/src/main/java/ru/noties/markwon/urlprocessor/UrlProcessorAndroidAssets.java b/markwon-core/src/main/java/io/noties/markwon/urlprocessor/UrlProcessorAndroidAssets.java similarity index 97% rename from markwon-core/src/main/java/ru/noties/markwon/urlprocessor/UrlProcessorAndroidAssets.java rename to markwon-core/src/main/java/io/noties/markwon/urlprocessor/UrlProcessorAndroidAssets.java index 439d7f12..714f9553 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/urlprocessor/UrlProcessorAndroidAssets.java +++ b/markwon-core/src/main/java/io/noties/markwon/urlprocessor/UrlProcessorAndroidAssets.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.urlprocessor; +package io.noties.markwon.urlprocessor; import android.net.Uri; import android.support.annotation.NonNull; diff --git a/markwon-core/src/main/java/ru/noties/markwon/urlprocessor/UrlProcessorNoOp.java b/markwon-core/src/main/java/io/noties/markwon/urlprocessor/UrlProcessorNoOp.java similarity index 84% rename from markwon-core/src/main/java/ru/noties/markwon/urlprocessor/UrlProcessorNoOp.java rename to markwon-core/src/main/java/io/noties/markwon/urlprocessor/UrlProcessorNoOp.java index 9d8560d6..ba795b5e 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/urlprocessor/UrlProcessorNoOp.java +++ b/markwon-core/src/main/java/io/noties/markwon/urlprocessor/UrlProcessorNoOp.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.urlprocessor; +package io.noties.markwon.urlprocessor; import android.support.annotation.NonNull; diff --git a/markwon-core/src/main/java/ru/noties/markwon/urlprocessor/UrlProcessorRelativeToAbsolute.java b/markwon-core/src/main/java/io/noties/markwon/urlprocessor/UrlProcessorRelativeToAbsolute.java similarity index 96% rename from markwon-core/src/main/java/ru/noties/markwon/urlprocessor/UrlProcessorRelativeToAbsolute.java rename to markwon-core/src/main/java/io/noties/markwon/urlprocessor/UrlProcessorRelativeToAbsolute.java index d99aaf4f..e67ab48c 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/urlprocessor/UrlProcessorRelativeToAbsolute.java +++ b/markwon-core/src/main/java/io/noties/markwon/urlprocessor/UrlProcessorRelativeToAbsolute.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.urlprocessor; +package io.noties.markwon.urlprocessor; import android.support.annotation.NonNull; import android.support.annotation.Nullable; diff --git a/markwon-core/src/main/java/ru/noties/markwon/utils/ColorUtils.java b/markwon-core/src/main/java/io/noties/markwon/utils/ColorUtils.java similarity index 85% rename from markwon-core/src/main/java/ru/noties/markwon/utils/ColorUtils.java rename to markwon-core/src/main/java/io/noties/markwon/utils/ColorUtils.java index d6305132..d2a8bc6e 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/utils/ColorUtils.java +++ b/markwon-core/src/main/java/io/noties/markwon/utils/ColorUtils.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.utils; +package io.noties.markwon.utils; public abstract class ColorUtils { diff --git a/markwon-core/src/main/java/ru/noties/markwon/utils/Dip.java b/markwon-core/src/main/java/io/noties/markwon/utils/Dip.java similarity index 94% rename from markwon-core/src/main/java/ru/noties/markwon/utils/Dip.java rename to markwon-core/src/main/java/io/noties/markwon/utils/Dip.java index 51d098e0..6b8fdba2 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/utils/Dip.java +++ b/markwon-core/src/main/java/io/noties/markwon/utils/Dip.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.utils; +package io.noties.markwon.utils; import android.content.Context; import android.support.annotation.NonNull; diff --git a/markwon-core/src/main/java/ru/noties/markwon/utils/DrawableUtils.java b/markwon-core/src/main/java/io/noties/markwon/utils/DrawableUtils.java similarity index 78% rename from markwon-core/src/main/java/ru/noties/markwon/utils/DrawableUtils.java rename to markwon-core/src/main/java/io/noties/markwon/utils/DrawableUtils.java index 0f719339..5201a828 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/utils/DrawableUtils.java +++ b/markwon-core/src/main/java/io/noties/markwon/utils/DrawableUtils.java @@ -1,10 +1,10 @@ -package ru.noties.markwon.utils; +package io.noties.markwon.utils; import android.graphics.drawable.Drawable; import android.support.annotation.NonNull; /** - * @deprecated Please use {@link ru.noties.markwon.image.DrawableUtils} + * @deprecated Please use {@link io.noties.markwon.image.DrawableUtils} */ @Deprecated public abstract class DrawableUtils { diff --git a/markwon-core/src/main/java/ru/noties/markwon/utils/DumpNodes.java b/markwon-core/src/main/java/io/noties/markwon/utils/DumpNodes.java similarity index 99% rename from markwon-core/src/main/java/ru/noties/markwon/utils/DumpNodes.java rename to markwon-core/src/main/java/io/noties/markwon/utils/DumpNodes.java index 3b45d238..0693da72 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/utils/DumpNodes.java +++ b/markwon-core/src/main/java/io/noties/markwon/utils/DumpNodes.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.utils; +package io.noties.markwon.utils; import android.support.annotation.NonNull; import android.support.annotation.Nullable; diff --git a/markwon-core/src/main/java/ru/noties/markwon/utils/LeadingMarginUtils.java b/markwon-core/src/main/java/io/noties/markwon/utils/LeadingMarginUtils.java similarity index 94% rename from markwon-core/src/main/java/ru/noties/markwon/utils/LeadingMarginUtils.java rename to markwon-core/src/main/java/io/noties/markwon/utils/LeadingMarginUtils.java index bc18a140..072d2ccf 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/utils/LeadingMarginUtils.java +++ b/markwon-core/src/main/java/io/noties/markwon/utils/LeadingMarginUtils.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.utils; +package io.noties.markwon.utils; import android.text.Spanned; diff --git a/markwon-core/src/main/java/ru/noties/markwon/utils/NoCopySpannableFactory.java b/markwon-core/src/main/java/io/noties/markwon/utils/NoCopySpannableFactory.java similarity index 95% rename from markwon-core/src/main/java/ru/noties/markwon/utils/NoCopySpannableFactory.java rename to markwon-core/src/main/java/io/noties/markwon/utils/NoCopySpannableFactory.java index f5eedc2a..7609630e 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/utils/NoCopySpannableFactory.java +++ b/markwon-core/src/main/java/io/noties/markwon/utils/NoCopySpannableFactory.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.utils; +package io.noties.markwon.utils; import android.support.annotation.NonNull; import android.text.Spannable; diff --git a/markwon-core/src/test/java/ru/noties/markwon/AbstractMarkwonPluginTest.java b/markwon-core/src/test/java/io/noties/markwon/AbstractMarkwonPluginTest.java similarity index 95% rename from markwon-core/src/test/java/ru/noties/markwon/AbstractMarkwonPluginTest.java rename to markwon-core/src/test/java/io/noties/markwon/AbstractMarkwonPluginTest.java index 025af005..3587fdca 100644 --- a/markwon-core/src/test/java/ru/noties/markwon/AbstractMarkwonPluginTest.java +++ b/markwon-core/src/test/java/io/noties/markwon/AbstractMarkwonPluginTest.java @@ -1,4 +1,4 @@ -package ru.noties.markwon; +package io.noties.markwon; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/markwon-core/src/test/java/ru/noties/markwon/AbstractMarkwonVisitorImpl.java b/markwon-core/src/test/java/io/noties/markwon/AbstractMarkwonVisitorImpl.java similarity index 95% rename from markwon-core/src/test/java/ru/noties/markwon/AbstractMarkwonVisitorImpl.java rename to markwon-core/src/test/java/io/noties/markwon/AbstractMarkwonVisitorImpl.java index ea099248..04298a06 100644 --- a/markwon-core/src/test/java/ru/noties/markwon/AbstractMarkwonVisitorImpl.java +++ b/markwon-core/src/test/java/io/noties/markwon/AbstractMarkwonVisitorImpl.java @@ -1,4 +1,4 @@ -package ru.noties.markwon; +package io.noties.markwon; import android.support.annotation.NonNull; diff --git a/markwon-core/src/test/java/ru/noties/markwon/MarkwonBuilderImplTest.java b/markwon-core/src/test/java/io/noties/markwon/MarkwonBuilderImplTest.java similarity index 96% rename from markwon-core/src/test/java/ru/noties/markwon/MarkwonBuilderImplTest.java rename to markwon-core/src/test/java/io/noties/markwon/MarkwonBuilderImplTest.java index fc4c73fc..56b1ee60 100644 --- a/markwon-core/src/test/java/ru/noties/markwon/MarkwonBuilderImplTest.java +++ b/markwon-core/src/test/java/io/noties/markwon/MarkwonBuilderImplTest.java @@ -1,4 +1,4 @@ -package ru.noties.markwon; +package io.noties.markwon; import android.text.Spanned; import android.widget.TextView; @@ -11,8 +11,8 @@ import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; -import ru.noties.markwon.core.MarkwonTheme; -import ru.noties.markwon.html.MarkwonHtmlRenderer; +import io.noties.markwon.core.MarkwonTheme; +import io.noties.markwon.html.MarkwonHtmlRenderer; import static org.hamcrest.Matchers.containsString; import static org.junit.Assert.assertThat; diff --git a/markwon-core/src/test/java/ru/noties/markwon/MarkwonImplTest.java b/markwon-core/src/test/java/io/noties/markwon/MarkwonImplTest.java similarity index 99% rename from markwon-core/src/test/java/ru/noties/markwon/MarkwonImplTest.java rename to markwon-core/src/test/java/io/noties/markwon/MarkwonImplTest.java index d80cb765..60f022ef 100644 --- a/markwon-core/src/test/java/ru/noties/markwon/MarkwonImplTest.java +++ b/markwon-core/src/test/java/io/noties/markwon/MarkwonImplTest.java @@ -1,4 +1,4 @@ -package ru.noties.markwon; +package io.noties.markwon; import android.text.Spanned; import android.widget.TextView; diff --git a/markwon-core/src/test/java/ru/noties/markwon/MarkwonSpansFactoryImplTest.java b/markwon-core/src/test/java/io/noties/markwon/MarkwonSpansFactoryImplTest.java similarity index 99% rename from markwon-core/src/test/java/ru/noties/markwon/MarkwonSpansFactoryImplTest.java rename to markwon-core/src/test/java/io/noties/markwon/MarkwonSpansFactoryImplTest.java index b66cfd0c..ad43e6e6 100644 --- a/markwon-core/src/test/java/ru/noties/markwon/MarkwonSpansFactoryImplTest.java +++ b/markwon-core/src/test/java/io/noties/markwon/MarkwonSpansFactoryImplTest.java @@ -1,4 +1,4 @@ -package ru.noties.markwon; +package io.noties.markwon; import org.commonmark.node.Block; import org.commonmark.node.Emphasis; diff --git a/markwon-core/src/test/java/ru/noties/markwon/MarkwonSpansFactoryTest.java b/markwon-core/src/test/java/io/noties/markwon/MarkwonSpansFactoryTest.java similarity index 98% rename from markwon-core/src/test/java/ru/noties/markwon/MarkwonSpansFactoryTest.java rename to markwon-core/src/test/java/io/noties/markwon/MarkwonSpansFactoryTest.java index a2cb36ff..cdb631e7 100644 --- a/markwon-core/src/test/java/ru/noties/markwon/MarkwonSpansFactoryTest.java +++ b/markwon-core/src/test/java/io/noties/markwon/MarkwonSpansFactoryTest.java @@ -1,4 +1,4 @@ -package ru.noties.markwon; +package io.noties.markwon; import org.commonmark.node.BlockQuote; import org.commonmark.node.Image; diff --git a/markwon-core/src/test/java/ru/noties/markwon/MarkwonVisitorImplTest.java b/markwon-core/src/test/java/io/noties/markwon/MarkwonVisitorImplTest.java similarity index 99% rename from markwon-core/src/test/java/ru/noties/markwon/MarkwonVisitorImplTest.java rename to markwon-core/src/test/java/io/noties/markwon/MarkwonVisitorImplTest.java index 1a444d70..45387afb 100644 --- a/markwon-core/src/test/java/ru/noties/markwon/MarkwonVisitorImplTest.java +++ b/markwon-core/src/test/java/io/noties/markwon/MarkwonVisitorImplTest.java @@ -1,4 +1,4 @@ -package ru.noties.markwon; +package io.noties.markwon; import org.commonmark.node.BlockQuote; import org.commonmark.node.Node; diff --git a/markwon-core/src/test/java/ru/noties/markwon/PropTest.java b/markwon-core/src/test/java/io/noties/markwon/PropTest.java similarity index 98% rename from markwon-core/src/test/java/ru/noties/markwon/PropTest.java rename to markwon-core/src/test/java/io/noties/markwon/PropTest.java index 85a81fe1..3b90b7fb 100644 --- a/markwon-core/src/test/java/ru/noties/markwon/PropTest.java +++ b/markwon-core/src/test/java/io/noties/markwon/PropTest.java @@ -1,4 +1,4 @@ -package ru.noties.markwon; +package io.noties.markwon; import org.junit.Before; import org.junit.Test; diff --git a/markwon-core/src/test/java/ru/noties/markwon/RenderPropsImplTest.java b/markwon-core/src/test/java/io/noties/markwon/RenderPropsImplTest.java similarity index 99% rename from markwon-core/src/test/java/ru/noties/markwon/RenderPropsImplTest.java rename to markwon-core/src/test/java/io/noties/markwon/RenderPropsImplTest.java index 36a6315b..3f185bcf 100644 --- a/markwon-core/src/test/java/ru/noties/markwon/RenderPropsImplTest.java +++ b/markwon-core/src/test/java/io/noties/markwon/RenderPropsImplTest.java @@ -1,4 +1,4 @@ -package ru.noties.markwon; +package io.noties.markwon; import org.junit.Before; import org.junit.Test; diff --git a/markwon-core/src/test/java/ru/noties/markwon/SpannableBuilderTest.java b/markwon-core/src/test/java/io/noties/markwon/SpannableBuilderTest.java similarity index 98% rename from markwon-core/src/test/java/ru/noties/markwon/SpannableBuilderTest.java rename to markwon-core/src/test/java/io/noties/markwon/SpannableBuilderTest.java index 3535e19b..3e68fe38 100644 --- a/markwon-core/src/test/java/ru/noties/markwon/SpannableBuilderTest.java +++ b/markwon-core/src/test/java/io/noties/markwon/SpannableBuilderTest.java @@ -1,4 +1,4 @@ -package ru.noties.markwon; +package io.noties.markwon; import android.support.annotation.NonNull; import android.text.SpannableStringBuilder; @@ -19,8 +19,8 @@ import ix.IxFunction; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import static ru.noties.markwon.SpannableBuilder.isPositionValid; -import static ru.noties.markwon.SpannableBuilder.setSpans; +import static io.noties.markwon.SpannableBuilder.isPositionValid; +import static io.noties.markwon.SpannableBuilder.setSpans; @RunWith(RobolectricTestRunner.class) @Config(manifest = Config.NONE) diff --git a/markwon-core/src/test/java/ru/noties/markwon/core/CorePluginBridge.java b/markwon-core/src/test/java/io/noties/markwon/core/CorePluginBridge.java similarity index 86% rename from markwon-core/src/test/java/ru/noties/markwon/core/CorePluginBridge.java rename to markwon-core/src/test/java/io/noties/markwon/core/CorePluginBridge.java index 6517873b..01520e54 100644 --- a/markwon-core/src/test/java/ru/noties/markwon/core/CorePluginBridge.java +++ b/markwon-core/src/test/java/io/noties/markwon/core/CorePluginBridge.java @@ -1,11 +1,11 @@ -package ru.noties.markwon.core; +package io.noties.markwon.core; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import org.commonmark.node.Node; -import ru.noties.markwon.MarkwonVisitor; +import io.noties.markwon.MarkwonVisitor; public abstract class CorePluginBridge { diff --git a/markwon-core/src/test/java/ru/noties/markwon/core/CorePluginTest.java b/markwon-core/src/test/java/io/noties/markwon/core/CorePluginTest.java similarity index 97% rename from markwon-core/src/test/java/ru/noties/markwon/core/CorePluginTest.java rename to markwon-core/src/test/java/io/noties/markwon/core/CorePluginTest.java index 3a300cfb..3d9834dc 100644 --- a/markwon-core/src/test/java/ru/noties/markwon/core/CorePluginTest.java +++ b/markwon-core/src/test/java/io/noties/markwon/core/CorePluginTest.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.core; +package io.noties.markwon.core; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -39,12 +39,12 @@ import java.util.Set; import ix.Ix; import ix.IxFunction; import ix.IxPredicate; -import ru.noties.markwon.MarkwonConfiguration; -import ru.noties.markwon.MarkwonSpansFactory; -import ru.noties.markwon.MarkwonVisitor; -import ru.noties.markwon.RenderProps; -import ru.noties.markwon.SpanFactory; -import ru.noties.markwon.SpannableBuilder; +import io.noties.markwon.MarkwonConfiguration; +import io.noties.markwon.MarkwonSpansFactory; +import io.noties.markwon.MarkwonVisitor; +import io.noties.markwon.RenderProps; +import io.noties.markwon.SpanFactory; +import io.noties.markwon.SpannableBuilder; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; diff --git a/markwon-core/src/test/java/ru/noties/markwon/core/CoreTest.java b/markwon-core/src/test/java/io/noties/markwon/core/CoreTest.java similarity index 78% rename from markwon-core/src/test/java/ru/noties/markwon/core/CoreTest.java rename to markwon-core/src/test/java/io/noties/markwon/core/CoreTest.java index de7c0dd0..1d5b4830 100644 --- a/markwon-core/src/test/java/ru/noties/markwon/core/CoreTest.java +++ b/markwon-core/src/test/java/io/noties/markwon/core/CoreTest.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.core; +package io.noties.markwon.core; import android.support.annotation.NonNull; import android.text.Spanned; @@ -11,18 +11,18 @@ import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; -import ru.noties.markwon.AbstractMarkwonPlugin; -import ru.noties.markwon.Markwon; -import ru.noties.markwon.MarkwonConfiguration; -import ru.noties.markwon.MarkwonSpansFactory; -import ru.noties.markwon.RenderProps; -import ru.noties.markwon.SpanFactory; -import ru.noties.markwon.test.TestSpan; -import ru.noties.markwon.test.TestSpanMatcher; +import io.noties.markwon.AbstractMarkwonPlugin; +import io.noties.markwon.Markwon; +import io.noties.markwon.MarkwonConfiguration; +import io.noties.markwon.MarkwonSpansFactory; +import io.noties.markwon.RenderProps; +import io.noties.markwon.SpanFactory; +import io.noties.markwon.test.TestSpan; +import io.noties.markwon.test.TestSpanMatcher; -import static ru.noties.markwon.test.TestSpan.document; -import static ru.noties.markwon.test.TestSpan.span; -import static ru.noties.markwon.test.TestSpan.text; +import static io.noties.markwon.test.TestSpan.document; +import static io.noties.markwon.test.TestSpan.span; +import static io.noties.markwon.test.TestSpan.text; @RunWith(RobolectricTestRunner.class) @Config(manifest = Config.NONE) diff --git a/markwon-core/src/test/java/ru/noties/markwon/core/suite/.editorconfig b/markwon-core/src/test/java/io/noties/markwon/core/suite/.editorconfig similarity index 100% rename from markwon-core/src/test/java/ru/noties/markwon/core/suite/.editorconfig rename to markwon-core/src/test/java/io/noties/markwon/core/suite/.editorconfig diff --git a/markwon-core/src/test/java/ru/noties/markwon/core/suite/BaseSuiteTest.java b/markwon-core/src/test/java/io/noties/markwon/core/suite/BaseSuiteTest.java similarity index 90% rename from markwon-core/src/test/java/ru/noties/markwon/core/suite/BaseSuiteTest.java rename to markwon-core/src/test/java/io/noties/markwon/core/suite/BaseSuiteTest.java index d434ed99..7ecab39d 100644 --- a/markwon-core/src/test/java/ru/noties/markwon/core/suite/BaseSuiteTest.java +++ b/markwon-core/src/test/java/io/noties/markwon/core/suite/BaseSuiteTest.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.core.suite; +package io.noties.markwon.core.suite; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -24,19 +24,19 @@ import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; -import ru.noties.markwon.AbstractMarkwonPlugin; -import ru.noties.markwon.Markwon; -import ru.noties.markwon.MarkwonConfiguration; -import ru.noties.markwon.MarkwonSpansFactory; -import ru.noties.markwon.RenderProps; -import ru.noties.markwon.SpanFactory; -import ru.noties.markwon.core.CorePlugin; -import ru.noties.markwon.core.CoreProps; -import ru.noties.markwon.test.TestSpan; -import ru.noties.markwon.test.TestSpanMatcher; +import io.noties.markwon.core.CorePlugin; +import io.noties.markwon.core.CoreProps; +import io.noties.markwon.AbstractMarkwonPlugin; +import io.noties.markwon.Markwon; +import io.noties.markwon.MarkwonConfiguration; +import io.noties.markwon.MarkwonSpansFactory; +import io.noties.markwon.RenderProps; +import io.noties.markwon.SpanFactory; +import io.noties.markwon.test.TestSpan; +import io.noties.markwon.test.TestSpanMatcher; -import static ru.noties.markwon.test.TestSpan.args; -import static ru.noties.markwon.test.TestSpan.span; +import static io.noties.markwon.test.TestSpan.args; +import static io.noties.markwon.test.TestSpan.span; abstract class BaseSuiteTest { diff --git a/markwon-core/src/test/java/ru/noties/markwon/core/suite/BlockquoteTest.java b/markwon-core/src/test/java/io/noties/markwon/core/suite/BlockquoteTest.java similarity index 76% rename from markwon-core/src/test/java/ru/noties/markwon/core/suite/BlockquoteTest.java rename to markwon-core/src/test/java/io/noties/markwon/core/suite/BlockquoteTest.java index 21d2c852..11d4aa1f 100644 --- a/markwon-core/src/test/java/ru/noties/markwon/core/suite/BlockquoteTest.java +++ b/markwon-core/src/test/java/io/noties/markwon/core/suite/BlockquoteTest.java @@ -1,15 +1,15 @@ -package ru.noties.markwon.core.suite; +package io.noties.markwon.core.suite; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -import ru.noties.markwon.test.TestSpan.Document; +import io.noties.markwon.test.TestSpan.Document; -import static ru.noties.markwon.test.TestSpan.document; -import static ru.noties.markwon.test.TestSpan.span; -import static ru.noties.markwon.test.TestSpan.text; +import static io.noties.markwon.test.TestSpan.document; +import static io.noties.markwon.test.TestSpan.span; +import static io.noties.markwon.test.TestSpan.text; @RunWith(RobolectricTestRunner.class) @Config(manifest = Config.NONE) diff --git a/markwon-core/src/test/java/ru/noties/markwon/core/suite/BoldItalicTest.java b/markwon-core/src/test/java/io/noties/markwon/core/suite/BoldItalicTest.java similarity index 66% rename from markwon-core/src/test/java/ru/noties/markwon/core/suite/BoldItalicTest.java rename to markwon-core/src/test/java/io/noties/markwon/core/suite/BoldItalicTest.java index 1315136b..ceece2f5 100644 --- a/markwon-core/src/test/java/ru/noties/markwon/core/suite/BoldItalicTest.java +++ b/markwon-core/src/test/java/io/noties/markwon/core/suite/BoldItalicTest.java @@ -1,15 +1,15 @@ -package ru.noties.markwon.core.suite; +package io.noties.markwon.core.suite; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -import ru.noties.markwon.test.TestSpan; +import io.noties.markwon.test.TestSpan; -import static ru.noties.markwon.test.TestSpan.document; -import static ru.noties.markwon.test.TestSpan.span; -import static ru.noties.markwon.test.TestSpan.text; +import static io.noties.markwon.test.TestSpan.document; +import static io.noties.markwon.test.TestSpan.span; +import static io.noties.markwon.test.TestSpan.text; @RunWith(RobolectricTestRunner.class) @Config(manifest = Config.NONE) diff --git a/markwon-core/src/test/java/ru/noties/markwon/core/suite/CodeTest.java b/markwon-core/src/test/java/io/noties/markwon/core/suite/CodeTest.java similarity index 80% rename from markwon-core/src/test/java/ru/noties/markwon/core/suite/CodeTest.java rename to markwon-core/src/test/java/io/noties/markwon/core/suite/CodeTest.java index 52a8f614..3fc22a3d 100644 --- a/markwon-core/src/test/java/ru/noties/markwon/core/suite/CodeTest.java +++ b/markwon-core/src/test/java/io/noties/markwon/core/suite/CodeTest.java @@ -1,16 +1,16 @@ -package ru.noties.markwon.core.suite; +package io.noties.markwon.core.suite; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -import ru.noties.markwon.test.TestSpan.Document; +import io.noties.markwon.test.TestSpan.Document; -import static ru.noties.markwon.test.TestSpan.args; -import static ru.noties.markwon.test.TestSpan.document; -import static ru.noties.markwon.test.TestSpan.span; -import static ru.noties.markwon.test.TestSpan.text; +import static io.noties.markwon.test.TestSpan.args; +import static io.noties.markwon.test.TestSpan.document; +import static io.noties.markwon.test.TestSpan.span; +import static io.noties.markwon.test.TestSpan.text; @RunWith(RobolectricTestRunner.class) @Config(manifest = Config.NONE) diff --git a/markwon-core/src/test/java/ru/noties/markwon/core/suite/DeeplyNestedTest.java b/markwon-core/src/test/java/io/noties/markwon/core/suite/DeeplyNestedTest.java similarity index 71% rename from markwon-core/src/test/java/ru/noties/markwon/core/suite/DeeplyNestedTest.java rename to markwon-core/src/test/java/io/noties/markwon/core/suite/DeeplyNestedTest.java index e0dcda38..86c948ba 100644 --- a/markwon-core/src/test/java/ru/noties/markwon/core/suite/DeeplyNestedTest.java +++ b/markwon-core/src/test/java/io/noties/markwon/core/suite/DeeplyNestedTest.java @@ -1,16 +1,16 @@ -package ru.noties.markwon.core.suite; +package io.noties.markwon.core.suite; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -import ru.noties.markwon.test.TestSpan.Document; +import io.noties.markwon.test.TestSpan.Document; -import static ru.noties.markwon.test.TestSpan.args; -import static ru.noties.markwon.test.TestSpan.document; -import static ru.noties.markwon.test.TestSpan.span; -import static ru.noties.markwon.test.TestSpan.text; +import static io.noties.markwon.test.TestSpan.args; +import static io.noties.markwon.test.TestSpan.document; +import static io.noties.markwon.test.TestSpan.span; +import static io.noties.markwon.test.TestSpan.text; @RunWith(RobolectricTestRunner.class) @Config(manifest = Config.NONE) diff --git a/markwon-core/src/test/java/ru/noties/markwon/core/suite/EmphasisTest.java b/markwon-core/src/test/java/io/noties/markwon/core/suite/EmphasisTest.java similarity index 64% rename from markwon-core/src/test/java/ru/noties/markwon/core/suite/EmphasisTest.java rename to markwon-core/src/test/java/io/noties/markwon/core/suite/EmphasisTest.java index 057acc18..697075ac 100644 --- a/markwon-core/src/test/java/ru/noties/markwon/core/suite/EmphasisTest.java +++ b/markwon-core/src/test/java/io/noties/markwon/core/suite/EmphasisTest.java @@ -1,15 +1,15 @@ -package ru.noties.markwon.core.suite; +package io.noties.markwon.core.suite; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -import ru.noties.markwon.test.TestSpan.Document; +import io.noties.markwon.test.TestSpan.Document; -import static ru.noties.markwon.test.TestSpan.document; -import static ru.noties.markwon.test.TestSpan.span; -import static ru.noties.markwon.test.TestSpan.text; +import static io.noties.markwon.test.TestSpan.document; +import static io.noties.markwon.test.TestSpan.span; +import static io.noties.markwon.test.TestSpan.text; @RunWith(RobolectricTestRunner.class) @Config(manifest = Config.NONE) diff --git a/markwon-core/src/test/java/ru/noties/markwon/core/suite/FirstTest.java b/markwon-core/src/test/java/io/noties/markwon/core/suite/FirstTest.java similarity index 71% rename from markwon-core/src/test/java/ru/noties/markwon/core/suite/FirstTest.java rename to markwon-core/src/test/java/io/noties/markwon/core/suite/FirstTest.java index f67a5062..32c8f17e 100644 --- a/markwon-core/src/test/java/ru/noties/markwon/core/suite/FirstTest.java +++ b/markwon-core/src/test/java/io/noties/markwon/core/suite/FirstTest.java @@ -1,16 +1,16 @@ -package ru.noties.markwon.core.suite; +package io.noties.markwon.core.suite; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -import ru.noties.markwon.test.TestSpan.Document; +import io.noties.markwon.test.TestSpan.Document; -import static ru.noties.markwon.test.TestSpan.args; -import static ru.noties.markwon.test.TestSpan.document; -import static ru.noties.markwon.test.TestSpan.span; -import static ru.noties.markwon.test.TestSpan.text; +import static io.noties.markwon.test.TestSpan.args; +import static io.noties.markwon.test.TestSpan.document; +import static io.noties.markwon.test.TestSpan.span; +import static io.noties.markwon.test.TestSpan.text; @RunWith(RobolectricTestRunner.class) @Config(manifest = Config.NONE) diff --git a/markwon-core/src/test/java/ru/noties/markwon/core/suite/HeadingTest.java b/markwon-core/src/test/java/io/noties/markwon/core/suite/HeadingTest.java similarity index 71% rename from markwon-core/src/test/java/ru/noties/markwon/core/suite/HeadingTest.java rename to markwon-core/src/test/java/io/noties/markwon/core/suite/HeadingTest.java index 10fa5f9b..4aef1e52 100644 --- a/markwon-core/src/test/java/ru/noties/markwon/core/suite/HeadingTest.java +++ b/markwon-core/src/test/java/io/noties/markwon/core/suite/HeadingTest.java @@ -1,16 +1,16 @@ -package ru.noties.markwon.core.suite; +package io.noties.markwon.core.suite; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -import ru.noties.markwon.test.TestSpan.Document; +import io.noties.markwon.test.TestSpan.Document; -import static ru.noties.markwon.test.TestSpan.args; -import static ru.noties.markwon.test.TestSpan.document; -import static ru.noties.markwon.test.TestSpan.span; -import static ru.noties.markwon.test.TestSpan.text; +import static io.noties.markwon.test.TestSpan.args; +import static io.noties.markwon.test.TestSpan.document; +import static io.noties.markwon.test.TestSpan.span; +import static io.noties.markwon.test.TestSpan.text; @RunWith(RobolectricTestRunner.class) @Config(manifest = Config.NONE) diff --git a/markwon-core/src/test/java/ru/noties/markwon/core/suite/LinkTest.java b/markwon-core/src/test/java/io/noties/markwon/core/suite/LinkTest.java similarity index 59% rename from markwon-core/src/test/java/ru/noties/markwon/core/suite/LinkTest.java rename to markwon-core/src/test/java/io/noties/markwon/core/suite/LinkTest.java index ff70f82c..a3e6f2af 100644 --- a/markwon-core/src/test/java/ru/noties/markwon/core/suite/LinkTest.java +++ b/markwon-core/src/test/java/io/noties/markwon/core/suite/LinkTest.java @@ -1,16 +1,16 @@ -package ru.noties.markwon.core.suite; +package io.noties.markwon.core.suite; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -import ru.noties.markwon.test.TestSpan.Document; +import io.noties.markwon.test.TestSpan.Document; -import static ru.noties.markwon.test.TestSpan.args; -import static ru.noties.markwon.test.TestSpan.document; -import static ru.noties.markwon.test.TestSpan.span; -import static ru.noties.markwon.test.TestSpan.text; +import static io.noties.markwon.test.TestSpan.args; +import static io.noties.markwon.test.TestSpan.document; +import static io.noties.markwon.test.TestSpan.span; +import static io.noties.markwon.test.TestSpan.text; @RunWith(RobolectricTestRunner.class) @Config(manifest = Config.NONE) diff --git a/markwon-core/src/test/java/ru/noties/markwon/core/suite/NoParagraphsTest.java b/markwon-core/src/test/java/io/noties/markwon/core/suite/NoParagraphsTest.java similarity index 75% rename from markwon-core/src/test/java/ru/noties/markwon/core/suite/NoParagraphsTest.java rename to markwon-core/src/test/java/io/noties/markwon/core/suite/NoParagraphsTest.java index 32ea306b..634b6d16 100644 --- a/markwon-core/src/test/java/ru/noties/markwon/core/suite/NoParagraphsTest.java +++ b/markwon-core/src/test/java/io/noties/markwon/core/suite/NoParagraphsTest.java @@ -1,14 +1,14 @@ -package ru.noties.markwon.core.suite; +package io.noties.markwon.core.suite; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -import ru.noties.markwon.test.TestSpan.Document; +import io.noties.markwon.test.TestSpan.Document; -import static ru.noties.markwon.test.TestSpan.document; -import static ru.noties.markwon.test.TestSpan.text; +import static io.noties.markwon.test.TestSpan.document; +import static io.noties.markwon.test.TestSpan.text; @RunWith(RobolectricTestRunner.class) @Config(manifest = Config.NONE) diff --git a/markwon-core/src/test/java/ru/noties/markwon/core/suite/OrderedListTest.java b/markwon-core/src/test/java/io/noties/markwon/core/suite/OrderedListTest.java similarity index 86% rename from markwon-core/src/test/java/ru/noties/markwon/core/suite/OrderedListTest.java rename to markwon-core/src/test/java/io/noties/markwon/core/suite/OrderedListTest.java index 9efb46b8..afd98aeb 100644 --- a/markwon-core/src/test/java/ru/noties/markwon/core/suite/OrderedListTest.java +++ b/markwon-core/src/test/java/io/noties/markwon/core/suite/OrderedListTest.java @@ -1,16 +1,16 @@ -package ru.noties.markwon.core.suite; +package io.noties.markwon.core.suite; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -import ru.noties.markwon.test.TestSpan.Document; +import io.noties.markwon.test.TestSpan.Document; -import static ru.noties.markwon.test.TestSpan.args; -import static ru.noties.markwon.test.TestSpan.document; -import static ru.noties.markwon.test.TestSpan.span; -import static ru.noties.markwon.test.TestSpan.text; +import static io.noties.markwon.test.TestSpan.args; +import static io.noties.markwon.test.TestSpan.document; +import static io.noties.markwon.test.TestSpan.span; +import static io.noties.markwon.test.TestSpan.text; @RunWith(RobolectricTestRunner.class) @Config(manifest = Config.NONE) diff --git a/markwon-core/src/test/java/ru/noties/markwon/core/suite/ParagraphTest.java b/markwon-core/src/test/java/io/noties/markwon/core/suite/ParagraphTest.java similarity index 73% rename from markwon-core/src/test/java/ru/noties/markwon/core/suite/ParagraphTest.java rename to markwon-core/src/test/java/io/noties/markwon/core/suite/ParagraphTest.java index 877a8818..c866ebe9 100644 --- a/markwon-core/src/test/java/ru/noties/markwon/core/suite/ParagraphTest.java +++ b/markwon-core/src/test/java/io/noties/markwon/core/suite/ParagraphTest.java @@ -1,15 +1,15 @@ -package ru.noties.markwon.core.suite; +package io.noties.markwon.core.suite; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -import ru.noties.markwon.test.TestSpan.Document; +import io.noties.markwon.test.TestSpan.Document; -import static ru.noties.markwon.test.TestSpan.document; -import static ru.noties.markwon.test.TestSpan.span; -import static ru.noties.markwon.test.TestSpan.text; +import static io.noties.markwon.test.TestSpan.document; +import static io.noties.markwon.test.TestSpan.span; +import static io.noties.markwon.test.TestSpan.text; @RunWith(RobolectricTestRunner.class) @Config(manifest = Config.NONE) diff --git a/markwon-core/src/test/java/ru/noties/markwon/core/suite/SecondTest.java b/markwon-core/src/test/java/io/noties/markwon/core/suite/SecondTest.java similarity index 78% rename from markwon-core/src/test/java/ru/noties/markwon/core/suite/SecondTest.java rename to markwon-core/src/test/java/io/noties/markwon/core/suite/SecondTest.java index 340df08d..fef1f3f4 100644 --- a/markwon-core/src/test/java/ru/noties/markwon/core/suite/SecondTest.java +++ b/markwon-core/src/test/java/io/noties/markwon/core/suite/SecondTest.java @@ -1,16 +1,16 @@ -package ru.noties.markwon.core.suite; +package io.noties.markwon.core.suite; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -import ru.noties.markwon.test.TestSpan.Document; +import io.noties.markwon.test.TestSpan.Document; -import static ru.noties.markwon.test.TestSpan.args; -import static ru.noties.markwon.test.TestSpan.document; -import static ru.noties.markwon.test.TestSpan.span; -import static ru.noties.markwon.test.TestSpan.text; +import static io.noties.markwon.test.TestSpan.args; +import static io.noties.markwon.test.TestSpan.document; +import static io.noties.markwon.test.TestSpan.span; +import static io.noties.markwon.test.TestSpan.text; @RunWith(RobolectricTestRunner.class) @Config(manifest = Config.NONE) diff --git a/markwon-core/src/test/java/ru/noties/markwon/core/suite/SoftBreakTest.java b/markwon-core/src/test/java/io/noties/markwon/core/suite/SoftBreakTest.java similarity index 72% rename from markwon-core/src/test/java/ru/noties/markwon/core/suite/SoftBreakTest.java rename to markwon-core/src/test/java/io/noties/markwon/core/suite/SoftBreakTest.java index b94ab45a..ed282908 100644 --- a/markwon-core/src/test/java/ru/noties/markwon/core/suite/SoftBreakTest.java +++ b/markwon-core/src/test/java/io/noties/markwon/core/suite/SoftBreakTest.java @@ -1,14 +1,14 @@ -package ru.noties.markwon.core.suite; +package io.noties.markwon.core.suite; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -import ru.noties.markwon.test.TestSpan.Document; +import io.noties.markwon.test.TestSpan.Document; -import static ru.noties.markwon.test.TestSpan.document; -import static ru.noties.markwon.test.TestSpan.text; +import static io.noties.markwon.test.TestSpan.document; +import static io.noties.markwon.test.TestSpan.text; @RunWith(RobolectricTestRunner.class) @Config(manifest = Config.NONE) diff --git a/markwon-core/src/test/java/ru/noties/markwon/core/suite/StrongEmphasisTest.java b/markwon-core/src/test/java/io/noties/markwon/core/suite/StrongEmphasisTest.java similarity index 65% rename from markwon-core/src/test/java/ru/noties/markwon/core/suite/StrongEmphasisTest.java rename to markwon-core/src/test/java/io/noties/markwon/core/suite/StrongEmphasisTest.java index d08377a1..97ccfa2e 100644 --- a/markwon-core/src/test/java/ru/noties/markwon/core/suite/StrongEmphasisTest.java +++ b/markwon-core/src/test/java/io/noties/markwon/core/suite/StrongEmphasisTest.java @@ -1,15 +1,15 @@ -package ru.noties.markwon.core.suite; +package io.noties.markwon.core.suite; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -import ru.noties.markwon.test.TestSpan.Document; +import io.noties.markwon.test.TestSpan.Document; -import static ru.noties.markwon.test.TestSpan.document; -import static ru.noties.markwon.test.TestSpan.span; -import static ru.noties.markwon.test.TestSpan.text; +import static io.noties.markwon.test.TestSpan.document; +import static io.noties.markwon.test.TestSpan.span; +import static io.noties.markwon.test.TestSpan.text; @RunWith(RobolectricTestRunner.class) @Config(manifest = Config.NONE) diff --git a/markwon-core/src/test/java/ru/noties/markwon/core/suite/ThematicBreakTest.java b/markwon-core/src/test/java/io/noties/markwon/core/suite/ThematicBreakTest.java similarity index 66% rename from markwon-core/src/test/java/ru/noties/markwon/core/suite/ThematicBreakTest.java rename to markwon-core/src/test/java/io/noties/markwon/core/suite/ThematicBreakTest.java index 1e0159bc..53d8f234 100644 --- a/markwon-core/src/test/java/ru/noties/markwon/core/suite/ThematicBreakTest.java +++ b/markwon-core/src/test/java/io/noties/markwon/core/suite/ThematicBreakTest.java @@ -1,15 +1,15 @@ -package ru.noties.markwon.core.suite; +package io.noties.markwon.core.suite; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -import ru.noties.markwon.test.TestSpan.Document; +import io.noties.markwon.test.TestSpan.Document; -import static ru.noties.markwon.test.TestSpan.document; -import static ru.noties.markwon.test.TestSpan.span; -import static ru.noties.markwon.test.TestSpan.text; +import static io.noties.markwon.test.TestSpan.document; +import static io.noties.markwon.test.TestSpan.span; +import static io.noties.markwon.test.TestSpan.text; @RunWith(RobolectricTestRunner.class) @Config(manifest = Config.NONE) diff --git a/markwon-core/src/test/java/ru/noties/markwon/core/suite/UnOrderedListTest.java b/markwon-core/src/test/java/io/noties/markwon/core/suite/UnOrderedListTest.java similarity index 83% rename from markwon-core/src/test/java/ru/noties/markwon/core/suite/UnOrderedListTest.java rename to markwon-core/src/test/java/io/noties/markwon/core/suite/UnOrderedListTest.java index 9b1dfb85..41503788 100644 --- a/markwon-core/src/test/java/ru/noties/markwon/core/suite/UnOrderedListTest.java +++ b/markwon-core/src/test/java/io/noties/markwon/core/suite/UnOrderedListTest.java @@ -1,16 +1,16 @@ -package ru.noties.markwon.core.suite; +package io.noties.markwon.core.suite; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -import ru.noties.markwon.test.TestSpan.Document; +import io.noties.markwon.test.TestSpan.Document; -import static ru.noties.markwon.test.TestSpan.args; -import static ru.noties.markwon.test.TestSpan.document; -import static ru.noties.markwon.test.TestSpan.span; -import static ru.noties.markwon.test.TestSpan.text; +import static io.noties.markwon.test.TestSpan.args; +import static io.noties.markwon.test.TestSpan.document; +import static io.noties.markwon.test.TestSpan.span; +import static io.noties.markwon.test.TestSpan.text; @RunWith(RobolectricTestRunner.class) @Config(manifest = Config.NONE) diff --git a/markwon-core/src/test/java/ru/noties/markwon/image/AsyncDrawableTest.java b/markwon-core/src/test/java/io/noties/markwon/image/AsyncDrawableTest.java similarity index 98% rename from markwon-core/src/test/java/ru/noties/markwon/image/AsyncDrawableTest.java rename to markwon-core/src/test/java/io/noties/markwon/image/AsyncDrawableTest.java index 7dad4514..d725c00f 100644 --- a/markwon-core/src/test/java/ru/noties/markwon/image/AsyncDrawableTest.java +++ b/markwon-core/src/test/java/io/noties/markwon/image/AsyncDrawableTest.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.image; +package io.noties.markwon.image; import android.graphics.Canvas; import android.graphics.ColorFilter; diff --git a/markwon-core/src/test/java/ru/noties/markwon/image/ImageSizeResolverDefTest.java b/markwon-core/src/test/java/io/noties/markwon/image/ImageSizeResolverDefTest.java similarity index 80% rename from markwon-core/src/test/java/ru/noties/markwon/image/ImageSizeResolverDefTest.java rename to markwon-core/src/test/java/io/noties/markwon/image/ImageSizeResolverDefTest.java index f8649603..33280b03 100644 --- a/markwon-core/src/test/java/ru/noties/markwon/image/ImageSizeResolverDefTest.java +++ b/markwon-core/src/test/java/io/noties/markwon/image/ImageSizeResolverDefTest.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.image; +package io.noties.markwon.image; import android.graphics.Rect; @@ -8,13 +8,9 @@ import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -import ru.noties.markwon.image.ImageSize; -import ru.noties.markwon.image.ImageSize.Dimension; -import ru.noties.markwon.image.ImageSizeResolverDef; - import static org.junit.Assert.assertEquals; -import static ru.noties.markwon.image.ImageSizeResolverDef.UNIT_EM; -import static ru.noties.markwon.image.ImageSizeResolverDef.UNIT_PERCENT; +import static io.noties.markwon.image.ImageSizeResolverDef.UNIT_EM; +import static io.noties.markwon.image.ImageSizeResolverDef.UNIT_PERCENT; @RunWith(RobolectricTestRunner.class) @Config(manifest = Config.NONE) @@ -55,7 +51,7 @@ public class ImageSizeResolverDefTest { assertEquals( rect, def.resolveImageSize( - new ImageSize(null, new Dimension(100.F, UNIT_PERCENT)), + new ImageSize(null, new ImageSize.Dimension(100.F, UNIT_PERCENT)), rect, -1, Float.NaN @@ -69,7 +65,7 @@ public class ImageSizeResolverDefTest { assertEquals( new Rect(0, 0, 50, 100), def.resolveImageSize( - new ImageSize(new Dimension(50.F, UNIT_PERCENT), null), + new ImageSize(new ImageSize.Dimension(50.F, UNIT_PERCENT), null), rect, 100, Float.NaN @@ -83,7 +79,7 @@ public class ImageSizeResolverDefTest { assertEquals( new Rect(0, 0, 7, 9), def.resolveImageSize( - new ImageSize(new Dimension(7, "width"), new Dimension(9, "height")), + new ImageSize(new ImageSize.Dimension(7, "width"), new ImageSize.Dimension(9, "height")), rect, 90, Float.NaN @@ -97,7 +93,7 @@ public class ImageSizeResolverDefTest { assertEquals( new Rect(0, 0, 20, 40), def.resolveImageSize( - new ImageSize(new Dimension(2.f, UNIT_EM), new Dimension(4.F, UNIT_EM)), + new ImageSize(new ImageSize.Dimension(2.f, UNIT_EM), new ImageSize.Dimension(4.F, UNIT_EM)), rect, 999, 10.F @@ -111,7 +107,7 @@ public class ImageSizeResolverDefTest { assertEquals( new Rect(0, 0, 10, 20), def.resolveImageSize( - new ImageSize(new Dimension(1.F, UNIT_EM), null), + new ImageSize(new ImageSize.Dimension(1.F, UNIT_EM), null), rect, 42, 10.F @@ -125,7 +121,7 @@ public class ImageSizeResolverDefTest { assertEquals( new Rect(0, 0, 100, 50), def.resolveImageSize( - new ImageSize(null, new Dimension(50, "px")), + new ImageSize(null, new ImageSize.Dimension(50, "px")), rect, 200, Float.NaN @@ -139,7 +135,7 @@ public class ImageSizeResolverDefTest { assertEquals( new Rect(0, 0, 10, 30), def.resolveImageSize( - new ImageSize(null, new Dimension(3.F, UNIT_EM)), + new ImageSize(null, new ImageSize.Dimension(3.F, UNIT_EM)), rect, 40, 10.F diff --git a/markwon-core/src/test/java/ru/noties/markwon/image/ImageTest.java b/markwon-core/src/test/java/io/noties/markwon/image/ImageTest.java similarity index 70% rename from markwon-core/src/test/java/ru/noties/markwon/image/ImageTest.java rename to markwon-core/src/test/java/io/noties/markwon/image/ImageTest.java index def53907..71d13624 100644 --- a/markwon-core/src/test/java/ru/noties/markwon/image/ImageTest.java +++ b/markwon-core/src/test/java/io/noties/markwon/image/ImageTest.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.image; +package io.noties.markwon.image; import android.content.Context; import android.support.annotation.NonNull; @@ -10,20 +10,20 @@ import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; -import ru.noties.markwon.AbstractMarkwonPlugin; -import ru.noties.markwon.Markwon; -import ru.noties.markwon.MarkwonConfiguration; -import ru.noties.markwon.MarkwonSpansFactory; -import ru.noties.markwon.RenderProps; -import ru.noties.markwon.SpanFactory; -import ru.noties.markwon.core.CorePlugin; -import ru.noties.markwon.test.TestSpan.Document; -import ru.noties.markwon.test.TestSpanMatcher; +import io.noties.markwon.AbstractMarkwonPlugin; +import io.noties.markwon.Markwon; +import io.noties.markwon.MarkwonConfiguration; +import io.noties.markwon.MarkwonSpansFactory; +import io.noties.markwon.RenderProps; +import io.noties.markwon.SpanFactory; +import io.noties.markwon.core.CorePlugin; +import io.noties.markwon.test.TestSpan.Document; +import io.noties.markwon.test.TestSpanMatcher; -import static ru.noties.markwon.test.TestSpan.args; -import static ru.noties.markwon.test.TestSpan.document; -import static ru.noties.markwon.test.TestSpan.span; -import static ru.noties.markwon.test.TestSpan.text; +import static io.noties.markwon.test.TestSpan.args; +import static io.noties.markwon.test.TestSpan.document; +import static io.noties.markwon.test.TestSpan.span; +import static io.noties.markwon.test.TestSpan.text; @RunWith(RobolectricTestRunner.class) @Config(manifest = Config.NONE) diff --git a/markwon-core/src/test/java/ru/noties/markwon/syntax/SyntaxHighlightTest.java b/markwon-core/src/test/java/io/noties/markwon/syntax/SyntaxHighlightTest.java similarity index 90% rename from markwon-core/src/test/java/ru/noties/markwon/syntax/SyntaxHighlightTest.java rename to markwon-core/src/test/java/io/noties/markwon/syntax/SyntaxHighlightTest.java index 68fa8a12..3024fcc0 100644 --- a/markwon-core/src/test/java/ru/noties/markwon/syntax/SyntaxHighlightTest.java +++ b/markwon-core/src/test/java/io/noties/markwon/syntax/SyntaxHighlightTest.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.syntax; +package io.noties.markwon.syntax; import android.os.Build; import android.support.annotation.NonNull; @@ -17,16 +17,16 @@ import java.util.Arrays; import java.util.Collections; import java.util.Map; -import ru.noties.markwon.AbstractMarkwonVisitorImpl; -import ru.noties.markwon.MarkwonConfiguration; -import ru.noties.markwon.MarkwonSpansFactory; -import ru.noties.markwon.MarkwonVisitor; -import ru.noties.markwon.RenderProps; -import ru.noties.markwon.SpanFactory; -import ru.noties.markwon.SpannableBuilder; -import ru.noties.markwon.core.CorePluginBridge; -import ru.noties.markwon.core.MarkwonTheme; -import ru.noties.markwon.html.MarkwonHtmlRenderer; +import io.noties.markwon.AbstractMarkwonVisitorImpl; +import io.noties.markwon.MarkwonConfiguration; +import io.noties.markwon.MarkwonSpansFactory; +import io.noties.markwon.MarkwonVisitor; +import io.noties.markwon.RenderProps; +import io.noties.markwon.SpanFactory; +import io.noties.markwon.SpannableBuilder; +import io.noties.markwon.core.CorePluginBridge; +import io.noties.markwon.core.MarkwonTheme; +import io.noties.markwon.html.MarkwonHtmlRenderer; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; diff --git a/markwon-core/src/test/java/ru/noties/markwon/urlprocessor/UrlProcessorAndroidAssetsTest.java b/markwon-core/src/test/java/io/noties/markwon/urlprocessor/UrlProcessorAndroidAssetsTest.java similarity index 87% rename from markwon-core/src/test/java/ru/noties/markwon/urlprocessor/UrlProcessorAndroidAssetsTest.java rename to markwon-core/src/test/java/io/noties/markwon/urlprocessor/UrlProcessorAndroidAssetsTest.java index 7a5cbf1a..4129bfb8 100644 --- a/markwon-core/src/test/java/ru/noties/markwon/urlprocessor/UrlProcessorAndroidAssetsTest.java +++ b/markwon-core/src/test/java/io/noties/markwon/urlprocessor/UrlProcessorAndroidAssetsTest.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.urlprocessor; +package io.noties.markwon.urlprocessor; import org.junit.Before; import org.junit.Test; @@ -6,10 +6,8 @@ import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -import ru.noties.markwon.urlprocessor.UrlProcessorAndroidAssets; - import static org.junit.Assert.assertEquals; -import static ru.noties.markwon.urlprocessor.UrlProcessorAndroidAssets.BASE; +import static io.noties.markwon.urlprocessor.UrlProcessorAndroidAssets.BASE; @RunWith(RobolectricTestRunner.class) @Config(manifest = Config.NONE) diff --git a/markwon-core/src/test/java/ru/noties/markwon/urlprocessor/UrlProcessorRelativeToAbsoluteTest.java b/markwon-core/src/test/java/io/noties/markwon/urlprocessor/UrlProcessorRelativeToAbsoluteTest.java similarity index 95% rename from markwon-core/src/test/java/ru/noties/markwon/urlprocessor/UrlProcessorRelativeToAbsoluteTest.java rename to markwon-core/src/test/java/io/noties/markwon/urlprocessor/UrlProcessorRelativeToAbsoluteTest.java index a8bf2d01..afa55b33 100644 --- a/markwon-core/src/test/java/ru/noties/markwon/urlprocessor/UrlProcessorRelativeToAbsoluteTest.java +++ b/markwon-core/src/test/java/io/noties/markwon/urlprocessor/UrlProcessorRelativeToAbsoluteTest.java @@ -1,12 +1,10 @@ -package ru.noties.markwon.urlprocessor; +package io.noties.markwon.urlprocessor; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -import ru.noties.markwon.urlprocessor.UrlProcessorRelativeToAbsolute; - import static org.junit.Assert.*; @RunWith(RobolectricTestRunner.class) diff --git a/markwon-ext-latex/src/main/AndroidManifest.xml b/markwon-ext-latex/src/main/AndroidManifest.xml index fee2db10..b38d59c6 100644 --- a/markwon-ext-latex/src/main/AndroidManifest.xml +++ b/markwon-ext-latex/src/main/AndroidManifest.xml @@ -1 +1 @@ - + diff --git a/markwon-ext-latex/src/main/java/ru/noties/markwon/ext/latex/JLatexMathBlock.java b/markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathBlock.java similarity index 87% rename from markwon-ext-latex/src/main/java/ru/noties/markwon/ext/latex/JLatexMathBlock.java rename to markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathBlock.java index d49d108a..4066caba 100644 --- a/markwon-ext-latex/src/main/java/ru/noties/markwon/ext/latex/JLatexMathBlock.java +++ b/markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathBlock.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.ext.latex; +package io.noties.markwon.ext.latex; import org.commonmark.node.CustomBlock; diff --git a/markwon-ext-latex/src/main/java/ru/noties/markwon/ext/latex/JLatexMathBlockParser.java b/markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathBlockParser.java similarity index 98% rename from markwon-ext-latex/src/main/java/ru/noties/markwon/ext/latex/JLatexMathBlockParser.java rename to markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathBlockParser.java index 7aac76f2..8f54f245 100644 --- a/markwon-ext-latex/src/main/java/ru/noties/markwon/ext/latex/JLatexMathBlockParser.java +++ b/markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathBlockParser.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.ext.latex; +package io.noties.markwon.ext.latex; import org.commonmark.node.Block; import org.commonmark.parser.block.AbstractBlockParser; diff --git a/markwon-ext-latex/src/main/java/ru/noties/markwon/ext/latex/JLatexMathPlugin.java b/markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathPlugin.java similarity index 95% rename from markwon-ext-latex/src/main/java/ru/noties/markwon/ext/latex/JLatexMathPlugin.java rename to markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathPlugin.java index decdb6d1..f3d16403 100644 --- a/markwon-ext-latex/src/main/java/ru/noties/markwon/ext/latex/JLatexMathPlugin.java +++ b/markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathPlugin.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.ext.latex; +package io.noties.markwon.ext.latex; import android.graphics.drawable.Drawable; import android.os.Handler; @@ -18,15 +18,15 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; +import io.noties.markwon.image.AsyncDrawable; +import io.noties.markwon.image.AsyncDrawableScheduler; +import io.noties.markwon.image.AsyncDrawableSpan; import ru.noties.jlatexmath.JLatexMathDrawable; -import ru.noties.markwon.AbstractMarkwonPlugin; -import ru.noties.markwon.MarkwonConfiguration; -import ru.noties.markwon.MarkwonVisitor; -import ru.noties.markwon.image.AsyncDrawable; -import ru.noties.markwon.image.AsyncDrawableLoader; -import ru.noties.markwon.image.AsyncDrawableScheduler; -import ru.noties.markwon.image.AsyncDrawableSpan; -import ru.noties.markwon.image.ImageSize; +import io.noties.markwon.AbstractMarkwonPlugin; +import io.noties.markwon.MarkwonConfiguration; +import io.noties.markwon.MarkwonVisitor; +import io.noties.markwon.image.AsyncDrawableLoader; +import io.noties.markwon.image.ImageSize; /** * @since 3.0.0 diff --git a/markwon-ext-strikethrough/README.md b/markwon-ext-strikethrough/README.md index acd8b513..1f99b846 100644 --- a/markwon-ext-strikethrough/README.md +++ b/markwon-ext-strikethrough/README.md @@ -1,6 +1,6 @@ # Strikethrough -[![ext-strikethrough](https://img.shields.io/maven-central/v/ru.noties.markwon/ext-strikethrough.svg?label=ext-strikethrough)](http://search.maven.org/#search|ga|1|g%3A%22ru.noties.markwon%22%20AND%20a%3A%22ext-strikethrough%22) +[![ext-strikethrough](https://img.shields.io/maven-central/v/io.noties.markwon/ext-strikethrough.svg?label=ext-strikethrough)](http://search.maven.org/#search|ga|1|g%3A%22io.noties.markwon%22%20AND%20a%3A%22ext-strikethrough%22) This module adds `strikethrough` functionality to `Markwon` via `StrikethroughPlugin`: diff --git a/markwon-ext-strikethrough/src/main/AndroidManifest.xml b/markwon-ext-strikethrough/src/main/AndroidManifest.xml index 6c243e1b..09c636bd 100644 --- a/markwon-ext-strikethrough/src/main/AndroidManifest.xml +++ b/markwon-ext-strikethrough/src/main/AndroidManifest.xml @@ -1 +1 @@ - + diff --git a/markwon-ext-strikethrough/src/main/java/ru/noties/markwon/ext/strikethrough/StrikethroughPlugin.java b/markwon-ext-strikethrough/src/main/java/io/noties/markwon/ext/strikethrough/StrikethroughPlugin.java similarity index 85% rename from markwon-ext-strikethrough/src/main/java/ru/noties/markwon/ext/strikethrough/StrikethroughPlugin.java rename to markwon-ext-strikethrough/src/main/java/io/noties/markwon/ext/strikethrough/StrikethroughPlugin.java index f73ccc71..08d7aa06 100644 --- a/markwon-ext-strikethrough/src/main/java/ru/noties/markwon/ext/strikethrough/StrikethroughPlugin.java +++ b/markwon-ext-strikethrough/src/main/java/io/noties/markwon/ext/strikethrough/StrikethroughPlugin.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.ext.strikethrough; +package io.noties.markwon.ext.strikethrough; import android.support.annotation.NonNull; import android.text.style.StrikethroughSpan; @@ -9,12 +9,12 @@ import org.commonmark.parser.Parser; import java.util.Collections; -import ru.noties.markwon.AbstractMarkwonPlugin; -import ru.noties.markwon.MarkwonConfiguration; -import ru.noties.markwon.MarkwonSpansFactory; -import ru.noties.markwon.MarkwonVisitor; -import ru.noties.markwon.RenderProps; -import ru.noties.markwon.SpanFactory; +import io.noties.markwon.AbstractMarkwonPlugin; +import io.noties.markwon.MarkwonConfiguration; +import io.noties.markwon.MarkwonSpansFactory; +import io.noties.markwon.MarkwonVisitor; +import io.noties.markwon.RenderProps; +import io.noties.markwon.SpanFactory; /** * Plugin to add strikethrough markdown feature. This plugin will extend commonmark-java.Parser diff --git a/markwon-ext-strikethrough/src/test/java/ru/noties/markwon/ext/strikethrough/StrikethroughPluginTest.java b/markwon-ext-strikethrough/src/test/java/io/noties/markwon/ext/strikethrough/StrikethroughPluginTest.java similarity index 87% rename from markwon-ext-strikethrough/src/test/java/ru/noties/markwon/ext/strikethrough/StrikethroughPluginTest.java rename to markwon-ext-strikethrough/src/test/java/io/noties/markwon/ext/strikethrough/StrikethroughPluginTest.java index 18cab664..db77c79d 100644 --- a/markwon-ext-strikethrough/src/test/java/ru/noties/markwon/ext/strikethrough/StrikethroughPluginTest.java +++ b/markwon-ext-strikethrough/src/test/java/io/noties/markwon/ext/strikethrough/StrikethroughPluginTest.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.ext.strikethrough; +package io.noties.markwon.ext.strikethrough; import android.support.annotation.NonNull; import android.text.style.StrikethroughSpan; @@ -17,16 +17,16 @@ import org.robolectric.annotation.Config; import java.util.List; import ix.Ix; -import ru.noties.markwon.AbstractMarkwonPlugin; -import ru.noties.markwon.Markwon; -import ru.noties.markwon.MarkwonConfiguration; -import ru.noties.markwon.MarkwonSpansFactory; -import ru.noties.markwon.MarkwonVisitor; -import ru.noties.markwon.RenderProps; -import ru.noties.markwon.SpanFactory; -import ru.noties.markwon.core.CorePlugin; -import ru.noties.markwon.test.TestSpan; -import ru.noties.markwon.test.TestSpanMatcher; +import io.noties.markwon.AbstractMarkwonPlugin; +import io.noties.markwon.Markwon; +import io.noties.markwon.MarkwonConfiguration; +import io.noties.markwon.MarkwonSpansFactory; +import io.noties.markwon.MarkwonVisitor; +import io.noties.markwon.RenderProps; +import io.noties.markwon.SpanFactory; +import io.noties.markwon.core.CorePlugin; +import io.noties.markwon.test.TestSpan; +import io.noties.markwon.test.TestSpanMatcher; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -35,9 +35,9 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import static ru.noties.markwon.test.TestSpan.document; -import static ru.noties.markwon.test.TestSpan.span; -import static ru.noties.markwon.test.TestSpan.text; +import static io.noties.markwon.test.TestSpan.document; +import static io.noties.markwon.test.TestSpan.span; +import static io.noties.markwon.test.TestSpan.text; @RunWith(RobolectricTestRunner.class) @Config(manifest = Config.NONE) diff --git a/markwon-ext-tables/README.md b/markwon-ext-tables/README.md index 6f94bd2d..5bb0effd 100644 --- a/markwon-ext-tables/README.md +++ b/markwon-ext-tables/README.md @@ -1,6 +1,6 @@ # Tables -[![ext-tables](https://img.shields.io/maven-central/v/ru.noties.markwon/ext-tables.svg?label=ext-tables)](http://search.maven.org/#search|ga|1|g%3A%22ru.noties.markwon%22%20AND%20a%3A%22ext-tables%22) +[![ext-tables](https://img.shields.io/maven-central/v/io.noties.markwon/ext-tables.svg?label=ext-tables)](http://search.maven.org/#search|ga|1|g%3A%22io.noties.markwon%22%20AND%20a%3A%22ext-tables%22) This extension adds support for GFM tables. diff --git a/markwon-ext-tables/src/main/AndroidManifest.xml b/markwon-ext-tables/src/main/AndroidManifest.xml index f65b9d67..d83c2374 100644 --- a/markwon-ext-tables/src/main/AndroidManifest.xml +++ b/markwon-ext-tables/src/main/AndroidManifest.xml @@ -1 +1 @@ - + diff --git a/markwon-ext-tables/src/main/java/ru/noties/markwon/ext/tables/Table.java b/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/Table.java similarity index 98% rename from markwon-ext-tables/src/main/java/ru/noties/markwon/ext/tables/Table.java rename to markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/Table.java index 12fee872..774c52e2 100644 --- a/markwon-ext-tables/src/main/java/ru/noties/markwon/ext/tables/Table.java +++ b/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/Table.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.ext.tables; +package io.noties.markwon.ext.tables; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -14,7 +14,7 @@ import org.commonmark.node.CustomNode; import java.util.ArrayList; import java.util.List; -import ru.noties.markwon.Markwon; +import io.noties.markwon.Markwon; /** * A class to parse TableBlock and return a data-structure that is not dependent diff --git a/markwon-ext-tables/src/main/java/ru/noties/markwon/ext/tables/TablePlugin.java b/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TablePlugin.java similarity index 97% rename from markwon-ext-tables/src/main/java/ru/noties/markwon/ext/tables/TablePlugin.java rename to markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TablePlugin.java index f05a84fc..7846029c 100644 --- a/markwon-ext-tables/src/main/java/ru/noties/markwon/ext/tables/TablePlugin.java +++ b/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TablePlugin.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.ext.tables; +package io.noties.markwon.ext.tables; import android.content.Context; import android.support.annotation.NonNull; @@ -17,9 +17,9 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import ru.noties.markwon.AbstractMarkwonPlugin; -import ru.noties.markwon.MarkwonVisitor; -import ru.noties.markwon.SpannableBuilder; +import io.noties.markwon.AbstractMarkwonPlugin; +import io.noties.markwon.MarkwonVisitor; +import io.noties.markwon.SpannableBuilder; /** * @since 3.0.0 diff --git a/markwon-ext-tables/src/main/java/ru/noties/markwon/ext/tables/TableRowSpan.java b/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TableRowSpan.java similarity index 99% rename from markwon-ext-tables/src/main/java/ru/noties/markwon/ext/tables/TableRowSpan.java rename to markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TableRowSpan.java index 3f9bbace..a4bd08a7 100644 --- a/markwon-ext-tables/src/main/java/ru/noties/markwon/ext/tables/TableRowSpan.java +++ b/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TableRowSpan.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.ext.tables; +package io.noties.markwon.ext.tables; import android.annotation.SuppressLint; import android.graphics.Canvas; diff --git a/markwon-ext-tables/src/main/java/ru/noties/markwon/ext/tables/TableRowsScheduler.java b/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TableRowsScheduler.java similarity index 98% rename from markwon-ext-tables/src/main/java/ru/noties/markwon/ext/tables/TableRowsScheduler.java rename to markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TableRowsScheduler.java index b3b4c773..5fbb6b4b 100644 --- a/markwon-ext-tables/src/main/java/ru/noties/markwon/ext/tables/TableRowsScheduler.java +++ b/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TableRowsScheduler.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.ext.tables; +package io.noties.markwon.ext.tables; import android.support.annotation.NonNull; import android.support.annotation.Nullable; diff --git a/markwon-ext-tables/src/main/java/ru/noties/markwon/ext/tables/TableTheme.java b/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TableTheme.java similarity index 97% rename from markwon-ext-tables/src/main/java/ru/noties/markwon/ext/tables/TableTheme.java rename to markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TableTheme.java index e9b1bd47..eeab17d9 100644 --- a/markwon-ext-tables/src/main/java/ru/noties/markwon/ext/tables/TableTheme.java +++ b/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TableTheme.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.ext.tables; +package io.noties.markwon.ext.tables; import android.content.Context; import android.graphics.Paint; @@ -6,8 +6,8 @@ import android.support.annotation.ColorInt; import android.support.annotation.NonNull; import android.support.annotation.Px; -import ru.noties.markwon.utils.ColorUtils; -import ru.noties.markwon.utils.Dip; +import io.noties.markwon.utils.ColorUtils; +import io.noties.markwon.utils.Dip; public class TableTheme { diff --git a/markwon-ext-tasklist/src/main/AndroidManifest.xml b/markwon-ext-tasklist/src/main/AndroidManifest.xml index 14f5d738..2d436d25 100644 --- a/markwon-ext-tasklist/src/main/AndroidManifest.xml +++ b/markwon-ext-tasklist/src/main/AndroidManifest.xml @@ -1 +1 @@ - + diff --git a/markwon-ext-tasklist/src/main/java/ru/noties/markwon/ext/tasklist/TaskListBlock.java b/markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListBlock.java similarity index 74% rename from markwon-ext-tasklist/src/main/java/ru/noties/markwon/ext/tasklist/TaskListBlock.java rename to markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListBlock.java index 4e3cc8b4..157104f4 100644 --- a/markwon-ext-tasklist/src/main/java/ru/noties/markwon/ext/tasklist/TaskListBlock.java +++ b/markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListBlock.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.ext.tasklist; +package io.noties.markwon.ext.tasklist; import org.commonmark.node.CustomBlock; diff --git a/markwon-ext-tasklist/src/main/java/ru/noties/markwon/ext/tasklist/TaskListBlockParser.java b/markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListBlockParser.java similarity index 99% rename from markwon-ext-tasklist/src/main/java/ru/noties/markwon/ext/tasklist/TaskListBlockParser.java rename to markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListBlockParser.java index 417d92a7..b36ce73a 100644 --- a/markwon-ext-tasklist/src/main/java/ru/noties/markwon/ext/tasklist/TaskListBlockParser.java +++ b/markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListBlockParser.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.ext.tasklist; +package io.noties.markwon.ext.tasklist; import android.support.annotation.NonNull; import android.support.annotation.Nullable; diff --git a/markwon-ext-tasklist/src/main/java/ru/noties/markwon/ext/tasklist/TaskListDrawable.java b/markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListDrawable.java similarity index 99% rename from markwon-ext-tasklist/src/main/java/ru/noties/markwon/ext/tasklist/TaskListDrawable.java rename to markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListDrawable.java index 4a02c6c4..b43ea1ec 100644 --- a/markwon-ext-tasklist/src/main/java/ru/noties/markwon/ext/tasklist/TaskListDrawable.java +++ b/markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListDrawable.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.ext.tasklist; +package io.noties.markwon.ext.tasklist; import android.graphics.Canvas; import android.graphics.ColorFilter; diff --git a/markwon-ext-tasklist/src/main/java/ru/noties/markwon/ext/tasklist/TaskListItem.java b/markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListItem.java similarity index 92% rename from markwon-ext-tasklist/src/main/java/ru/noties/markwon/ext/tasklist/TaskListItem.java rename to markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListItem.java index 65b969db..0ba504b8 100644 --- a/markwon-ext-tasklist/src/main/java/ru/noties/markwon/ext/tasklist/TaskListItem.java +++ b/markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListItem.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.ext.tasklist; +package io.noties.markwon.ext.tasklist; import org.commonmark.node.CustomNode; diff --git a/markwon-ext-tasklist/src/main/java/ru/noties/markwon/ext/tasklist/TaskListPlugin.java b/markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListPlugin.java similarity index 93% rename from markwon-ext-tasklist/src/main/java/ru/noties/markwon/ext/tasklist/TaskListPlugin.java rename to markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListPlugin.java index ec664280..5c37ea8c 100644 --- a/markwon-ext-tasklist/src/main/java/ru/noties/markwon/ext/tasklist/TaskListPlugin.java +++ b/markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListPlugin.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.ext.tasklist; +package io.noties.markwon.ext.tasklist; import android.content.Context; import android.content.res.TypedArray; @@ -11,11 +11,11 @@ import android.util.TypedValue; import org.commonmark.node.Node; import org.commonmark.parser.Parser; -import ru.noties.markwon.AbstractMarkwonPlugin; -import ru.noties.markwon.MarkwonSpansFactory; -import ru.noties.markwon.MarkwonVisitor; -import ru.noties.markwon.RenderProps; -import ru.noties.markwon.core.SimpleBlockNodeVisitor; +import io.noties.markwon.AbstractMarkwonPlugin; +import io.noties.markwon.MarkwonSpansFactory; +import io.noties.markwon.MarkwonVisitor; +import io.noties.markwon.RenderProps; +import io.noties.markwon.core.SimpleBlockNodeVisitor; /** * @since 3.0.0 diff --git a/markwon-ext-tasklist/src/main/java/ru/noties/markwon/ext/tasklist/TaskListProps.java b/markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListProps.java similarity index 78% rename from markwon-ext-tasklist/src/main/java/ru/noties/markwon/ext/tasklist/TaskListProps.java rename to markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListProps.java index 7a0b6ca7..9e02990b 100644 --- a/markwon-ext-tasklist/src/main/java/ru/noties/markwon/ext/tasklist/TaskListProps.java +++ b/markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListProps.java @@ -1,6 +1,6 @@ -package ru.noties.markwon.ext.tasklist; +package io.noties.markwon.ext.tasklist; -import ru.noties.markwon.Prop; +import io.noties.markwon.Prop; /** * @since 3.0.0 diff --git a/markwon-ext-tasklist/src/main/java/ru/noties/markwon/ext/tasklist/TaskListSpan.java b/markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListSpan.java similarity index 95% rename from markwon-ext-tasklist/src/main/java/ru/noties/markwon/ext/tasklist/TaskListSpan.java rename to markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListSpan.java index b851f382..02d8a2a3 100644 --- a/markwon-ext-tasklist/src/main/java/ru/noties/markwon/ext/tasklist/TaskListSpan.java +++ b/markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListSpan.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.ext.tasklist; +package io.noties.markwon.ext.tasklist; import android.graphics.Canvas; import android.graphics.Paint; @@ -7,8 +7,8 @@ import android.support.annotation.NonNull; import android.text.Layout; import android.text.style.LeadingMarginSpan; -import ru.noties.markwon.core.MarkwonTheme; -import ru.noties.markwon.utils.LeadingMarginUtils; +import io.noties.markwon.core.MarkwonTheme; +import io.noties.markwon.utils.LeadingMarginUtils; /** * @since 1.0.1 diff --git a/markwon-ext-tasklist/src/main/java/ru/noties/markwon/ext/tasklist/TaskListSpanFactory.java b/markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListSpanFactory.java similarity index 80% rename from markwon-ext-tasklist/src/main/java/ru/noties/markwon/ext/tasklist/TaskListSpanFactory.java rename to markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListSpanFactory.java index bd68ede3..80864340 100644 --- a/markwon-ext-tasklist/src/main/java/ru/noties/markwon/ext/tasklist/TaskListSpanFactory.java +++ b/markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListSpanFactory.java @@ -1,12 +1,12 @@ -package ru.noties.markwon.ext.tasklist; +package io.noties.markwon.ext.tasklist; import android.graphics.drawable.Drawable; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import ru.noties.markwon.MarkwonConfiguration; -import ru.noties.markwon.RenderProps; -import ru.noties.markwon.SpanFactory; +import io.noties.markwon.MarkwonConfiguration; +import io.noties.markwon.RenderProps; +import io.noties.markwon.SpanFactory; public class TaskListSpanFactory implements SpanFactory { diff --git a/markwon-ext-tasklist/src/test/java/ru/noties/markwon/ext/tasklist/TaskListTest.java b/markwon-ext-tasklist/src/test/java/io/noties/markwon/ext/tasklist/TaskListTest.java similarity index 56% rename from markwon-ext-tasklist/src/test/java/ru/noties/markwon/ext/tasklist/TaskListTest.java rename to markwon-ext-tasklist/src/test/java/io/noties/markwon/ext/tasklist/TaskListTest.java index 6097312a..c28a8555 100644 --- a/markwon-ext-tasklist/src/test/java/ru/noties/markwon/ext/tasklist/TaskListTest.java +++ b/markwon-ext-tasklist/src/test/java/io/noties/markwon/ext/tasklist/TaskListTest.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.ext.tasklist; +package io.noties.markwon.ext.tasklist; import android.support.annotation.NonNull; @@ -12,19 +12,16 @@ import org.robolectric.annotation.Config; import java.io.IOException; import java.nio.charset.StandardCharsets; -import ru.noties.markwon.AbstractMarkwonPlugin; -import ru.noties.markwon.Markwon; -import ru.noties.markwon.MarkwonConfiguration; -import ru.noties.markwon.MarkwonSpansFactory; -import ru.noties.markwon.RenderProps; -import ru.noties.markwon.SpanFactory; -import ru.noties.markwon.test.TestSpan; -import ru.noties.markwon.test.TestSpanMatcher; +import io.noties.markwon.AbstractMarkwonPlugin; +import io.noties.markwon.Markwon; +import io.noties.markwon.MarkwonConfiguration; +import io.noties.markwon.MarkwonSpansFactory; +import io.noties.markwon.RenderProps; +import io.noties.markwon.SpanFactory; +import io.noties.markwon.test.TestSpan; +import io.noties.markwon.test.TestSpanMatcher; -import static ru.noties.markwon.test.TestSpan.args; -import static ru.noties.markwon.test.TestSpan.document; -import static ru.noties.markwon.test.TestSpan.span; -import static ru.noties.markwon.test.TestSpan.text; +import static io.noties.markwon.test.TestSpan.span; @RunWith(RobolectricTestRunner.class) @Config(manifest = Config.NONE) @@ -36,28 +33,28 @@ public class TaskListTest { @Test public void test() { - final TestSpan.Document document = document( - span(SPAN, args(IS_DONE, false), text("First")), + final TestSpan.Document document = TestSpan.document( + TestSpan.span(SPAN, TestSpan.args(IS_DONE, false), TestSpan.text("First")), newLine(), - span(SPAN, args(IS_DONE, true), text("Second")), + TestSpan.span(SPAN, TestSpan.args(IS_DONE, true), TestSpan.text("Second")), newLine(), - span(SPAN, args(IS_DONE, true), text("Third")), + TestSpan.span(SPAN, TestSpan.args(IS_DONE, true), TestSpan.text("Third")), newLine(), - span(SPAN, args(IS_DONE, false), text("First star")), + TestSpan.span(SPAN, TestSpan.args(IS_DONE, false), TestSpan.text("First star")), newLine(), - span(SPAN, args(IS_DONE, true), text("Second star")), + TestSpan.span(SPAN, TestSpan.args(IS_DONE, true), TestSpan.text("Second star")), newLine(), - span(SPAN, args(IS_DONE, true), text("Third star")), + TestSpan.span(SPAN, TestSpan.args(IS_DONE, true), TestSpan.text("Third star")), newLine(), - span(SPAN, args(IS_DONE, false), text("First plus")), + TestSpan.span(SPAN, TestSpan.args(IS_DONE, false), TestSpan.text("First plus")), newLine(), - span(SPAN, args(IS_DONE, true), text("Second plus")), + TestSpan.span(SPAN, TestSpan.args(IS_DONE, true), TestSpan.text("Second plus")), newLine(), - span(SPAN, args(IS_DONE, true), text("Third plus")), + TestSpan.span(SPAN, TestSpan.args(IS_DONE, true), TestSpan.text("Third plus")), newLine(), - span(SPAN, args(IS_DONE, true), text("Number with dot")), + TestSpan.span(SPAN, TestSpan.args(IS_DONE, true), TestSpan.text("Number with dot")), newLine(), - span(SPAN, args(IS_DONE, false), text("Number")) + TestSpan.span(SPAN, TestSpan.args(IS_DONE, false), TestSpan.text("Number")) ); TestSpanMatcher.matches( @@ -76,7 +73,7 @@ public class TaskListTest { builder.setFactory(TaskListItem.class, new SpanFactory() { @Override public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) { - return span(SPAN, args(IS_DONE, TaskListProps.DONE.require(props))); + return TestSpan.span(SPAN, TestSpan.args(IS_DONE, TaskListProps.DONE.require(props))); } }); } @@ -96,6 +93,6 @@ public class TaskListTest { @NonNull private static TestSpan.Text newLine() { - return text("\n"); + return TestSpan.text("\n"); } } diff --git a/markwon-html/src/main/AndroidManifest.xml b/markwon-html/src/main/AndroidManifest.xml index 6d886e0e..9eff536f 100644 --- a/markwon-html/src/main/AndroidManifest.xml +++ b/markwon-html/src/main/AndroidManifest.xml @@ -1 +1 @@ - + diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/AppendableUtils.java b/markwon-html/src/main/java/io/noties/markwon/html/AppendableUtils.java similarity index 96% rename from markwon-html/src/main/java/ru/noties/markwon/html/AppendableUtils.java rename to markwon-html/src/main/java/io/noties/markwon/html/AppendableUtils.java index 5e890174..29f25b83 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/AppendableUtils.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/AppendableUtils.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.html; +package io.noties.markwon.html; import android.support.annotation.NonNull; diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/CssInlineStyleParser.java b/markwon-html/src/main/java/io/noties/markwon/html/CssInlineStyleParser.java similarity index 99% rename from markwon-html/src/main/java/ru/noties/markwon/html/CssInlineStyleParser.java rename to markwon-html/src/main/java/io/noties/markwon/html/CssInlineStyleParser.java index c9d7c1fc..c06f396d 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/CssInlineStyleParser.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/CssInlineStyleParser.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.html; +package io.noties.markwon.html; import android.support.annotation.NonNull; import android.support.annotation.Nullable; diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/CssProperty.java b/markwon-html/src/main/java/io/noties/markwon/html/CssProperty.java similarity index 96% rename from markwon-html/src/main/java/ru/noties/markwon/html/CssProperty.java rename to markwon-html/src/main/java/io/noties/markwon/html/CssProperty.java index 70bc6d88..6805296e 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/CssProperty.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/CssProperty.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.html; +package io.noties.markwon.html; import android.support.annotation.NonNull; diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/HtmlEmptyTagReplacement.java b/markwon-html/src/main/java/io/noties/markwon/html/HtmlEmptyTagReplacement.java similarity index 98% rename from markwon-html/src/main/java/ru/noties/markwon/html/HtmlEmptyTagReplacement.java rename to markwon-html/src/main/java/io/noties/markwon/html/HtmlEmptyTagReplacement.java index c191b59d..416346e6 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/HtmlEmptyTagReplacement.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/HtmlEmptyTagReplacement.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.html; +package io.noties.markwon.html; import android.support.annotation.NonNull; import android.support.annotation.Nullable; diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/HtmlPlugin.java b/markwon-html/src/main/java/io/noties/markwon/html/HtmlPlugin.java similarity index 86% rename from markwon-html/src/main/java/ru/noties/markwon/html/HtmlPlugin.java rename to markwon-html/src/main/java/io/noties/markwon/html/HtmlPlugin.java index 8e437ac5..526fb323 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/HtmlPlugin.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/HtmlPlugin.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.html; +package io.noties.markwon.html; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -7,20 +7,20 @@ import org.commonmark.node.HtmlBlock; import org.commonmark.node.HtmlInline; import org.commonmark.node.Node; -import ru.noties.markwon.AbstractMarkwonPlugin; -import ru.noties.markwon.MarkwonConfiguration; -import ru.noties.markwon.MarkwonVisitor; -import ru.noties.markwon.html.tag.BlockquoteHandler; -import ru.noties.markwon.html.tag.EmphasisHandler; -import ru.noties.markwon.html.tag.HeadingHandler; -import ru.noties.markwon.html.tag.ImageHandler; -import ru.noties.markwon.html.tag.LinkHandler; -import ru.noties.markwon.html.tag.ListHandler; -import ru.noties.markwon.html.tag.StrikeHandler; -import ru.noties.markwon.html.tag.StrongEmphasisHandler; -import ru.noties.markwon.html.tag.SubScriptHandler; -import ru.noties.markwon.html.tag.SuperScriptHandler; -import ru.noties.markwon.html.tag.UnderlineHandler; +import io.noties.markwon.html.tag.ImageHandler; +import io.noties.markwon.AbstractMarkwonPlugin; +import io.noties.markwon.MarkwonConfiguration; +import io.noties.markwon.MarkwonVisitor; +import io.noties.markwon.html.tag.BlockquoteHandler; +import io.noties.markwon.html.tag.EmphasisHandler; +import io.noties.markwon.html.tag.HeadingHandler; +import io.noties.markwon.html.tag.LinkHandler; +import io.noties.markwon.html.tag.ListHandler; +import io.noties.markwon.html.tag.StrikeHandler; +import io.noties.markwon.html.tag.StrongEmphasisHandler; +import io.noties.markwon.html.tag.SubScriptHandler; +import io.noties.markwon.html.tag.SuperScriptHandler; +import io.noties.markwon.html.tag.UnderlineHandler; /** * @since 3.0.0 diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/HtmlTagImpl.java b/markwon-html/src/main/java/io/noties/markwon/html/HtmlTagImpl.java similarity index 99% rename from markwon-html/src/main/java/ru/noties/markwon/html/HtmlTagImpl.java rename to markwon-html/src/main/java/io/noties/markwon/html/HtmlTagImpl.java index 7c07360a..3dfb2c00 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/HtmlTagImpl.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/HtmlTagImpl.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.html; +package io.noties.markwon.html; import android.support.annotation.NonNull; import android.support.annotation.Nullable; diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/MarkwonHtmlParserImpl.java b/markwon-html/src/main/java/io/noties/markwon/html/MarkwonHtmlParserImpl.java similarity index 93% rename from markwon-html/src/main/java/ru/noties/markwon/html/MarkwonHtmlParserImpl.java rename to markwon-html/src/main/java/io/noties/markwon/html/MarkwonHtmlParserImpl.java index e0f4a9e3..ba0ce566 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/MarkwonHtmlParserImpl.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/MarkwonHtmlParserImpl.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.html; +package io.noties.markwon.html; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -14,16 +14,14 @@ import java.util.Locale; import java.util.Map; import java.util.Set; -import ru.noties.markwon.html.HtmlTag.Block; -import ru.noties.markwon.html.HtmlTag.Inline; -import ru.noties.markwon.html.jsoup.nodes.Attribute; -import ru.noties.markwon.html.jsoup.nodes.Attributes; -import ru.noties.markwon.html.jsoup.parser.CharacterReader; -import ru.noties.markwon.html.jsoup.parser.ParseErrorList; -import ru.noties.markwon.html.jsoup.parser.Token; -import ru.noties.markwon.html.jsoup.parser.Tokeniser; +import io.noties.markwon.html.jsoup.nodes.Attribute; +import io.noties.markwon.html.jsoup.nodes.Attributes; +import io.noties.markwon.html.jsoup.parser.CharacterReader; +import io.noties.markwon.html.jsoup.parser.ParseErrorList; +import io.noties.markwon.html.jsoup.parser.Token; +import io.noties.markwon.html.jsoup.parser.Tokeniser; -import static ru.noties.markwon.html.AppendableUtils.appendQuietly; +import static io.noties.markwon.html.AppendableUtils.appendQuietly; /** * @since 2.0.0 @@ -186,7 +184,7 @@ public class MarkwonHtmlParserImpl extends MarkwonHtmlParser { } @Override - public void flushInlineTags(int documentLength, @NonNull FlushAction action) { + public void flushInlineTags(int documentLength, @NonNull FlushAction action) { if (inlineTags.size() > 0) { if (documentLength > HtmlTag.NO_END) { @@ -195,15 +193,15 @@ public class MarkwonHtmlParserImpl extends MarkwonHtmlParser { } } - action.apply(Collections.unmodifiableList((List) inlineTags)); + action.apply(Collections.unmodifiableList((List) inlineTags)); inlineTags.clear(); } else { - action.apply(Collections.emptyList()); + action.apply(Collections.emptyList()); } } @Override - public void flushBlockTags(int documentLength, @NonNull FlushAction action) { + public void flushBlockTags(int documentLength, @NonNull FlushAction action) { HtmlTagImpl.BlockImpl block = currentBlock; while (block.parent != null) { @@ -214,11 +212,11 @@ public class MarkwonHtmlParserImpl extends MarkwonHtmlParser { block.closeAt(documentLength); } - final List children = block.children(); + final List children = block.children(); if (children.size() > 0) { action.apply(children); } else { - action.apply(Collections.emptyList()); + action.apply(Collections.emptyList()); } currentBlock = HtmlTagImpl.BlockImpl.root(); @@ -247,7 +245,7 @@ public class MarkwonHtmlParserImpl extends MarkwonHtmlParser { final String replacement = emptyTagReplacement.replace(inline); if (replacement != null && replacement.length() > 0) { - appendQuietly(output, replacement); + AppendableUtils.appendQuietly(output, replacement); } // the thing is: we will keep this inline tag in the list, @@ -292,7 +290,7 @@ public class MarkwonHtmlParserImpl extends MarkwonHtmlParser { // it must be closed here not matter what we are as here we _assume_ // that it's a block tag currentBlock.closeAt(output.length()); - appendQuietly(output, '\n'); + AppendableUtils.appendQuietly(output, '\n'); currentBlock = currentBlock.parent; } else if (TAG_LIST_ITEM.equals(name) && TAG_LIST_ITEM.equals(currentBlock.name)) { @@ -317,7 +315,7 @@ public class MarkwonHtmlParserImpl extends MarkwonHtmlParser { final String replacement = emptyTagReplacement.replace(block); if (replacement != null && replacement.length() > 0) { - appendQuietly(output, replacement); + AppendableUtils.appendQuietly(output, replacement); } block.closeAt(output.length()); } @@ -357,7 +355,7 @@ public class MarkwonHtmlParserImpl extends MarkwonHtmlParser { } if (TAG_PARAGRAPH.equals(name)) { - appendQuietly(output, '\n'); + AppendableUtils.appendQuietly(output, '\n'); } this.currentBlock = block.parent; @@ -441,7 +439,7 @@ public class MarkwonHtmlParserImpl extends MarkwonHtmlParser { final int length = output.length(); if (length > 0 && '\n' != output.charAt(length - 1)) { - appendQuietly(output, '\n'); + AppendableUtils.appendQuietly(output, '\n'); } } @@ -477,7 +475,7 @@ public class MarkwonHtmlParserImpl extends MarkwonHtmlParser { @NonNull HtmlTagImpl tag) { final String replacement = emptyTagReplacement.replace(tag); if (replacement != null) { - appendQuietly(output, replacement); + AppendableUtils.appendQuietly(output, replacement); } } } diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/MarkwonHtmlRendererImpl.java b/markwon-html/src/main/java/io/noties/markwon/html/MarkwonHtmlRendererImpl.java similarity index 98% rename from markwon-html/src/main/java/ru/noties/markwon/html/MarkwonHtmlRendererImpl.java rename to markwon-html/src/main/java/io/noties/markwon/html/MarkwonHtmlRendererImpl.java index dbde9035..fe3e1d97 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/MarkwonHtmlRendererImpl.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/MarkwonHtmlRendererImpl.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.html; +package io.noties.markwon.html; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -8,7 +8,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import ru.noties.markwon.MarkwonVisitor; +import io.noties.markwon.MarkwonVisitor; class MarkwonHtmlRendererImpl extends MarkwonHtmlRenderer { diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/TagHandlerNoOp.java b/markwon-html/src/main/java/io/noties/markwon/html/TagHandlerNoOp.java similarity index 92% rename from markwon-html/src/main/java/ru/noties/markwon/html/TagHandlerNoOp.java rename to markwon-html/src/main/java/io/noties/markwon/html/TagHandlerNoOp.java index c96d6867..944a10f9 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/TagHandlerNoOp.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/TagHandlerNoOp.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.html; +package io.noties.markwon.html; import android.support.annotation.NonNull; @@ -6,7 +6,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import ru.noties.markwon.MarkwonVisitor; +import io.noties.markwon.MarkwonVisitor; /** * @since 4.0.0-SNAPSHOT diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/TrimmingAppender.java b/markwon-html/src/main/java/io/noties/markwon/html/TrimmingAppender.java similarity index 95% rename from markwon-html/src/main/java/ru/noties/markwon/html/TrimmingAppender.java rename to markwon-html/src/main/java/io/noties/markwon/html/TrimmingAppender.java index 4f884b00..0115a531 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/TrimmingAppender.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/TrimmingAppender.java @@ -1,8 +1,8 @@ -package ru.noties.markwon.html; +package io.noties.markwon.html; import android.support.annotation.NonNull; -import static ru.noties.markwon.html.AppendableUtils.appendQuietly; +import static io.noties.markwon.html.AppendableUtils.appendQuietly; abstract class TrimmingAppender { diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/jsoup/UncheckedIOException.java b/markwon-html/src/main/java/io/noties/markwon/html/jsoup/UncheckedIOException.java similarity index 87% rename from markwon-html/src/main/java/ru/noties/markwon/html/jsoup/UncheckedIOException.java rename to markwon-html/src/main/java/io/noties/markwon/html/jsoup/UncheckedIOException.java index 9548bdf4..3a8f568b 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/jsoup/UncheckedIOException.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/jsoup/UncheckedIOException.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.html.jsoup; +package io.noties.markwon.html.jsoup; import java.io.IOException; diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/jsoup/helper/Normalizer.java b/markwon-html/src/main/java/io/noties/markwon/html/jsoup/helper/Normalizer.java similarity index 90% rename from markwon-html/src/main/java/ru/noties/markwon/html/jsoup/helper/Normalizer.java rename to markwon-html/src/main/java/io/noties/markwon/html/jsoup/helper/Normalizer.java index a0df7dd4..4bc3181a 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/jsoup/helper/Normalizer.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/jsoup/helper/Normalizer.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.html.jsoup.helper; +package io.noties.markwon.html.jsoup.helper; import java.util.Locale; diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/jsoup/helper/Validate.java b/markwon-html/src/main/java/io/noties/markwon/html/jsoup/helper/Validate.java similarity index 98% rename from markwon-html/src/main/java/ru/noties/markwon/html/jsoup/helper/Validate.java rename to markwon-html/src/main/java/io/noties/markwon/html/jsoup/helper/Validate.java index 0d00249b..171be48a 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/jsoup/helper/Validate.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/jsoup/helper/Validate.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.html.jsoup.helper; +package io.noties.markwon.html.jsoup.helper; /** * Simple validation methods. Designed for jsoup internal use diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/jsoup/nodes/Attribute.java b/markwon-html/src/main/java/io/noties/markwon/html/jsoup/nodes/Attribute.java similarity index 98% rename from markwon-html/src/main/java/ru/noties/markwon/html/jsoup/nodes/Attribute.java rename to markwon-html/src/main/java/io/noties/markwon/html/jsoup/nodes/Attribute.java index 934dc364..2ea27051 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/jsoup/nodes/Attribute.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/jsoup/nodes/Attribute.java @@ -1,8 +1,8 @@ -package ru.noties.markwon.html.jsoup.nodes; +package io.noties.markwon.html.jsoup.nodes; import java.util.Map; -import ru.noties.markwon.html.jsoup.helper.Validate; +import io.noties.markwon.html.jsoup.helper.Validate; /** A single key + value attribute. (Only used for presentation.) diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/jsoup/nodes/Attributes.java b/markwon-html/src/main/java/io/noties/markwon/html/jsoup/nodes/Attributes.java similarity index 98% rename from markwon-html/src/main/java/ru/noties/markwon/html/jsoup/nodes/Attributes.java rename to markwon-html/src/main/java/io/noties/markwon/html/jsoup/nodes/Attributes.java index ced993b0..1656a3c5 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/jsoup/nodes/Attributes.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/jsoup/nodes/Attributes.java @@ -1,11 +1,11 @@ -package ru.noties.markwon.html.jsoup.nodes; +package io.noties.markwon.html.jsoup.nodes; import java.util.Arrays; import java.util.Iterator; -import ru.noties.markwon.html.jsoup.helper.Validate; +import io.noties.markwon.html.jsoup.helper.Validate; -import static ru.noties.markwon.html.jsoup.helper.Normalizer.lowerCase; +import static io.noties.markwon.html.jsoup.helper.Normalizer.lowerCase; /** * The attributes of an Element. diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/jsoup/nodes/CommonMarkEntities.java b/markwon-html/src/main/java/io/noties/markwon/html/jsoup/nodes/CommonMarkEntities.java similarity index 97% rename from markwon-html/src/main/java/ru/noties/markwon/html/jsoup/nodes/CommonMarkEntities.java rename to markwon-html/src/main/java/io/noties/markwon/html/jsoup/nodes/CommonMarkEntities.java index ec362312..1bf8dca5 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/jsoup/nodes/CommonMarkEntities.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/jsoup/nodes/CommonMarkEntities.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.html.jsoup.nodes; +package io.noties.markwon.html.jsoup.nodes; import android.support.annotation.NonNull; diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/jsoup/nodes/DocumentType.java b/markwon-html/src/main/java/io/noties/markwon/html/jsoup/nodes/DocumentType.java similarity index 98% rename from markwon-html/src/main/java/ru/noties/markwon/html/jsoup/nodes/DocumentType.java rename to markwon-html/src/main/java/io/noties/markwon/html/jsoup/nodes/DocumentType.java index dc11e537..28e82f70 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/jsoup/nodes/DocumentType.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/jsoup/nodes/DocumentType.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.html.jsoup.nodes; +package io.noties.markwon.html.jsoup.nodes; /** * A {@code } node. diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/jsoup/parser/CharacterReader.java b/markwon-html/src/main/java/io/noties/markwon/html/jsoup/parser/CharacterReader.java similarity index 98% rename from markwon-html/src/main/java/ru/noties/markwon/html/jsoup/parser/CharacterReader.java rename to markwon-html/src/main/java/io/noties/markwon/html/jsoup/parser/CharacterReader.java index 1839cc2b..c9dc770f 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/jsoup/parser/CharacterReader.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/jsoup/parser/CharacterReader.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.html.jsoup.parser; +package io.noties.markwon.html.jsoup.parser; import java.io.IOException; import java.io.Reader; @@ -6,8 +6,8 @@ import java.io.StringReader; import java.util.Arrays; import java.util.Locale; -import ru.noties.markwon.html.jsoup.UncheckedIOException; -import ru.noties.markwon.html.jsoup.helper.Validate; +import io.noties.markwon.html.jsoup.UncheckedIOException; +import io.noties.markwon.html.jsoup.helper.Validate; /** * CharacterReader consumes tokens off a string. Used internally by jsoup. API subject to changes. diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/jsoup/parser/ParseError.java b/markwon-html/src/main/java/io/noties/markwon/html/jsoup/parser/ParseError.java similarity index 95% rename from markwon-html/src/main/java/ru/noties/markwon/html/jsoup/parser/ParseError.java rename to markwon-html/src/main/java/io/noties/markwon/html/jsoup/parser/ParseError.java index 533f9aee..bc97fcb3 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/jsoup/parser/ParseError.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/jsoup/parser/ParseError.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.html.jsoup.parser; +package io.noties.markwon.html.jsoup.parser; /** * A Parse Error records an error in the input HTML that occurs in either the tokenisation or the tree building phase. diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/jsoup/parser/ParseErrorList.java b/markwon-html/src/main/java/io/noties/markwon/html/jsoup/parser/ParseErrorList.java similarity index 94% rename from markwon-html/src/main/java/ru/noties/markwon/html/jsoup/parser/ParseErrorList.java rename to markwon-html/src/main/java/io/noties/markwon/html/jsoup/parser/ParseErrorList.java index a3e42a08..919c7b35 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/jsoup/parser/ParseErrorList.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/jsoup/parser/ParseErrorList.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.html.jsoup.parser; +package io.noties.markwon.html.jsoup.parser; import java.util.ArrayList; diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/jsoup/parser/Token.java b/markwon-html/src/main/java/io/noties/markwon/html/jsoup/parser/Token.java similarity index 98% rename from markwon-html/src/main/java/ru/noties/markwon/html/jsoup/parser/Token.java rename to markwon-html/src/main/java/io/noties/markwon/html/jsoup/parser/Token.java index 887cc61c..428186b5 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/jsoup/parser/Token.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/jsoup/parser/Token.java @@ -1,11 +1,11 @@ -package ru.noties.markwon.html.jsoup.parser; +package io.noties.markwon.html.jsoup.parser; import android.support.annotation.NonNull; -import ru.noties.markwon.html.jsoup.helper.Validate; -import ru.noties.markwon.html.jsoup.nodes.Attributes; +import io.noties.markwon.html.jsoup.helper.Validate; +import io.noties.markwon.html.jsoup.nodes.Attributes; -import static ru.noties.markwon.html.jsoup.helper.Normalizer.lowerCase; +import static io.noties.markwon.html.jsoup.helper.Normalizer.lowerCase; /** * Parse tokens for the Tokeniser. diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/jsoup/parser/Tokeniser.java b/markwon-html/src/main/java/io/noties/markwon/html/jsoup/parser/Tokeniser.java similarity index 98% rename from markwon-html/src/main/java/ru/noties/markwon/html/jsoup/parser/Tokeniser.java rename to markwon-html/src/main/java/io/noties/markwon/html/jsoup/parser/Tokeniser.java index 3b871776..786ab75a 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/jsoup/parser/Tokeniser.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/jsoup/parser/Tokeniser.java @@ -1,9 +1,9 @@ -package ru.noties.markwon.html.jsoup.parser; +package io.noties.markwon.html.jsoup.parser; import java.util.Arrays; -import ru.noties.markwon.html.jsoup.helper.Validate; -import ru.noties.markwon.html.jsoup.nodes.CommonMarkEntities; +import io.noties.markwon.html.jsoup.helper.Validate; +import io.noties.markwon.html.jsoup.nodes.CommonMarkEntities; /** * Readers the input stream into tokens. diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/jsoup/parser/TokeniserState.java b/markwon-html/src/main/java/io/noties/markwon/html/jsoup/parser/TokeniserState.java similarity index 99% rename from markwon-html/src/main/java/ru/noties/markwon/html/jsoup/parser/TokeniserState.java rename to markwon-html/src/main/java/io/noties/markwon/html/jsoup/parser/TokeniserState.java index 01a98958..f4b7bdb4 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/jsoup/parser/TokeniserState.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/jsoup/parser/TokeniserState.java @@ -1,6 +1,6 @@ -package ru.noties.markwon.html.jsoup.parser; +package io.noties.markwon.html.jsoup.parser; -import ru.noties.markwon.html.jsoup.nodes.DocumentType; +import io.noties.markwon.html.jsoup.nodes.DocumentType; /** * States and transition activations for the Tokeniser. diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/span/SubScriptSpan.java b/markwon-html/src/main/java/io/noties/markwon/html/span/SubScriptSpan.java similarity index 87% rename from markwon-html/src/main/java/ru/noties/markwon/html/span/SubScriptSpan.java rename to markwon-html/src/main/java/io/noties/markwon/html/span/SubScriptSpan.java index 5ab51160..8fa840ad 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/span/SubScriptSpan.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/span/SubScriptSpan.java @@ -1,10 +1,10 @@ -package ru.noties.markwon.html.span; +package io.noties.markwon.html.span; import android.support.annotation.NonNull; import android.text.TextPaint; import android.text.style.MetricAffectingSpan; -import ru.noties.markwon.html.HtmlPlugin; +import io.noties.markwon.html.HtmlPlugin; public class SubScriptSpan extends MetricAffectingSpan { diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/span/SuperScriptSpan.java b/markwon-html/src/main/java/io/noties/markwon/html/span/SuperScriptSpan.java similarity index 87% rename from markwon-html/src/main/java/ru/noties/markwon/html/span/SuperScriptSpan.java rename to markwon-html/src/main/java/io/noties/markwon/html/span/SuperScriptSpan.java index 7375309a..6c4d5247 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/span/SuperScriptSpan.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/span/SuperScriptSpan.java @@ -1,10 +1,10 @@ -package ru.noties.markwon.html.span; +package io.noties.markwon.html.span; import android.support.annotation.NonNull; import android.text.TextPaint; import android.text.style.MetricAffectingSpan; -import ru.noties.markwon.html.HtmlPlugin; +import io.noties.markwon.html.HtmlPlugin; public class SuperScriptSpan extends MetricAffectingSpan { diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/tag/BlockquoteHandler.java b/markwon-html/src/main/java/io/noties/markwon/html/tag/BlockquoteHandler.java similarity index 75% rename from markwon-html/src/main/java/ru/noties/markwon/html/tag/BlockquoteHandler.java rename to markwon-html/src/main/java/io/noties/markwon/html/tag/BlockquoteHandler.java index 31ed4916..ee8373c7 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/tag/BlockquoteHandler.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/tag/BlockquoteHandler.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.html.tag; +package io.noties.markwon.html.tag; import android.support.annotation.NonNull; @@ -7,13 +7,13 @@ import org.commonmark.node.BlockQuote; import java.util.Collection; import java.util.Collections; -import ru.noties.markwon.MarkwonConfiguration; -import ru.noties.markwon.MarkwonVisitor; -import ru.noties.markwon.SpanFactory; -import ru.noties.markwon.SpannableBuilder; -import ru.noties.markwon.html.HtmlTag; -import ru.noties.markwon.html.MarkwonHtmlRenderer; -import ru.noties.markwon.html.TagHandler; +import io.noties.markwon.html.HtmlTag; +import io.noties.markwon.html.MarkwonHtmlRenderer; +import io.noties.markwon.html.TagHandler; +import io.noties.markwon.MarkwonConfiguration; +import io.noties.markwon.MarkwonVisitor; +import io.noties.markwon.SpanFactory; +import io.noties.markwon.SpannableBuilder; public class BlockquoteHandler extends TagHandler { diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/tag/EmphasisHandler.java b/markwon-html/src/main/java/io/noties/markwon/html/tag/EmphasisHandler.java similarity index 80% rename from markwon-html/src/main/java/ru/noties/markwon/html/tag/EmphasisHandler.java rename to markwon-html/src/main/java/io/noties/markwon/html/tag/EmphasisHandler.java index a5e62c40..ff7c4e5e 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/tag/EmphasisHandler.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/tag/EmphasisHandler.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.html.tag; +package io.noties.markwon.html.tag; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -8,10 +8,10 @@ import org.commonmark.node.Emphasis; import java.util.Arrays; import java.util.Collection; -import ru.noties.markwon.MarkwonConfiguration; -import ru.noties.markwon.RenderProps; -import ru.noties.markwon.SpanFactory; -import ru.noties.markwon.html.HtmlTag; +import io.noties.markwon.html.HtmlTag; +import io.noties.markwon.MarkwonConfiguration; +import io.noties.markwon.RenderProps; +import io.noties.markwon.SpanFactory; public class EmphasisHandler extends SimpleTagHandler { @Nullable diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/tag/HeadingHandler.java b/markwon-html/src/main/java/io/noties/markwon/html/tag/HeadingHandler.java similarity index 82% rename from markwon-html/src/main/java/ru/noties/markwon/html/tag/HeadingHandler.java rename to markwon-html/src/main/java/io/noties/markwon/html/tag/HeadingHandler.java index 8c778f94..155a46fa 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/tag/HeadingHandler.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/tag/HeadingHandler.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.html.tag; +package io.noties.markwon.html.tag; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -8,11 +8,11 @@ import org.commonmark.node.Heading; import java.util.Arrays; import java.util.Collection; -import ru.noties.markwon.MarkwonConfiguration; -import ru.noties.markwon.RenderProps; -import ru.noties.markwon.SpanFactory; -import ru.noties.markwon.core.CoreProps; -import ru.noties.markwon.html.HtmlTag; +import io.noties.markwon.core.CoreProps; +import io.noties.markwon.html.HtmlTag; +import io.noties.markwon.MarkwonConfiguration; +import io.noties.markwon.RenderProps; +import io.noties.markwon.SpanFactory; public class HeadingHandler extends SimpleTagHandler { diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/tag/ImageHandler.java b/markwon-html/src/main/java/io/noties/markwon/html/tag/ImageHandler.java similarity index 86% rename from markwon-html/src/main/java/ru/noties/markwon/html/tag/ImageHandler.java rename to markwon-html/src/main/java/io/noties/markwon/html/tag/ImageHandler.java index 04cbe46e..e93c42cb 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/tag/ImageHandler.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/tag/ImageHandler.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.html.tag; +package io.noties.markwon.html.tag; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -10,13 +10,13 @@ import java.util.Collection; import java.util.Collections; import java.util.Map; -import ru.noties.markwon.MarkwonConfiguration; -import ru.noties.markwon.RenderProps; -import ru.noties.markwon.SpanFactory; -import ru.noties.markwon.html.CssInlineStyleParser; -import ru.noties.markwon.html.HtmlTag; -import ru.noties.markwon.image.ImageProps; -import ru.noties.markwon.image.ImageSize; +import io.noties.markwon.image.ImageSize; +import io.noties.markwon.MarkwonConfiguration; +import io.noties.markwon.RenderProps; +import io.noties.markwon.SpanFactory; +import io.noties.markwon.html.CssInlineStyleParser; +import io.noties.markwon.html.HtmlTag; +import io.noties.markwon.image.ImageProps; public class ImageHandler extends SimpleTagHandler { diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/tag/ImageSizeParserImpl.java b/markwon-html/src/main/java/io/noties/markwon/html/tag/ImageSizeParserImpl.java similarity index 94% rename from markwon-html/src/main/java/ru/noties/markwon/html/tag/ImageSizeParserImpl.java rename to markwon-html/src/main/java/io/noties/markwon/html/tag/ImageSizeParserImpl.java index 236f53be..69eb0412 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/tag/ImageSizeParserImpl.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/tag/ImageSizeParserImpl.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.html.tag; +package io.noties.markwon.html.tag; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -7,9 +7,9 @@ import android.text.TextUtils; import java.util.Map; -import ru.noties.markwon.html.CssInlineStyleParser; -import ru.noties.markwon.html.CssProperty; -import ru.noties.markwon.image.ImageSize; +import io.noties.markwon.html.CssInlineStyleParser; +import io.noties.markwon.html.CssProperty; +import io.noties.markwon.image.ImageSize; class ImageSizeParserImpl implements ImageHandler.ImageSizeParser { diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/tag/LinkHandler.java b/markwon-html/src/main/java/io/noties/markwon/html/tag/LinkHandler.java similarity index 81% rename from markwon-html/src/main/java/ru/noties/markwon/html/tag/LinkHandler.java rename to markwon-html/src/main/java/io/noties/markwon/html/tag/LinkHandler.java index a1687dd8..a3cd6084 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/tag/LinkHandler.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/tag/LinkHandler.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.html.tag; +package io.noties.markwon.html.tag; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -9,11 +9,11 @@ import org.commonmark.node.Link; import java.util.Collection; import java.util.Collections; -import ru.noties.markwon.MarkwonConfiguration; -import ru.noties.markwon.RenderProps; -import ru.noties.markwon.SpanFactory; -import ru.noties.markwon.core.CoreProps; -import ru.noties.markwon.html.HtmlTag; +import io.noties.markwon.core.CoreProps; +import io.noties.markwon.html.HtmlTag; +import io.noties.markwon.MarkwonConfiguration; +import io.noties.markwon.RenderProps; +import io.noties.markwon.SpanFactory; public class LinkHandler extends SimpleTagHandler { @Nullable diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/tag/ListHandler.java b/markwon-html/src/main/java/io/noties/markwon/html/tag/ListHandler.java similarity index 84% rename from markwon-html/src/main/java/ru/noties/markwon/html/tag/ListHandler.java rename to markwon-html/src/main/java/io/noties/markwon/html/tag/ListHandler.java index a8f8df9d..d214aaca 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/tag/ListHandler.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/tag/ListHandler.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.html.tag; +package io.noties.markwon.html.tag; import android.support.annotation.NonNull; @@ -7,15 +7,15 @@ import org.commonmark.node.ListItem; import java.util.Arrays; import java.util.Collection; -import ru.noties.markwon.MarkwonConfiguration; -import ru.noties.markwon.MarkwonVisitor; -import ru.noties.markwon.RenderProps; -import ru.noties.markwon.SpanFactory; -import ru.noties.markwon.SpannableBuilder; -import ru.noties.markwon.core.CoreProps; -import ru.noties.markwon.html.HtmlTag; -import ru.noties.markwon.html.MarkwonHtmlRenderer; -import ru.noties.markwon.html.TagHandler; +import io.noties.markwon.core.CoreProps; +import io.noties.markwon.html.HtmlTag; +import io.noties.markwon.html.MarkwonHtmlRenderer; +import io.noties.markwon.html.TagHandler; +import io.noties.markwon.MarkwonConfiguration; +import io.noties.markwon.MarkwonVisitor; +import io.noties.markwon.RenderProps; +import io.noties.markwon.SpanFactory; +import io.noties.markwon.SpannableBuilder; public class ListHandler extends TagHandler { diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/tag/SimpleTagHandler.java b/markwon-html/src/main/java/io/noties/markwon/html/tag/SimpleTagHandler.java similarity index 70% rename from markwon-html/src/main/java/ru/noties/markwon/html/tag/SimpleTagHandler.java rename to markwon-html/src/main/java/io/noties/markwon/html/tag/SimpleTagHandler.java index 94341b2f..bf0f141c 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/tag/SimpleTagHandler.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/tag/SimpleTagHandler.java @@ -1,17 +1,17 @@ -package ru.noties.markwon.html.tag; +package io.noties.markwon.html.tag; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import java.util.Collection; -import ru.noties.markwon.MarkwonConfiguration; -import ru.noties.markwon.MarkwonVisitor; -import ru.noties.markwon.RenderProps; -import ru.noties.markwon.SpannableBuilder; -import ru.noties.markwon.html.HtmlTag; -import ru.noties.markwon.html.MarkwonHtmlRenderer; -import ru.noties.markwon.html.TagHandler; +import io.noties.markwon.html.HtmlTag; +import io.noties.markwon.html.MarkwonHtmlRenderer; +import io.noties.markwon.html.TagHandler; +import io.noties.markwon.MarkwonConfiguration; +import io.noties.markwon.MarkwonVisitor; +import io.noties.markwon.RenderProps; +import io.noties.markwon.SpannableBuilder; public abstract class SimpleTagHandler extends TagHandler { diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/tag/StrikeHandler.java b/markwon-html/src/main/java/io/noties/markwon/html/tag/StrikeHandler.java similarity index 84% rename from markwon-html/src/main/java/ru/noties/markwon/html/tag/StrikeHandler.java rename to markwon-html/src/main/java/io/noties/markwon/html/tag/StrikeHandler.java index 02dedc8a..2715a8f5 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/tag/StrikeHandler.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/tag/StrikeHandler.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.html.tag; +package io.noties.markwon.html.tag; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -7,13 +7,13 @@ import android.text.style.StrikethroughSpan; import java.util.Arrays; import java.util.Collection; -import ru.noties.markwon.MarkwonConfiguration; -import ru.noties.markwon.MarkwonVisitor; -import ru.noties.markwon.SpanFactory; -import ru.noties.markwon.SpannableBuilder; -import ru.noties.markwon.html.HtmlTag; -import ru.noties.markwon.html.MarkwonHtmlRenderer; -import ru.noties.markwon.html.TagHandler; +import io.noties.markwon.html.HtmlTag; +import io.noties.markwon.html.MarkwonHtmlRenderer; +import io.noties.markwon.html.TagHandler; +import io.noties.markwon.MarkwonConfiguration; +import io.noties.markwon.MarkwonVisitor; +import io.noties.markwon.SpanFactory; +import io.noties.markwon.SpannableBuilder; public class StrikeHandler extends TagHandler { diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/tag/StrongEmphasisHandler.java b/markwon-html/src/main/java/io/noties/markwon/html/tag/StrongEmphasisHandler.java similarity index 80% rename from markwon-html/src/main/java/ru/noties/markwon/html/tag/StrongEmphasisHandler.java rename to markwon-html/src/main/java/io/noties/markwon/html/tag/StrongEmphasisHandler.java index 486e43c4..2a28ec7c 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/tag/StrongEmphasisHandler.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/tag/StrongEmphasisHandler.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.html.tag; +package io.noties.markwon.html.tag; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -8,10 +8,10 @@ import org.commonmark.node.StrongEmphasis; import java.util.Arrays; import java.util.Collection; -import ru.noties.markwon.MarkwonConfiguration; -import ru.noties.markwon.RenderProps; -import ru.noties.markwon.SpanFactory; -import ru.noties.markwon.html.HtmlTag; +import io.noties.markwon.html.HtmlTag; +import io.noties.markwon.MarkwonConfiguration; +import io.noties.markwon.RenderProps; +import io.noties.markwon.SpanFactory; public class StrongEmphasisHandler extends SimpleTagHandler { @Nullable diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/tag/SubScriptHandler.java b/markwon-html/src/main/java/io/noties/markwon/html/tag/SubScriptHandler.java similarity index 71% rename from markwon-html/src/main/java/ru/noties/markwon/html/tag/SubScriptHandler.java rename to markwon-html/src/main/java/io/noties/markwon/html/tag/SubScriptHandler.java index 5c99d963..cfcf77c5 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/tag/SubScriptHandler.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/tag/SubScriptHandler.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.html.tag; +package io.noties.markwon.html.tag; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -6,10 +6,10 @@ import android.support.annotation.Nullable; import java.util.Collection; import java.util.Collections; -import ru.noties.markwon.MarkwonConfiguration; -import ru.noties.markwon.RenderProps; -import ru.noties.markwon.html.HtmlTag; -import ru.noties.markwon.html.span.SubScriptSpan; +import io.noties.markwon.html.HtmlTag; +import io.noties.markwon.MarkwonConfiguration; +import io.noties.markwon.RenderProps; +import io.noties.markwon.html.span.SubScriptSpan; public class SubScriptHandler extends SimpleTagHandler { @Nullable diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/tag/SuperScriptHandler.java b/markwon-html/src/main/java/io/noties/markwon/html/tag/SuperScriptHandler.java similarity index 71% rename from markwon-html/src/main/java/ru/noties/markwon/html/tag/SuperScriptHandler.java rename to markwon-html/src/main/java/io/noties/markwon/html/tag/SuperScriptHandler.java index 163a1735..199350aa 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/tag/SuperScriptHandler.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/tag/SuperScriptHandler.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.html.tag; +package io.noties.markwon.html.tag; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -6,10 +6,10 @@ import android.support.annotation.Nullable; import java.util.Collection; import java.util.Collections; -import ru.noties.markwon.MarkwonConfiguration; -import ru.noties.markwon.RenderProps; -import ru.noties.markwon.html.HtmlTag; -import ru.noties.markwon.html.span.SuperScriptSpan; +import io.noties.markwon.html.HtmlTag; +import io.noties.markwon.MarkwonConfiguration; +import io.noties.markwon.RenderProps; +import io.noties.markwon.html.span.SuperScriptSpan; public class SuperScriptHandler extends SimpleTagHandler { @Nullable diff --git a/markwon-html/src/main/java/ru/noties/markwon/html/tag/UnderlineHandler.java b/markwon-html/src/main/java/io/noties/markwon/html/tag/UnderlineHandler.java similarity index 78% rename from markwon-html/src/main/java/ru/noties/markwon/html/tag/UnderlineHandler.java rename to markwon-html/src/main/java/io/noties/markwon/html/tag/UnderlineHandler.java index bc2be951..300cc69c 100644 --- a/markwon-html/src/main/java/ru/noties/markwon/html/tag/UnderlineHandler.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/tag/UnderlineHandler.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.html.tag; +package io.noties.markwon.html.tag; import android.support.annotation.NonNull; import android.text.style.UnderlineSpan; @@ -6,11 +6,11 @@ import android.text.style.UnderlineSpan; import java.util.Arrays; import java.util.Collection; -import ru.noties.markwon.MarkwonVisitor; -import ru.noties.markwon.SpannableBuilder; -import ru.noties.markwon.html.HtmlTag; -import ru.noties.markwon.html.MarkwonHtmlRenderer; -import ru.noties.markwon.html.TagHandler; +import io.noties.markwon.html.HtmlTag; +import io.noties.markwon.html.MarkwonHtmlRenderer; +import io.noties.markwon.html.TagHandler; +import io.noties.markwon.MarkwonVisitor; +import io.noties.markwon.SpannableBuilder; public class UnderlineHandler extends TagHandler { diff --git a/markwon-html/src/test/java/ru/noties/markwon/html/CssInlineStyleParserTest.java b/markwon-html/src/test/java/io/noties/markwon/html/CssInlineStyleParserTest.java similarity index 99% rename from markwon-html/src/test/java/ru/noties/markwon/html/CssInlineStyleParserTest.java rename to markwon-html/src/test/java/io/noties/markwon/html/CssInlineStyleParserTest.java index cc105137..88a45f14 100644 --- a/markwon-html/src/test/java/ru/noties/markwon/html/CssInlineStyleParserTest.java +++ b/markwon-html/src/test/java/io/noties/markwon/html/CssInlineStyleParserTest.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.html; +package io.noties.markwon.html; import android.support.annotation.NonNull; diff --git a/markwon-html/src/test/java/ru/noties/markwon/html/HtmlEmptyTagReplacementTest.java b/markwon-html/src/test/java/io/noties/markwon/html/HtmlEmptyTagReplacementTest.java similarity index 92% rename from markwon-html/src/test/java/ru/noties/markwon/html/HtmlEmptyTagReplacementTest.java rename to markwon-html/src/test/java/io/noties/markwon/html/HtmlEmptyTagReplacementTest.java index c54fab18..148564a2 100644 --- a/markwon-html/src/test/java/ru/noties/markwon/html/HtmlEmptyTagReplacementTest.java +++ b/markwon-html/src/test/java/io/noties/markwon/html/HtmlEmptyTagReplacementTest.java @@ -1,11 +1,11 @@ -package ru.noties.markwon.html; +package io.noties.markwon.html; import org.junit.Before; import org.junit.Test; import java.util.Collections; -import ru.noties.markwon.html.HtmlTagImpl.InlineImpl; +import io.noties.markwon.html.HtmlTagImpl.InlineImpl; import static org.junit.Assert.assertEquals; diff --git a/markwon-html/src/test/java/ru/noties/markwon/html/MarkwonHtmlParserImplTest.java b/markwon-html/src/test/java/io/noties/markwon/html/MarkwonHtmlParserImplTest.java similarity index 99% rename from markwon-html/src/test/java/ru/noties/markwon/html/MarkwonHtmlParserImplTest.java rename to markwon-html/src/test/java/io/noties/markwon/html/MarkwonHtmlParserImplTest.java index c614d36c..a2e0e7bd 100644 --- a/markwon-html/src/test/java/ru/noties/markwon/html/MarkwonHtmlParserImplTest.java +++ b/markwon-html/src/test/java/io/noties/markwon/html/MarkwonHtmlParserImplTest.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.html; +package io.noties.markwon.html; import android.support.annotation.NonNull; import android.support.annotation.Nullable; diff --git a/markwon-html/src/test/java/ru/noties/markwon/html/TrimmingAppenderTest.java b/markwon-html/src/test/java/io/noties/markwon/html/TrimmingAppenderTest.java similarity index 93% rename from markwon-html/src/test/java/ru/noties/markwon/html/TrimmingAppenderTest.java rename to markwon-html/src/test/java/io/noties/markwon/html/TrimmingAppenderTest.java index ef82795e..828f867b 100644 --- a/markwon-html/src/test/java/ru/noties/markwon/html/TrimmingAppenderTest.java +++ b/markwon-html/src/test/java/io/noties/markwon/html/TrimmingAppenderTest.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.html; +package io.noties.markwon.html; import org.junit.Before; import org.junit.Test; @@ -6,8 +6,6 @@ import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -import ru.noties.markwon.html.TrimmingAppender; - import static org.junit.Assert.assertEquals; @RunWith(RobolectricTestRunner.class) diff --git a/markwon-html/src/test/java/ru/noties/markwon/html/jsoup/nodes/CommonMarkEntitiesTest.java b/markwon-html/src/test/java/io/noties/markwon/html/jsoup/nodes/CommonMarkEntitiesTest.java similarity index 92% rename from markwon-html/src/test/java/ru/noties/markwon/html/jsoup/nodes/CommonMarkEntitiesTest.java rename to markwon-html/src/test/java/io/noties/markwon/html/jsoup/nodes/CommonMarkEntitiesTest.java index 3472d8d5..0cfbac5b 100644 --- a/markwon-html/src/test/java/ru/noties/markwon/html/jsoup/nodes/CommonMarkEntitiesTest.java +++ b/markwon-html/src/test/java/io/noties/markwon/html/jsoup/nodes/CommonMarkEntitiesTest.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.html.jsoup.nodes; +package io.noties.markwon.html.jsoup.nodes; import org.junit.Assert; import org.junit.Test; diff --git a/markwon-html/src/test/java/ru/noties/markwon/html/tag/ImageSizeParserImplTest.java b/markwon-html/src/test/java/io/noties/markwon/html/tag/ImageSizeParserImplTest.java similarity index 97% rename from markwon-html/src/test/java/ru/noties/markwon/html/tag/ImageSizeParserImplTest.java rename to markwon-html/src/test/java/io/noties/markwon/html/tag/ImageSizeParserImplTest.java index ffa9fdc6..daa5491e 100644 --- a/markwon-html/src/test/java/ru/noties/markwon/html/tag/ImageSizeParserImplTest.java +++ b/markwon-html/src/test/java/io/noties/markwon/html/tag/ImageSizeParserImplTest.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.html.tag; +package io.noties.markwon.html.tag; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -14,8 +14,8 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; -import ru.noties.markwon.html.CssInlineStyleParser; -import ru.noties.markwon.image.ImageSize; +import io.noties.markwon.image.ImageSize; +import io.noties.markwon.html.CssInlineStyleParser; @RunWith(RobolectricTestRunner.class) @Config(manifest = Config.NONE) diff --git a/markwon-image-glide/src/main/AndroidManifest.xml b/markwon-image-glide/src/main/AndroidManifest.xml index 806be809..2447b688 100644 --- a/markwon-image-glide/src/main/AndroidManifest.xml +++ b/markwon-image-glide/src/main/AndroidManifest.xml @@ -1 +1 @@ - + diff --git a/markwon-image-glide/src/main/java/ru/noties/markwon/image/glide/GlideImagesPlugin.java b/markwon-image-glide/src/main/java/io/noties/markwon/image/glide/GlideImagesPlugin.java similarity index 93% rename from markwon-image-glide/src/main/java/ru/noties/markwon/image/glide/GlideImagesPlugin.java rename to markwon-image-glide/src/main/java/io/noties/markwon/image/glide/GlideImagesPlugin.java index 2afa28f7..21d2bc55 100644 --- a/markwon-image-glide/src/main/java/ru/noties/markwon/image/glide/GlideImagesPlugin.java +++ b/markwon-image-glide/src/main/java/io/noties/markwon/image/glide/GlideImagesPlugin.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.image.glide; +package io.noties.markwon.image.glide; import android.content.Context; import android.graphics.drawable.Drawable; @@ -19,14 +19,14 @@ import org.commonmark.node.Image; import java.util.HashMap; import java.util.Map; -import ru.noties.markwon.AbstractMarkwonPlugin; -import ru.noties.markwon.MarkwonConfiguration; -import ru.noties.markwon.MarkwonSpansFactory; -import ru.noties.markwon.image.AsyncDrawable; -import ru.noties.markwon.image.AsyncDrawableLoader; -import ru.noties.markwon.image.AsyncDrawableScheduler; -import ru.noties.markwon.image.DrawableUtils; -import ru.noties.markwon.image.ImageSpanFactory; +import io.noties.markwon.image.AsyncDrawable; +import io.noties.markwon.image.AsyncDrawableScheduler; +import io.noties.markwon.AbstractMarkwonPlugin; +import io.noties.markwon.MarkwonConfiguration; +import io.noties.markwon.MarkwonSpansFactory; +import io.noties.markwon.image.AsyncDrawableLoader; +import io.noties.markwon.image.DrawableUtils; +import io.noties.markwon.image.ImageSpanFactory; /** * @since 4.0.0-SNAPSHOT diff --git a/markwon-image-picasso/src/main/AndroidManifest.xml b/markwon-image-picasso/src/main/AndroidManifest.xml index a32bdc6e..993a051e 100644 --- a/markwon-image-picasso/src/main/AndroidManifest.xml +++ b/markwon-image-picasso/src/main/AndroidManifest.xml @@ -1 +1 @@ - + diff --git a/markwon-image-picasso/src/main/java/ru/noties/markwon/image/picasso/PicassoImagesPlugin.java b/markwon-image-picasso/src/main/java/io/noties/markwon/image/picasso/PicassoImagesPlugin.java similarity index 92% rename from markwon-image-picasso/src/main/java/ru/noties/markwon/image/picasso/PicassoImagesPlugin.java rename to markwon-image-picasso/src/main/java/io/noties/markwon/image/picasso/PicassoImagesPlugin.java index 7bb37c1d..5d3fc7b5 100644 --- a/markwon-image-picasso/src/main/java/ru/noties/markwon/image/picasso/PicassoImagesPlugin.java +++ b/markwon-image-picasso/src/main/java/io/noties/markwon/image/picasso/PicassoImagesPlugin.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.image.picasso; +package io.noties.markwon.image.picasso; import android.content.Context; import android.content.res.Resources; @@ -19,14 +19,14 @@ import org.commonmark.node.Image; import java.util.HashMap; import java.util.Map; -import ru.noties.markwon.AbstractMarkwonPlugin; -import ru.noties.markwon.MarkwonConfiguration; -import ru.noties.markwon.MarkwonSpansFactory; -import ru.noties.markwon.image.AsyncDrawable; -import ru.noties.markwon.image.AsyncDrawableLoader; -import ru.noties.markwon.image.AsyncDrawableScheduler; -import ru.noties.markwon.image.DrawableUtils; -import ru.noties.markwon.image.ImageSpanFactory; +import io.noties.markwon.AbstractMarkwonPlugin; +import io.noties.markwon.MarkwonConfiguration; +import io.noties.markwon.MarkwonSpansFactory; +import io.noties.markwon.image.AsyncDrawable; +import io.noties.markwon.image.AsyncDrawableLoader; +import io.noties.markwon.image.AsyncDrawableScheduler; +import io.noties.markwon.image.DrawableUtils; +import io.noties.markwon.image.ImageSpanFactory; /** * @since 4.0.0-SNAPSHOT diff --git a/markwon-image/src/main/AndroidManifest.xml b/markwon-image/src/main/AndroidManifest.xml index e8b1253d..c7a58c74 100644 --- a/markwon-image/src/main/AndroidManifest.xml +++ b/markwon-image/src/main/AndroidManifest.xml @@ -1 +1 @@ - + diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderBuilder.java b/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderBuilder.java similarity index 95% rename from markwon-image/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderBuilder.java rename to markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderBuilder.java index 59de548f..7f8c0dcb 100644 --- a/markwon-image/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderBuilder.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderBuilder.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.image; +package io.noties.markwon.image; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -8,8 +8,8 @@ import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import ru.noties.markwon.image.data.DataUriSchemeHandler; -import ru.noties.markwon.image.network.NetworkSchemeHandler; +import io.noties.markwon.image.data.DataUriSchemeHandler; +import io.noties.markwon.image.network.NetworkSchemeHandler; class AsyncDrawableLoaderBuilder { diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderImpl.java b/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderImpl.java similarity index 98% rename from markwon-image/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderImpl.java rename to markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderImpl.java index 01b12282..c03529d7 100644 --- a/markwon-image/src/main/java/ru/noties/markwon/image/AsyncDrawableLoaderImpl.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderImpl.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.image; +package io.noties.markwon.image; import android.graphics.drawable.Drawable; import android.net.Uri; @@ -10,9 +10,7 @@ import android.support.annotation.Nullable; import android.support.annotation.VisibleForTesting; import android.util.Log; -import java.lang.ref.WeakReference; import java.util.HashMap; -import java.util.Iterator; import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/DefaultImageMediaDecoder.java b/markwon-image/src/main/java/io/noties/markwon/image/DefaultImageMediaDecoder.java similarity index 98% rename from markwon-image/src/main/java/ru/noties/markwon/image/DefaultImageMediaDecoder.java rename to markwon-image/src/main/java/io/noties/markwon/image/DefaultImageMediaDecoder.java index 8322f745..3aec554a 100644 --- a/markwon-image/src/main/java/ru/noties/markwon/image/DefaultImageMediaDecoder.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/DefaultImageMediaDecoder.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.image; +package io.noties.markwon.image; import android.content.res.Resources; import android.graphics.Bitmap; diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/ImageItem.java b/markwon-image/src/main/java/io/noties/markwon/image/ImageItem.java similarity index 99% rename from markwon-image/src/main/java/ru/noties/markwon/image/ImageItem.java rename to markwon-image/src/main/java/io/noties/markwon/image/ImageItem.java index df07e768..8e62e010 100644 --- a/markwon-image/src/main/java/ru/noties/markwon/image/ImageItem.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/ImageItem.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.image; +package io.noties.markwon.image; import android.graphics.drawable.Drawable; import android.support.annotation.NonNull; diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/ImagesPlugin.java b/markwon-image/src/main/java/io/noties/markwon/image/ImagesPlugin.java similarity index 84% rename from markwon-image/src/main/java/ru/noties/markwon/image/ImagesPlugin.java rename to markwon-image/src/main/java/io/noties/markwon/image/ImagesPlugin.java index ebb4cea0..4d7ad275 100644 --- a/markwon-image/src/main/java/ru/noties/markwon/image/ImagesPlugin.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/ImagesPlugin.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.image; +package io.noties.markwon.image; import android.graphics.drawable.Drawable; import android.support.annotation.NonNull; @@ -10,9 +10,16 @@ import org.commonmark.node.Image; import java.util.concurrent.ExecutorService; -import ru.noties.markwon.AbstractMarkwonPlugin; -import ru.noties.markwon.MarkwonConfiguration; -import ru.noties.markwon.MarkwonSpansFactory; +import io.noties.markwon.MarkwonPlugin; +import io.noties.markwon.image.data.DataUriSchemeHandler; +import io.noties.markwon.image.file.FileSchemeHandler; +import io.noties.markwon.image.gif.GifMediaDecoder; +import io.noties.markwon.image.network.NetworkSchemeHandler; +import io.noties.markwon.image.network.OkHttpNetworkSchemeHandler; +import io.noties.markwon.image.svg.SvgMediaDecoder; +import io.noties.markwon.AbstractMarkwonPlugin; +import io.noties.markwon.MarkwonConfiguration; +import io.noties.markwon.MarkwonSpansFactory; @SuppressWarnings({"UnusedReturnValue", "WeakerAccess"}) public class ImagesPlugin extends AbstractMarkwonPlugin { @@ -47,7 +54,7 @@ public class ImagesPlugin extends AbstractMarkwonPlugin { /** * Factory method to create an empty {@link ImagesPlugin} instance with no {@link SchemeHandler}s * nor {@link MediaDecoder}s registered. Can be used to further configure via instance methods or - * via {@link ru.noties.markwon.MarkwonPlugin#configure(Registry)} + * via {@link MarkwonPlugin#configure(Registry)} * * @see #create(ImagesConfigure) */ @@ -78,10 +85,10 @@ public class ImagesPlugin extends AbstractMarkwonPlugin { /** * @see SchemeHandler - * @see ru.noties.markwon.image.data.DataUriSchemeHandler - * @see ru.noties.markwon.image.file.FileSchemeHandler - * @see ru.noties.markwon.image.network.NetworkSchemeHandler - * @see ru.noties.markwon.image.network.OkHttpNetworkSchemeHandler + * @see DataUriSchemeHandler + * @see FileSchemeHandler + * @see NetworkSchemeHandler + * @see OkHttpNetworkSchemeHandler * @since 4.0.0-SNAPSHOT */ @NonNull @@ -92,8 +99,8 @@ public class ImagesPlugin extends AbstractMarkwonPlugin { /** * @see DefaultImageMediaDecoder - * @see ru.noties.markwon.image.svg.SvgMediaDecoder - * @see ru.noties.markwon.image.gif.GifMediaDecoder + * @see SvgMediaDecoder + * @see GifMediaDecoder * @since 4.0.0-SNAPSHOT */ @NonNull diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/MediaDecoder.java b/markwon-image/src/main/java/io/noties/markwon/image/MediaDecoder.java similarity index 95% rename from markwon-image/src/main/java/ru/noties/markwon/image/MediaDecoder.java rename to markwon-image/src/main/java/io/noties/markwon/image/MediaDecoder.java index 4470c50e..6f05bb20 100644 --- a/markwon-image/src/main/java/ru/noties/markwon/image/MediaDecoder.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/MediaDecoder.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.image; +package io.noties.markwon.image; import android.graphics.drawable.Drawable; import android.support.annotation.NonNull; diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/SchemeHandler.java b/markwon-image/src/main/java/io/noties/markwon/image/SchemeHandler.java similarity index 95% rename from markwon-image/src/main/java/ru/noties/markwon/image/SchemeHandler.java rename to markwon-image/src/main/java/io/noties/markwon/image/SchemeHandler.java index 32402136..d16ffc0e 100644 --- a/markwon-image/src/main/java/ru/noties/markwon/image/SchemeHandler.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/SchemeHandler.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.image; +package io.noties.markwon.image; import android.net.Uri; import android.support.annotation.NonNull; diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/data/DataUri.java b/markwon-image/src/main/java/io/noties/markwon/image/data/DataUri.java similarity index 97% rename from markwon-image/src/main/java/ru/noties/markwon/image/data/DataUri.java rename to markwon-image/src/main/java/io/noties/markwon/image/data/DataUri.java index 6e812c92..0d14bad9 100644 --- a/markwon-image/src/main/java/ru/noties/markwon/image/data/DataUri.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/data/DataUri.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.image.data; +package io.noties.markwon.image.data; import android.support.annotation.Nullable; diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/data/DataUriDecoder.java b/markwon-image/src/main/java/io/noties/markwon/image/data/DataUriDecoder.java similarity index 96% rename from markwon-image/src/main/java/ru/noties/markwon/image/data/DataUriDecoder.java rename to markwon-image/src/main/java/io/noties/markwon/image/data/DataUriDecoder.java index 929ff47d..e802cad2 100644 --- a/markwon-image/src/main/java/ru/noties/markwon/image/data/DataUriDecoder.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/data/DataUriDecoder.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.image.data; +package io.noties.markwon.image.data; import android.support.annotation.NonNull; import android.support.annotation.Nullable; diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/data/DataUriParser.java b/markwon-image/src/main/java/io/noties/markwon/image/data/DataUriParser.java similarity index 98% rename from markwon-image/src/main/java/ru/noties/markwon/image/data/DataUriParser.java rename to markwon-image/src/main/java/io/noties/markwon/image/data/DataUriParser.java index 0768ee4a..ad3311b2 100644 --- a/markwon-image/src/main/java/ru/noties/markwon/image/data/DataUriParser.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/data/DataUriParser.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.image.data; +package io.noties.markwon.image.data; import android.support.annotation.NonNull; import android.support.annotation.Nullable; diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/data/DataUriSchemeHandler.java b/markwon-image/src/main/java/io/noties/markwon/image/data/DataUriSchemeHandler.java similarity index 93% rename from markwon-image/src/main/java/ru/noties/markwon/image/data/DataUriSchemeHandler.java rename to markwon-image/src/main/java/io/noties/markwon/image/data/DataUriSchemeHandler.java index b5c8dcc4..6ba1cb33 100644 --- a/markwon-image/src/main/java/ru/noties/markwon/image/data/DataUriSchemeHandler.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/data/DataUriSchemeHandler.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.image.data; +package io.noties.markwon.image.data; import android.net.Uri; import android.support.annotation.NonNull; @@ -7,8 +7,8 @@ import java.io.ByteArrayInputStream; import java.util.Collection; import java.util.Collections; -import ru.noties.markwon.image.ImageItem; -import ru.noties.markwon.image.SchemeHandler; +import io.noties.markwon.image.ImageItem; +import io.noties.markwon.image.SchemeHandler; /** * @since 2.0.0 diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/file/FileSchemeHandler.java b/markwon-image/src/main/java/io/noties/markwon/image/file/FileSchemeHandler.java similarity index 93% rename from markwon-image/src/main/java/ru/noties/markwon/image/file/FileSchemeHandler.java rename to markwon-image/src/main/java/io/noties/markwon/image/file/FileSchemeHandler.java index f09906a1..257fcfe8 100644 --- a/markwon-image/src/main/java/ru/noties/markwon/image/file/FileSchemeHandler.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/file/FileSchemeHandler.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.image.file; +package io.noties.markwon.image.file; import android.content.Context; import android.content.res.AssetManager; @@ -18,8 +18,9 @@ import java.util.Collection; import java.util.Collections; import java.util.List; -import ru.noties.markwon.image.ImageItem; -import ru.noties.markwon.image.SchemeHandler; +import io.noties.markwon.urlprocessor.UrlProcessorAndroidAssets; +import io.noties.markwon.image.ImageItem; +import io.noties.markwon.image.SchemeHandler; /** * @since 3.0.0 @@ -29,7 +30,7 @@ public class FileSchemeHandler extends SchemeHandler { public static final String SCHEME = "file"; /** - * @see ru.noties.markwon.urlprocessor.UrlProcessorAndroidAssets + * @see UrlProcessorAndroidAssets */ @NonNull public static FileSchemeHandler createWithAssets(@NonNull AssetManager assetManager) { @@ -38,7 +39,7 @@ public class FileSchemeHandler extends SchemeHandler { /** * @see #createWithAssets(AssetManager) - * @see ru.noties.markwon.urlprocessor.UrlProcessorAndroidAssets + * @see UrlProcessorAndroidAssets * @since 4.0.0-SNAPSHOT */ @NonNull diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/gif/GifMediaDecoder.java b/markwon-image/src/main/java/io/noties/markwon/image/gif/GifMediaDecoder.java similarity index 95% rename from markwon-image/src/main/java/ru/noties/markwon/image/gif/GifMediaDecoder.java rename to markwon-image/src/main/java/io/noties/markwon/image/gif/GifMediaDecoder.java index 200be994..d8757df4 100644 --- a/markwon-image/src/main/java/ru/noties/markwon/image/gif/GifMediaDecoder.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/gif/GifMediaDecoder.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.image.gif; +package io.noties.markwon.image.gif; import android.graphics.drawable.Drawable; import android.support.annotation.NonNull; @@ -10,9 +10,9 @@ import java.io.InputStream; import java.util.Collection; import java.util.Collections; +import io.noties.markwon.image.MediaDecoder; import pl.droidsonroids.gif.GifDrawable; -import ru.noties.markwon.image.DrawableUtils; -import ru.noties.markwon.image.MediaDecoder; +import io.noties.markwon.image.DrawableUtils; /** * @since 1.1.0 diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/network/NetworkSchemeHandler.java b/markwon-image/src/main/java/io/noties/markwon/image/network/NetworkSchemeHandler.java similarity index 94% rename from markwon-image/src/main/java/ru/noties/markwon/image/network/NetworkSchemeHandler.java rename to markwon-image/src/main/java/io/noties/markwon/image/network/NetworkSchemeHandler.java index 920fa4c1..03c015e3 100644 --- a/markwon-image/src/main/java/ru/noties/markwon/image/network/NetworkSchemeHandler.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/network/NetworkSchemeHandler.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.image.network; +package io.noties.markwon.image.network; import android.net.Uri; import android.support.annotation.NonNull; @@ -12,8 +12,8 @@ import java.net.URL; import java.util.Arrays; import java.util.Collection; -import ru.noties.markwon.image.ImageItem; -import ru.noties.markwon.image.SchemeHandler; +import io.noties.markwon.image.ImageItem; +import io.noties.markwon.image.SchemeHandler; /** * A simple network scheme handler that is not dependent on any external libraries. diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/network/OkHttpNetworkSchemeHandler.java b/markwon-image/src/main/java/io/noties/markwon/image/network/OkHttpNetworkSchemeHandler.java similarity index 95% rename from markwon-image/src/main/java/ru/noties/markwon/image/network/OkHttpNetworkSchemeHandler.java rename to markwon-image/src/main/java/io/noties/markwon/image/network/OkHttpNetworkSchemeHandler.java index b470841d..5203d23a 100644 --- a/markwon-image/src/main/java/ru/noties/markwon/image/network/OkHttpNetworkSchemeHandler.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/network/OkHttpNetworkSchemeHandler.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.image.network; +package io.noties.markwon.image.network; import android.net.Uri; import android.support.annotation.NonNull; @@ -7,13 +7,13 @@ import java.io.InputStream; import java.util.Arrays; import java.util.Collection; +import io.noties.markwon.image.ImageItem; +import io.noties.markwon.image.SchemeHandler; import okhttp3.Call; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; import okhttp3.ResponseBody; -import ru.noties.markwon.image.ImageItem; -import ru.noties.markwon.image.SchemeHandler; /** * @since 4.0.0-SNAPSHOT diff --git a/markwon-image/src/main/java/ru/noties/markwon/image/svg/SvgMediaDecoder.java b/markwon-image/src/main/java/io/noties/markwon/image/svg/SvgMediaDecoder.java similarity index 95% rename from markwon-image/src/main/java/ru/noties/markwon/image/svg/SvgMediaDecoder.java rename to markwon-image/src/main/java/io/noties/markwon/image/svg/SvgMediaDecoder.java index 78d381a8..229899c2 100644 --- a/markwon-image/src/main/java/ru/noties/markwon/image/svg/SvgMediaDecoder.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/svg/SvgMediaDecoder.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.image.svg; +package io.noties.markwon.image.svg; import android.content.res.Resources; import android.graphics.Bitmap; @@ -15,8 +15,8 @@ import java.io.InputStream; import java.util.Collection; import java.util.Collections; -import ru.noties.markwon.image.DrawableUtils; -import ru.noties.markwon.image.MediaDecoder; +import io.noties.markwon.image.MediaDecoder; +import io.noties.markwon.image.DrawableUtils; /** * @since 1.1.0 diff --git a/markwon-image/src/test/java/ru/noties/markwon/image/AsyncDrawableLoaderBuilderTest.java b/markwon-image/src/test/java/io/noties/markwon/image/AsyncDrawableLoaderBuilderTest.java similarity index 97% rename from markwon-image/src/test/java/ru/noties/markwon/image/AsyncDrawableLoaderBuilderTest.java rename to markwon-image/src/test/java/io/noties/markwon/image/AsyncDrawableLoaderBuilderTest.java index b2400a37..e08328d2 100644 --- a/markwon-image/src/test/java/ru/noties/markwon/image/AsyncDrawableLoaderBuilderTest.java +++ b/markwon-image/src/test/java/io/noties/markwon/image/AsyncDrawableLoaderBuilderTest.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.image; +package io.noties.markwon.image; import org.junit.Before; import org.junit.Test; @@ -10,8 +10,8 @@ import java.util.Arrays; import java.util.Collections; import java.util.concurrent.ExecutorService; -import ru.noties.markwon.image.data.DataUriSchemeHandler; -import ru.noties.markwon.image.network.NetworkSchemeHandler; +import io.noties.markwon.image.network.NetworkSchemeHandler; +import io.noties.markwon.image.data.DataUriSchemeHandler; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; diff --git a/markwon-image/src/test/java/ru/noties/markwon/image/AsyncDrawableLoaderImplTest.java b/markwon-image/src/test/java/io/noties/markwon/image/AsyncDrawableLoaderImplTest.java similarity index 98% rename from markwon-image/src/test/java/ru/noties/markwon/image/AsyncDrawableLoaderImplTest.java rename to markwon-image/src/test/java/io/noties/markwon/image/AsyncDrawableLoaderImplTest.java index 80e2bf53..2737fcc6 100644 --- a/markwon-image/src/test/java/ru/noties/markwon/image/AsyncDrawableLoaderImplTest.java +++ b/markwon-image/src/test/java/io/noties/markwon/image/AsyncDrawableLoaderImplTest.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.image; +package io.noties.markwon.image; import android.os.Handler; import android.support.annotation.NonNull; diff --git a/markwon-image/src/test/java/ru/noties/markwon/image/ImagesPluginTest.java b/markwon-image/src/test/java/io/noties/markwon/image/ImagesPluginTest.java similarity index 92% rename from markwon-image/src/test/java/ru/noties/markwon/image/ImagesPluginTest.java rename to markwon-image/src/test/java/io/noties/markwon/image/ImagesPluginTest.java index e141d456..20e7feb5 100644 --- a/markwon-image/src/test/java/ru/noties/markwon/image/ImagesPluginTest.java +++ b/markwon-image/src/test/java/io/noties/markwon/image/ImagesPluginTest.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.image; +package io.noties.markwon.image; import android.support.annotation.NonNull; import android.text.Spanned; @@ -9,15 +9,17 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import org.mockito.ArgumentMatchers; import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; import java.util.concurrent.ExecutorService; -import ru.noties.markwon.MarkwonConfiguration; -import ru.noties.markwon.MarkwonSpansFactory; -import ru.noties.markwon.SpanFactory; -import ru.noties.markwon.image.data.DataUriSchemeHandler; +import io.noties.markwon.MarkwonConfiguration; +import io.noties.markwon.MarkwonSpansFactory; +import io.noties.markwon.SpanFactory; +import ru.noties.markwon.image.R; +import io.noties.markwon.image.data.DataUriSchemeHandler; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @@ -159,7 +161,7 @@ public class ImagesPluginTest { plugin.beforeSetText(textView, mock(Spanned.class)); verify(textView, times(1)) - .getTag(eq(R.id.markwon_drawables_scheduler_last_text_hashcode)); + .getTag(ArgumentMatchers.eq(R.id.markwon_drawables_scheduler_last_text_hashcode)); } @Test diff --git a/markwon-image/src/test/java/ru/noties/markwon/image/data/DataUriParserTest.java b/markwon-image/src/test/java/io/noties/markwon/image/data/DataUriParserTest.java similarity index 98% rename from markwon-image/src/test/java/ru/noties/markwon/image/data/DataUriParserTest.java rename to markwon-image/src/test/java/io/noties/markwon/image/data/DataUriParserTest.java index b361a0d3..d8bda4b3 100644 --- a/markwon-image/src/test/java/ru/noties/markwon/image/data/DataUriParserTest.java +++ b/markwon-image/src/test/java/io/noties/markwon/image/data/DataUriParserTest.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.image.data; +package io.noties.markwon.image.data; import org.junit.Before; import org.junit.Test; diff --git a/markwon-image/src/test/java/ru/noties/markwon/image/data/DataUriSchemeHandlerTest.java b/markwon-image/src/test/java/io/noties/markwon/image/data/DataUriSchemeHandlerTest.java similarity index 97% rename from markwon-image/src/test/java/ru/noties/markwon/image/data/DataUriSchemeHandlerTest.java rename to markwon-image/src/test/java/io/noties/markwon/image/data/DataUriSchemeHandlerTest.java index 6cb64cd2..58d9ffd2 100644 --- a/markwon-image/src/test/java/ru/noties/markwon/image/data/DataUriSchemeHandlerTest.java +++ b/markwon-image/src/test/java/io/noties/markwon/image/data/DataUriSchemeHandlerTest.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.image.data; +package io.noties.markwon.image.data; import android.net.Uri; import android.support.annotation.NonNull; @@ -14,7 +14,7 @@ import java.util.HashMap; import java.util.Map; import java.util.Scanner; -import ru.noties.markwon.image.ImageItem; +import io.noties.markwon.image.ImageItem; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; diff --git a/markwon-linkify/src/main/AndroidManifest.xml b/markwon-linkify/src/main/AndroidManifest.xml index 3a9ba865..28afaae4 100644 --- a/markwon-linkify/src/main/AndroidManifest.xml +++ b/markwon-linkify/src/main/AndroidManifest.xml @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/markwon-linkify/src/main/java/ru/noties/markwon/linkify/LinkifyPlugin.java b/markwon-linkify/src/main/java/io/noties/markwon/linkify/LinkifyPlugin.java similarity index 92% rename from markwon-linkify/src/main/java/ru/noties/markwon/linkify/LinkifyPlugin.java rename to markwon-linkify/src/main/java/io/noties/markwon/linkify/LinkifyPlugin.java index b24f3b49..05098dcf 100644 --- a/markwon-linkify/src/main/java/ru/noties/markwon/linkify/LinkifyPlugin.java +++ b/markwon-linkify/src/main/java/io/noties/markwon/linkify/LinkifyPlugin.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.linkify; +package io.noties.markwon.linkify; import android.support.annotation.IntDef; import android.support.annotation.NonNull; @@ -8,10 +8,10 @@ import android.text.util.Linkify; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import ru.noties.markwon.AbstractMarkwonPlugin; -import ru.noties.markwon.MarkwonVisitor; -import ru.noties.markwon.SpannableBuilder; -import ru.noties.markwon.core.CorePlugin; +import io.noties.markwon.AbstractMarkwonPlugin; +import io.noties.markwon.MarkwonVisitor; +import io.noties.markwon.SpannableBuilder; +import io.noties.markwon.core.CorePlugin; public class LinkifyPlugin extends AbstractMarkwonPlugin { diff --git a/markwon-recycler-table/src/main/AndroidManifest.xml b/markwon-recycler-table/src/main/AndroidManifest.xml index b215e1f6..da5aced9 100644 --- a/markwon-recycler-table/src/main/AndroidManifest.xml +++ b/markwon-recycler-table/src/main/AndroidManifest.xml @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/markwon-recycler-table/src/main/java/ru/noties/markwon/recycler/table/TableBorderDrawable.java b/markwon-recycler-table/src/main/java/io/noties/markwon/recycler/table/TableBorderDrawable.java similarity index 96% rename from markwon-recycler-table/src/main/java/ru/noties/markwon/recycler/table/TableBorderDrawable.java rename to markwon-recycler-table/src/main/java/io/noties/markwon/recycler/table/TableBorderDrawable.java index 06a89f24..e78dbd84 100644 --- a/markwon-recycler-table/src/main/java/ru/noties/markwon/recycler/table/TableBorderDrawable.java +++ b/markwon-recycler-table/src/main/java/io/noties/markwon/recycler/table/TableBorderDrawable.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.recycler.table; +package io.noties.markwon.recycler.table; import android.graphics.Canvas; import android.graphics.ColorFilter; diff --git a/markwon-recycler-table/src/main/java/ru/noties/markwon/recycler/table/TableEntry.java b/markwon-recycler-table/src/main/java/io/noties/markwon/recycler/table/TableEntry.java similarity index 98% rename from markwon-recycler-table/src/main/java/ru/noties/markwon/recycler/table/TableEntry.java rename to markwon-recycler-table/src/main/java/io/noties/markwon/recycler/table/TableEntry.java index 5ff8b25e..01190f29 100644 --- a/markwon-recycler-table/src/main/java/ru/noties/markwon/recycler/table/TableEntry.java +++ b/markwon-recycler-table/src/main/java/io/noties/markwon/recycler/table/TableEntry.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.recycler.table; +package io.noties.markwon.recycler.table; import android.annotation.SuppressLint; import android.content.Context; @@ -24,10 +24,10 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import ru.noties.markwon.Markwon; -import ru.noties.markwon.ext.tables.Table; -import ru.noties.markwon.recycler.MarkwonAdapter; -import ru.noties.markwon.utils.NoCopySpannableFactory; +import io.noties.markwon.recycler.MarkwonAdapter; +import io.noties.markwon.utils.NoCopySpannableFactory; +import io.noties.markwon.Markwon; +import io.noties.markwon.ext.tables.Table; /** * @since 3.0.0 diff --git a/markwon-recycler-table/src/main/java/ru/noties/markwon/recycler/table/TableEntryPlugin.java b/markwon-recycler-table/src/main/java/io/noties/markwon/recycler/table/TableEntryPlugin.java similarity index 86% rename from markwon-recycler-table/src/main/java/ru/noties/markwon/recycler/table/TableEntryPlugin.java rename to markwon-recycler-table/src/main/java/io/noties/markwon/recycler/table/TableEntryPlugin.java index a92400ee..0a339c3a 100644 --- a/markwon-recycler-table/src/main/java/ru/noties/markwon/recycler/table/TableEntryPlugin.java +++ b/markwon-recycler-table/src/main/java/io/noties/markwon/recycler/table/TableEntryPlugin.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.recycler.table; +package io.noties.markwon.recycler.table; import android.content.Context; import android.support.annotation.NonNull; @@ -8,12 +8,12 @@ import org.commonmark.parser.Parser; import java.util.Collections; -import ru.noties.markwon.AbstractMarkwonPlugin; -import ru.noties.markwon.ext.tables.TablePlugin; -import ru.noties.markwon.ext.tables.TableTheme; +import io.noties.markwon.AbstractMarkwonPlugin; +import io.noties.markwon.ext.tables.TablePlugin; +import io.noties.markwon.ext.tables.TableTheme; /** - * This plugin must be used instead of {@link ru.noties.markwon.ext.tables.TablePlugin} when a markdown + * This plugin must be used instead of {@link TablePlugin} when a markdown * table is intended to be used in a RecyclerView via {@link TableEntry}. This is required * because TablePlugin additionally processes markdown tables to be displayed in limited * context of a TextView. If TablePlugin will be used, {@link TableEntry} will display table, diff --git a/markwon-recycler-table/src/main/java/ru/noties/markwon/recycler/table/TableEntryTheme.java b/markwon-recycler-table/src/main/java/io/noties/markwon/recycler/table/TableEntryTheme.java similarity index 92% rename from markwon-recycler-table/src/main/java/ru/noties/markwon/recycler/table/TableEntryTheme.java rename to markwon-recycler-table/src/main/java/io/noties/markwon/recycler/table/TableEntryTheme.java index e9b9b7ca..9164bd12 100644 --- a/markwon-recycler-table/src/main/java/ru/noties/markwon/recycler/table/TableEntryTheme.java +++ b/markwon-recycler-table/src/main/java/io/noties/markwon/recycler/table/TableEntryTheme.java @@ -1,12 +1,12 @@ -package ru.noties.markwon.recycler.table; +package io.noties.markwon.recycler.table; import android.graphics.Paint; import android.support.annotation.ColorInt; import android.support.annotation.NonNull; import android.support.annotation.Px; -import ru.noties.markwon.ext.tables.TableTheme; -import ru.noties.markwon.utils.ColorUtils; +import io.noties.markwon.utils.ColorUtils; +import io.noties.markwon.ext.tables.TableTheme; /** * Mimics TableTheme to allow uniform table customization diff --git a/markwon-recycler-table/src/test/java/ru/noties/markwon/recycler/table/TableEntryTest.java b/markwon-recycler-table/src/test/java/io/noties/markwon/recycler/table/TableEntryTest.java similarity index 97% rename from markwon-recycler-table/src/test/java/ru/noties/markwon/recycler/table/TableEntryTest.java rename to markwon-recycler-table/src/test/java/io/noties/markwon/recycler/table/TableEntryTest.java index ae55f18e..e7c89bd5 100644 --- a/markwon-recycler-table/src/test/java/ru/noties/markwon/recycler/table/TableEntryTest.java +++ b/markwon-recycler-table/src/test/java/io/noties/markwon/recycler/table/TableEntryTest.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.recycler.table; +package io.noties.markwon.recycler.table; import android.content.res.Resources; import android.util.Pair; @@ -14,7 +14,7 @@ import org.robolectric.annotation.Config; import java.util.Arrays; import java.util.List; -import ru.noties.markwon.ext.tables.Table; +import io.noties.markwon.ext.tables.Table; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; diff --git a/markwon-recycler/src/main/AndroidManifest.xml b/markwon-recycler/src/main/AndroidManifest.xml index 4af698d1..8373a44c 100644 --- a/markwon-recycler/src/main/AndroidManifest.xml +++ b/markwon-recycler/src/main/AndroidManifest.xml @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/markwon-recycler/src/main/java/ru/noties/markwon/recycler/MarkwonAdapter.java b/markwon-recycler/src/main/java/io/noties/markwon/recycler/MarkwonAdapter.java similarity index 98% rename from markwon-recycler/src/main/java/ru/noties/markwon/recycler/MarkwonAdapter.java rename to markwon-recycler/src/main/java/io/noties/markwon/recycler/MarkwonAdapter.java index 64241d55..99894ddd 100644 --- a/markwon-recycler/src/main/java/ru/noties/markwon/recycler/MarkwonAdapter.java +++ b/markwon-recycler/src/main/java/io/noties/markwon/recycler/MarkwonAdapter.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.recycler; +package io.noties.markwon.recycler; import android.support.annotation.IdRes; import android.support.annotation.LayoutRes; @@ -13,8 +13,8 @@ import org.commonmark.node.Node; import java.util.List; -import ru.noties.markwon.Markwon; -import ru.noties.markwon.MarkwonReducer; +import io.noties.markwon.Markwon; +import io.noties.markwon.MarkwonReducer; /** * Adapter to display markdown in a RecyclerView. It is done by extracting root blocks from a diff --git a/markwon-recycler/src/main/java/ru/noties/markwon/recycler/MarkwonAdapterImpl.java b/markwon-recycler/src/main/java/io/noties/markwon/recycler/MarkwonAdapterImpl.java similarity index 97% rename from markwon-recycler/src/main/java/ru/noties/markwon/recycler/MarkwonAdapterImpl.java rename to markwon-recycler/src/main/java/io/noties/markwon/recycler/MarkwonAdapterImpl.java index 30b093f5..ea7c34d2 100644 --- a/markwon-recycler/src/main/java/ru/noties/markwon/recycler/MarkwonAdapterImpl.java +++ b/markwon-recycler/src/main/java/io/noties/markwon/recycler/MarkwonAdapterImpl.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.recycler; +package io.noties.markwon.recycler; import android.support.annotation.NonNull; import android.util.SparseArray; @@ -10,8 +10,8 @@ import org.commonmark.node.Node; import java.util.Collections; import java.util.List; -import ru.noties.markwon.Markwon; -import ru.noties.markwon.MarkwonReducer; +import io.noties.markwon.Markwon; +import io.noties.markwon.MarkwonReducer; class MarkwonAdapterImpl extends MarkwonAdapter { diff --git a/markwon-recycler/src/main/java/ru/noties/markwon/recycler/SimpleEntry.java b/markwon-recycler/src/main/java/io/noties/markwon/recycler/SimpleEntry.java similarity index 95% rename from markwon-recycler/src/main/java/ru/noties/markwon/recycler/SimpleEntry.java rename to markwon-recycler/src/main/java/io/noties/markwon/recycler/SimpleEntry.java index 93ef0d30..a876597a 100644 --- a/markwon-recycler/src/main/java/ru/noties/markwon/recycler/SimpleEntry.java +++ b/markwon-recycler/src/main/java/io/noties/markwon/recycler/SimpleEntry.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.recycler; +package io.noties.markwon.recycler; import android.support.annotation.IdRes; import android.support.annotation.LayoutRes; @@ -14,8 +14,8 @@ import org.commonmark.node.Node; import java.util.HashMap; import java.util.Map; -import ru.noties.markwon.Markwon; -import ru.noties.markwon.utils.NoCopySpannableFactory; +import io.noties.markwon.Markwon; +import io.noties.markwon.utils.NoCopySpannableFactory; /** * @since 3.0.0 diff --git a/markwon-syntax-highlight/src/main/AndroidManifest.xml b/markwon-syntax-highlight/src/main/AndroidManifest.xml index e758e4c1..318afcd8 100644 --- a/markwon-syntax-highlight/src/main/AndroidManifest.xml +++ b/markwon-syntax-highlight/src/main/AndroidManifest.xml @@ -1 +1 @@ - + diff --git a/markwon-syntax-highlight/src/main/java/ru/noties/markwon/syntax/Prism4jSyntaxHighlight.java b/markwon-syntax-highlight/src/main/java/io/noties/markwon/syntax/Prism4jSyntaxHighlight.java similarity index 98% rename from markwon-syntax-highlight/src/main/java/ru/noties/markwon/syntax/Prism4jSyntaxHighlight.java rename to markwon-syntax-highlight/src/main/java/io/noties/markwon/syntax/Prism4jSyntaxHighlight.java index bb016796..a36a0170 100644 --- a/markwon-syntax-highlight/src/main/java/ru/noties/markwon/syntax/Prism4jSyntaxHighlight.java +++ b/markwon-syntax-highlight/src/main/java/io/noties/markwon/syntax/Prism4jSyntaxHighlight.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.syntax; +package io.noties.markwon.syntax; import android.support.annotation.NonNull; import android.support.annotation.Nullable; diff --git a/markwon-syntax-highlight/src/main/java/ru/noties/markwon/syntax/Prism4jSyntaxVisitor.java b/markwon-syntax-highlight/src/main/java/io/noties/markwon/syntax/Prism4jSyntaxVisitor.java similarity index 96% rename from markwon-syntax-highlight/src/main/java/ru/noties/markwon/syntax/Prism4jSyntaxVisitor.java rename to markwon-syntax-highlight/src/main/java/io/noties/markwon/syntax/Prism4jSyntaxVisitor.java index cd7f2f04..9fd14435 100644 --- a/markwon-syntax-highlight/src/main/java/ru/noties/markwon/syntax/Prism4jSyntaxVisitor.java +++ b/markwon-syntax-highlight/src/main/java/io/noties/markwon/syntax/Prism4jSyntaxVisitor.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.syntax; +package io.noties.markwon.syntax; import android.support.annotation.NonNull; import android.text.SpannableStringBuilder; diff --git a/markwon-syntax-highlight/src/main/java/ru/noties/markwon/syntax/Prism4jTheme.java b/markwon-syntax-highlight/src/main/java/io/noties/markwon/syntax/Prism4jTheme.java similarity index 93% rename from markwon-syntax-highlight/src/main/java/ru/noties/markwon/syntax/Prism4jTheme.java rename to markwon-syntax-highlight/src/main/java/io/noties/markwon/syntax/Prism4jTheme.java index 3932bafc..6f15c6ed 100644 --- a/markwon-syntax-highlight/src/main/java/ru/noties/markwon/syntax/Prism4jTheme.java +++ b/markwon-syntax-highlight/src/main/java/io/noties/markwon/syntax/Prism4jTheme.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.syntax; +package io.noties.markwon.syntax; import android.support.annotation.ColorInt; import android.support.annotation.NonNull; diff --git a/markwon-syntax-highlight/src/main/java/ru/noties/markwon/syntax/Prism4jThemeBase.java b/markwon-syntax-highlight/src/main/java/io/noties/markwon/syntax/Prism4jThemeBase.java similarity index 99% rename from markwon-syntax-highlight/src/main/java/ru/noties/markwon/syntax/Prism4jThemeBase.java rename to markwon-syntax-highlight/src/main/java/io/noties/markwon/syntax/Prism4jThemeBase.java index 5cf784df..16110cf0 100644 --- a/markwon-syntax-highlight/src/main/java/ru/noties/markwon/syntax/Prism4jThemeBase.java +++ b/markwon-syntax-highlight/src/main/java/io/noties/markwon/syntax/Prism4jThemeBase.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.syntax; +package io.noties.markwon.syntax; import android.support.annotation.ColorInt; import android.support.annotation.FloatRange; diff --git a/markwon-syntax-highlight/src/main/java/ru/noties/markwon/syntax/Prism4jThemeDarkula.java b/markwon-syntax-highlight/src/main/java/io/noties/markwon/syntax/Prism4jThemeDarkula.java similarity index 94% rename from markwon-syntax-highlight/src/main/java/ru/noties/markwon/syntax/Prism4jThemeDarkula.java rename to markwon-syntax-highlight/src/main/java/io/noties/markwon/syntax/Prism4jThemeDarkula.java index 4d4016bf..df586fd0 100644 --- a/markwon-syntax-highlight/src/main/java/ru/noties/markwon/syntax/Prism4jThemeDarkula.java +++ b/markwon-syntax-highlight/src/main/java/io/noties/markwon/syntax/Prism4jThemeDarkula.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.syntax; +package io.noties.markwon.syntax; import android.support.annotation.ColorInt; import android.support.annotation.NonNull; @@ -6,8 +6,8 @@ import android.support.annotation.Nullable; import android.text.SpannableStringBuilder; import android.text.Spanned; -import ru.noties.markwon.core.spans.EmphasisSpan; -import ru.noties.markwon.core.spans.StrongEmphasisSpan; +import io.noties.markwon.core.spans.StrongEmphasisSpan; +import io.noties.markwon.core.spans.EmphasisSpan; public class Prism4jThemeDarkula extends Prism4jThemeBase { diff --git a/markwon-syntax-highlight/src/main/java/ru/noties/markwon/syntax/Prism4jThemeDefault.java b/markwon-syntax-highlight/src/main/java/io/noties/markwon/syntax/Prism4jThemeDefault.java similarity index 95% rename from markwon-syntax-highlight/src/main/java/ru/noties/markwon/syntax/Prism4jThemeDefault.java rename to markwon-syntax-highlight/src/main/java/io/noties/markwon/syntax/Prism4jThemeDefault.java index b729ed76..b44e46e7 100644 --- a/markwon-syntax-highlight/src/main/java/ru/noties/markwon/syntax/Prism4jThemeDefault.java +++ b/markwon-syntax-highlight/src/main/java/io/noties/markwon/syntax/Prism4jThemeDefault.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.syntax; +package io.noties.markwon.syntax; import android.support.annotation.ColorInt; import android.support.annotation.NonNull; @@ -7,8 +7,8 @@ import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.style.BackgroundColorSpan; -import ru.noties.markwon.core.spans.EmphasisSpan; -import ru.noties.markwon.core.spans.StrongEmphasisSpan; +import io.noties.markwon.core.spans.EmphasisSpan; +import io.noties.markwon.core.spans.StrongEmphasisSpan; public class Prism4jThemeDefault extends Prism4jThemeBase { diff --git a/markwon-syntax-highlight/src/main/java/ru/noties/markwon/syntax/SyntaxHighlightPlugin.java b/markwon-syntax-highlight/src/main/java/io/noties/markwon/syntax/SyntaxHighlightPlugin.java similarity index 89% rename from markwon-syntax-highlight/src/main/java/ru/noties/markwon/syntax/SyntaxHighlightPlugin.java rename to markwon-syntax-highlight/src/main/java/io/noties/markwon/syntax/SyntaxHighlightPlugin.java index b07f5c6e..9bcefc38 100644 --- a/markwon-syntax-highlight/src/main/java/ru/noties/markwon/syntax/SyntaxHighlightPlugin.java +++ b/markwon-syntax-highlight/src/main/java/io/noties/markwon/syntax/SyntaxHighlightPlugin.java @@ -1,11 +1,11 @@ -package ru.noties.markwon.syntax; +package io.noties.markwon.syntax; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import ru.noties.markwon.AbstractMarkwonPlugin; -import ru.noties.markwon.MarkwonConfiguration; -import ru.noties.markwon.core.MarkwonTheme; +import io.noties.markwon.AbstractMarkwonPlugin; +import io.noties.markwon.MarkwonConfiguration; +import io.noties.markwon.core.MarkwonTheme; import ru.noties.prism4j.Prism4j; public class SyntaxHighlightPlugin extends AbstractMarkwonPlugin { diff --git a/markwon-test-span/src/main/AndroidManifest.xml b/markwon-test-span/src/main/AndroidManifest.xml index c2e8a267..966a6859 100644 --- a/markwon-test-span/src/main/AndroidManifest.xml +++ b/markwon-test-span/src/main/AndroidManifest.xml @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/markwon-test-span/src/main/java/ru/noties/markwon/test/TestSpan.java b/markwon-test-span/src/main/java/io/noties/markwon/test/TestSpan.java similarity index 99% rename from markwon-test-span/src/main/java/ru/noties/markwon/test/TestSpan.java rename to markwon-test-span/src/main/java/io/noties/markwon/test/TestSpan.java index f979d633..fe41dd2a 100644 --- a/markwon-test-span/src/main/java/ru/noties/markwon/test/TestSpan.java +++ b/markwon-test-span/src/main/java/io/noties/markwon/test/TestSpan.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.test; +package io.noties.markwon.test; import android.support.annotation.NonNull; diff --git a/markwon-test-span/src/main/java/ru/noties/markwon/test/TestSpanDocument.java b/markwon-test-span/src/main/java/io/noties/markwon/test/TestSpanDocument.java similarity index 97% rename from markwon-test-span/src/main/java/ru/noties/markwon/test/TestSpanDocument.java rename to markwon-test-span/src/main/java/io/noties/markwon/test/TestSpanDocument.java index ef876311..91b479db 100644 --- a/markwon-test-span/src/main/java/ru/noties/markwon/test/TestSpanDocument.java +++ b/markwon-test-span/src/main/java/io/noties/markwon/test/TestSpanDocument.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.test; +package io.noties.markwon.test; import android.support.annotation.NonNull; diff --git a/markwon-test-span/src/main/java/ru/noties/markwon/test/TestSpanEnumerator.java b/markwon-test-span/src/main/java/io/noties/markwon/test/TestSpanEnumerator.java similarity index 96% rename from markwon-test-span/src/main/java/ru/noties/markwon/test/TestSpanEnumerator.java rename to markwon-test-span/src/main/java/io/noties/markwon/test/TestSpanEnumerator.java index 1c2172db..7e75f149 100644 --- a/markwon-test-span/src/main/java/ru/noties/markwon/test/TestSpanEnumerator.java +++ b/markwon-test-span/src/main/java/io/noties/markwon/test/TestSpanEnumerator.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.test; +package io.noties.markwon.test; import android.support.annotation.NonNull; diff --git a/markwon-test-span/src/main/java/ru/noties/markwon/test/TestSpanMatcher.java b/markwon-test-span/src/main/java/io/noties/markwon/test/TestSpanMatcher.java similarity index 99% rename from markwon-test-span/src/main/java/ru/noties/markwon/test/TestSpanMatcher.java rename to markwon-test-span/src/main/java/io/noties/markwon/test/TestSpanMatcher.java index 03bc2ace..a3cf1b57 100644 --- a/markwon-test-span/src/main/java/ru/noties/markwon/test/TestSpanMatcher.java +++ b/markwon-test-span/src/main/java/io/noties/markwon/test/TestSpanMatcher.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.test; +package io.noties.markwon.test; import android.support.annotation.NonNull; import android.text.Spanned; diff --git a/markwon-test-span/src/main/java/ru/noties/markwon/test/TestSpanSpan.java b/markwon-test-span/src/main/java/io/noties/markwon/test/TestSpanSpan.java similarity index 97% rename from markwon-test-span/src/main/java/ru/noties/markwon/test/TestSpanSpan.java rename to markwon-test-span/src/main/java/io/noties/markwon/test/TestSpanSpan.java index d9669cb2..f51a32ba 100644 --- a/markwon-test-span/src/main/java/ru/noties/markwon/test/TestSpanSpan.java +++ b/markwon-test-span/src/main/java/io/noties/markwon/test/TestSpanSpan.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.test; +package io.noties.markwon.test; import android.support.annotation.NonNull; diff --git a/markwon-test-span/src/main/java/ru/noties/markwon/test/TestSpanText.java b/markwon-test-span/src/main/java/io/noties/markwon/test/TestSpanText.java similarity index 96% rename from markwon-test-span/src/main/java/ru/noties/markwon/test/TestSpanText.java rename to markwon-test-span/src/main/java/io/noties/markwon/test/TestSpanText.java index 8a34a410..995d3541 100644 --- a/markwon-test-span/src/main/java/ru/noties/markwon/test/TestSpanText.java +++ b/markwon-test-span/src/main/java/io/noties/markwon/test/TestSpanText.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.test; +package io.noties.markwon.test; import android.support.annotation.NonNull; diff --git a/markwon-test-span/src/test/java/ru/noties/markwon/test/TestSpanTest.java b/markwon-test-span/src/test/java/io/noties/markwon/test/TestSpanTest.java similarity index 70% rename from markwon-test-span/src/test/java/ru/noties/markwon/test/TestSpanTest.java rename to markwon-test-span/src/test/java/io/noties/markwon/test/TestSpanTest.java index 5e178409..d1c90adf 100644 --- a/markwon-test-span/src/test/java/ru/noties/markwon/test/TestSpanTest.java +++ b/markwon-test-span/src/test/java/io/noties/markwon/test/TestSpanTest.java @@ -1,25 +1,20 @@ -package ru.noties.markwon.test; +package io.noties.markwon.test; import org.junit.Test; import java.util.Map; -import ru.noties.markwon.test.TestSpan.Document; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -import static ru.noties.markwon.test.TestSpan.args; -import static ru.noties.markwon.test.TestSpan.document; -import static ru.noties.markwon.test.TestSpan.span; -import static ru.noties.markwon.test.TestSpan.text; +import static io.noties.markwon.test.TestSpan.span; public class TestSpanTest { @Test public void args_not_event_throws() { try { - args("key"); + TestSpan.args("key"); fail(); } catch (IllegalStateException e) { assertTrue(e.getMessage(), e.getMessage().contains("Supplied key-values array must contain ")); @@ -29,7 +24,7 @@ public class TestSpanTest { @Test public void args_key_not_string_throws() { try { - args("key", 1, 2, 3); + TestSpan.args("key", 1, 2, 3); fail(); } catch (ClassCastException e) { assertTrue(true); @@ -39,7 +34,7 @@ public class TestSpanTest { @Test public void args_correct() { - final Map args = args("key1", true, "key2", 4); + final Map args = TestSpan.args("key1", true, "key2", 4); assertEquals(2, args.size()); assertEquals(true, args.get("key1")); @@ -48,21 +43,21 @@ public class TestSpanTest { @Test public void empty_document() { - final Document document = document(); + final TestSpan.Document document = TestSpan.document(); assertEquals(0, document.children().size()); assertEquals("", document.wholeText()); } @Test public void document_single_text_child() { - final Document document = document(text("Text")); + final TestSpan.Document document = TestSpan.document(TestSpan.text("Text")); assertEquals(1, document.children().size()); assertEquals("Text", document.wholeText()); } @Test public void document_single_span_child() { - final Document document = document(span("span", text("TextInSpan"))); + final TestSpan.Document document = TestSpan.document(TestSpan.span("span", TestSpan.text("TextInSpan"))); assertEquals(1, document.children().size()); assertTrue(document.children().get(0) instanceof TestSpan.Span); assertEquals("TextInSpan", document.wholeText()); diff --git a/sample/build.gradle b/sample/build.gradle index 4bde062b..df6695e4 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -6,7 +6,7 @@ android { buildToolsVersion config['build-tools'] defaultConfig { - applicationId "ru.noties.markwon.sample" + applicationId "io.noties.markwon.sample" minSdkVersion config['min-sdk'] targetSdkVersion config['target-sdk'] versionCode 1 diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml index 376348ca..a26c6d72 100644 --- a/sample/src/main/AndroidManifest.xml +++ b/sample/src/main/AndroidManifest.xml @@ -1,7 +1,7 @@ + package="io.noties.markwon.sample"> @@ -11,19 +11,19 @@ android:theme="@style/AppTheme" tools:ignore="AllowBackup,GoogleAppIndexingWarning,MissingApplicationIcon"> - + - - - - - - + + + + + + diff --git a/sample/src/main/java/ru/noties/markwon/sample/MainActivity.java b/sample/src/main/java/io/noties/markwon/sample/MainActivity.java similarity index 89% rename from sample/src/main/java/ru/noties/markwon/sample/MainActivity.java rename to sample/src/main/java/io/noties/markwon/sample/MainActivity.java index 16205066..9348f6bf 100644 --- a/sample/src/main/java/ru/noties/markwon/sample/MainActivity.java +++ b/sample/src/main/java/io/noties/markwon/sample/MainActivity.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.sample; +package io.noties.markwon.sample; import android.app.Activity; import android.content.Context; @@ -12,16 +12,16 @@ import android.view.View; import java.util.Arrays; +import io.noties.markwon.Markwon; +import io.noties.markwon.sample.basicplugins.BasicPluginsActivity; +import io.noties.markwon.sample.core.CoreActivity; +import io.noties.markwon.sample.customextension.CustomExtensionActivity; +import io.noties.markwon.sample.latex.LatexActivity; +import io.noties.markwon.sample.recycler.RecyclerActivity; import ru.noties.adapt.Adapt; import ru.noties.adapt.OnClickViewProcessor; import ru.noties.debug.AndroidLogDebugOutput; import ru.noties.debug.Debug; -import ru.noties.markwon.Markwon; -import ru.noties.markwon.sample.basicplugins.BasicPluginsActivity; -import ru.noties.markwon.sample.core.CoreActivity; -import ru.noties.markwon.sample.customextension.CustomExtensionActivity; -import ru.noties.markwon.sample.latex.LatexActivity; -import ru.noties.markwon.sample.recycler.RecyclerActivity; public class MainActivity extends Activity { diff --git a/sample/src/main/java/ru/noties/markwon/sample/SampleItem.java b/sample/src/main/java/io/noties/markwon/sample/SampleItem.java similarity index 94% rename from sample/src/main/java/ru/noties/markwon/sample/SampleItem.java rename to sample/src/main/java/io/noties/markwon/sample/SampleItem.java index e21444ba..0c7f8b86 100644 --- a/sample/src/main/java/ru/noties/markwon/sample/SampleItem.java +++ b/sample/src/main/java/io/noties/markwon/sample/SampleItem.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.sample; +package io.noties.markwon.sample; import android.support.annotation.StringRes; diff --git a/sample/src/main/java/ru/noties/markwon/sample/SampleItemDecoration.java b/sample/src/main/java/io/noties/markwon/sample/SampleItemDecoration.java similarity index 98% rename from sample/src/main/java/ru/noties/markwon/sample/SampleItemDecoration.java rename to sample/src/main/java/io/noties/markwon/sample/SampleItemDecoration.java index 580b2763..16a04286 100644 --- a/sample/src/main/java/ru/noties/markwon/sample/SampleItemDecoration.java +++ b/sample/src/main/java/io/noties/markwon/sample/SampleItemDecoration.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.sample; +package io.noties.markwon.sample; import android.graphics.Canvas; import android.graphics.Paint; diff --git a/sample/src/main/java/ru/noties/markwon/sample/SampleItemView.java b/sample/src/main/java/io/noties/markwon/sample/SampleItemView.java similarity index 94% rename from sample/src/main/java/ru/noties/markwon/sample/SampleItemView.java rename to sample/src/main/java/io/noties/markwon/sample/SampleItemView.java index dc4432aa..fa2a202e 100644 --- a/sample/src/main/java/ru/noties/markwon/sample/SampleItemView.java +++ b/sample/src/main/java/io/noties/markwon/sample/SampleItemView.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.sample; +package io.noties.markwon.sample; import android.support.annotation.NonNull; import android.text.Spannable; @@ -10,10 +10,10 @@ import android.widget.TextView; import java.util.EnumMap; +import io.noties.markwon.Markwon; +import io.noties.markwon.utils.NoCopySpannableFactory; import ru.noties.adapt.Holder; import ru.noties.adapt.ItemView; -import ru.noties.markwon.Markwon; -import ru.noties.markwon.utils.NoCopySpannableFactory; class SampleItemView extends ItemView { diff --git a/sample/src/main/java/ru/noties/markwon/sample/basicplugins/BasicPluginsActivity.java b/sample/src/main/java/io/noties/markwon/sample/basicplugins/BasicPluginsActivity.java similarity index 92% rename from sample/src/main/java/ru/noties/markwon/sample/basicplugins/BasicPluginsActivity.java rename to sample/src/main/java/io/noties/markwon/sample/basicplugins/BasicPluginsActivity.java index 4d34db84..8e6c2500 100644 --- a/sample/src/main/java/ru/noties/markwon/sample/basicplugins/BasicPluginsActivity.java +++ b/sample/src/main/java/io/noties/markwon/sample/basicplugins/BasicPluginsActivity.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.sample.basicplugins; +package io.noties.markwon.sample.basicplugins; import android.app.Activity; import android.graphics.Color; @@ -18,22 +18,22 @@ import org.commonmark.node.Paragraph; import java.util.Collection; import java.util.Collections; -import ru.noties.markwon.AbstractMarkwonPlugin; -import ru.noties.markwon.Markwon; -import ru.noties.markwon.MarkwonConfiguration; -import ru.noties.markwon.MarkwonPlugin; -import ru.noties.markwon.MarkwonSpansFactory; -import ru.noties.markwon.MarkwonVisitor; -import ru.noties.markwon.RenderProps; -import ru.noties.markwon.core.MarkwonTheme; -import ru.noties.markwon.html.HtmlPlugin; -import ru.noties.markwon.html.HtmlTag; -import ru.noties.markwon.html.tag.SimpleTagHandler; -import ru.noties.markwon.image.ImageItem; -import ru.noties.markwon.image.ImagesPlugin; -import ru.noties.markwon.image.SchemeHandler; -import ru.noties.markwon.image.network.NetworkSchemeHandler; -import ru.noties.markwon.movement.MovementMethodPlugin; +import io.noties.markwon.core.MarkwonTheme; +import io.noties.markwon.html.HtmlTag; +import io.noties.markwon.image.ImageItem; +import io.noties.markwon.image.ImagesPlugin; +import io.noties.markwon.image.SchemeHandler; +import io.noties.markwon.image.network.NetworkSchemeHandler; +import io.noties.markwon.movement.MovementMethodPlugin; +import io.noties.markwon.AbstractMarkwonPlugin; +import io.noties.markwon.Markwon; +import io.noties.markwon.MarkwonConfiguration; +import io.noties.markwon.MarkwonPlugin; +import io.noties.markwon.MarkwonSpansFactory; +import io.noties.markwon.MarkwonVisitor; +import io.noties.markwon.RenderProps; +import io.noties.markwon.html.HtmlPlugin; +import io.noties.markwon.html.tag.SimpleTagHandler; public class BasicPluginsActivity extends Activity { diff --git a/sample/src/main/java/ru/noties/markwon/sample/core/CoreActivity.java b/sample/src/main/java/io/noties/markwon/sample/core/CoreActivity.java similarity index 96% rename from sample/src/main/java/ru/noties/markwon/sample/core/CoreActivity.java rename to sample/src/main/java/io/noties/markwon/sample/core/CoreActivity.java index 3f8118c5..f208fa07 100644 --- a/sample/src/main/java/ru/noties/markwon/sample/core/CoreActivity.java +++ b/sample/src/main/java/io/noties/markwon/sample/core/CoreActivity.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.sample.core; +package io.noties.markwon.sample.core; import android.app.Activity; import android.os.Bundle; @@ -9,8 +9,8 @@ import android.widget.Toast; import org.commonmark.node.Node; -import ru.noties.markwon.Markwon; -import ru.noties.markwon.core.CorePlugin; +import io.noties.markwon.core.CorePlugin; +import io.noties.markwon.Markwon; public class CoreActivity extends Activity { diff --git a/sample/src/main/java/ru/noties/markwon/sample/customextension/CustomExtensionActivity.java b/sample/src/main/java/io/noties/markwon/sample/customextension/CustomExtensionActivity.java similarity index 91% rename from sample/src/main/java/ru/noties/markwon/sample/customextension/CustomExtensionActivity.java rename to sample/src/main/java/io/noties/markwon/sample/customextension/CustomExtensionActivity.java index 71e592c6..c8615331 100644 --- a/sample/src/main/java/ru/noties/markwon/sample/customextension/CustomExtensionActivity.java +++ b/sample/src/main/java/io/noties/markwon/sample/customextension/CustomExtensionActivity.java @@ -1,12 +1,12 @@ -package ru.noties.markwon.sample.customextension; +package io.noties.markwon.sample.customextension; import android.app.Activity; import android.os.Bundle; import android.support.annotation.Nullable; import android.widget.TextView; -import ru.noties.markwon.Markwon; -import ru.noties.markwon.sample.R; +import io.noties.markwon.Markwon; +import io.noties.markwon.sample.R; public class CustomExtensionActivity extends Activity { diff --git a/sample/src/main/java/ru/noties/markwon/sample/customextension/IconGroupNode.java b/sample/src/main/java/io/noties/markwon/sample/customextension/IconGroupNode.java similarity index 71% rename from sample/src/main/java/ru/noties/markwon/sample/customextension/IconGroupNode.java rename to sample/src/main/java/io/noties/markwon/sample/customextension/IconGroupNode.java index 98560b49..40868396 100644 --- a/sample/src/main/java/ru/noties/markwon/sample/customextension/IconGroupNode.java +++ b/sample/src/main/java/io/noties/markwon/sample/customextension/IconGroupNode.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.sample.customextension; +package io.noties.markwon.sample.customextension; import org.commonmark.node.CustomNode; diff --git a/sample/src/main/java/ru/noties/markwon/sample/customextension/IconNode.java b/sample/src/main/java/io/noties/markwon/sample/customextension/IconNode.java similarity index 96% rename from sample/src/main/java/ru/noties/markwon/sample/customextension/IconNode.java rename to sample/src/main/java/io/noties/markwon/sample/customextension/IconNode.java index b297e4a6..c0a2f75b 100644 --- a/sample/src/main/java/ru/noties/markwon/sample/customextension/IconNode.java +++ b/sample/src/main/java/io/noties/markwon/sample/customextension/IconNode.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.sample.customextension; +package io.noties.markwon.sample.customextension; import android.support.annotation.NonNull; diff --git a/sample/src/main/java/ru/noties/markwon/sample/customextension/IconPlugin.java b/sample/src/main/java/io/noties/markwon/sample/customextension/IconPlugin.java similarity index 93% rename from sample/src/main/java/ru/noties/markwon/sample/customextension/IconPlugin.java rename to sample/src/main/java/io/noties/markwon/sample/customextension/IconPlugin.java index 42b7c8d8..bf39834c 100644 --- a/sample/src/main/java/ru/noties/markwon/sample/customextension/IconPlugin.java +++ b/sample/src/main/java/io/noties/markwon/sample/customextension/IconPlugin.java @@ -1,12 +1,12 @@ -package ru.noties.markwon.sample.customextension; +package io.noties.markwon.sample.customextension; import android.support.annotation.NonNull; import android.text.TextUtils; import org.commonmark.parser.Parser; -import ru.noties.markwon.AbstractMarkwonPlugin; -import ru.noties.markwon.MarkwonVisitor; +import io.noties.markwon.AbstractMarkwonPlugin; +import io.noties.markwon.MarkwonVisitor; public class IconPlugin extends AbstractMarkwonPlugin { diff --git a/sample/src/main/java/ru/noties/markwon/sample/customextension/IconProcessor.java b/sample/src/main/java/io/noties/markwon/sample/customextension/IconProcessor.java similarity index 98% rename from sample/src/main/java/ru/noties/markwon/sample/customextension/IconProcessor.java rename to sample/src/main/java/io/noties/markwon/sample/customextension/IconProcessor.java index eb7a79be..0fa1797b 100644 --- a/sample/src/main/java/ru/noties/markwon/sample/customextension/IconProcessor.java +++ b/sample/src/main/java/io/noties/markwon/sample/customextension/IconProcessor.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.sample.customextension; +package io.noties.markwon.sample.customextension; import android.support.annotation.NonNull; import android.text.TextUtils; diff --git a/sample/src/main/java/ru/noties/markwon/sample/customextension/IconSpan.java b/sample/src/main/java/io/noties/markwon/sample/customextension/IconSpan.java similarity index 97% rename from sample/src/main/java/ru/noties/markwon/sample/customextension/IconSpan.java rename to sample/src/main/java/io/noties/markwon/sample/customextension/IconSpan.java index 9d2b8b43..b055233d 100644 --- a/sample/src/main/java/ru/noties/markwon/sample/customextension/IconSpan.java +++ b/sample/src/main/java/io/noties/markwon/sample/customextension/IconSpan.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.sample.customextension; +package io.noties.markwon.sample.customextension; import android.graphics.Canvas; import android.graphics.Paint; diff --git a/sample/src/main/java/ru/noties/markwon/sample/customextension/IconSpanProvider.java b/sample/src/main/java/io/noties/markwon/sample/customextension/IconSpanProvider.java similarity index 97% rename from sample/src/main/java/ru/noties/markwon/sample/customextension/IconSpanProvider.java rename to sample/src/main/java/io/noties/markwon/sample/customextension/IconSpanProvider.java index 25049bc2..a324ae35 100644 --- a/sample/src/main/java/ru/noties/markwon/sample/customextension/IconSpanProvider.java +++ b/sample/src/main/java/io/noties/markwon/sample/customextension/IconSpanProvider.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.sample.customextension; +package io.noties.markwon.sample.customextension; import android.content.Context; import android.content.res.Resources; diff --git a/sample/src/main/java/ru/noties/markwon/sample/latex/LatexActivity.java b/sample/src/main/java/io/noties/markwon/sample/latex/LatexActivity.java similarity index 94% rename from sample/src/main/java/ru/noties/markwon/sample/latex/LatexActivity.java rename to sample/src/main/java/io/noties/markwon/sample/latex/LatexActivity.java index ec4cd397..6c94afa9 100644 --- a/sample/src/main/java/ru/noties/markwon/sample/latex/LatexActivity.java +++ b/sample/src/main/java/io/noties/markwon/sample/latex/LatexActivity.java @@ -1,13 +1,13 @@ -package ru.noties.markwon.sample.latex; +package io.noties.markwon.sample.latex; import android.app.Activity; import android.os.Bundle; import android.support.annotation.Nullable; import android.widget.TextView; -import ru.noties.markwon.Markwon; -import ru.noties.markwon.ext.latex.JLatexMathPlugin; -import ru.noties.markwon.sample.R; +import io.noties.markwon.ext.latex.JLatexMathPlugin; +import io.noties.markwon.Markwon; +import io.noties.markwon.sample.R; public class LatexActivity extends Activity { diff --git a/sample/src/main/java/ru/noties/markwon/sample/recycler/RecyclerActivity.java b/sample/src/main/java/io/noties/markwon/sample/recycler/RecyclerActivity.java similarity index 86% rename from sample/src/main/java/ru/noties/markwon/sample/recycler/RecyclerActivity.java rename to sample/src/main/java/io/noties/markwon/sample/recycler/RecyclerActivity.java index ff911a15..2c4f5b4d 100644 --- a/sample/src/main/java/ru/noties/markwon/sample/recycler/RecyclerActivity.java +++ b/sample/src/main/java/io/noties/markwon/sample/recycler/RecyclerActivity.java @@ -1,9 +1,7 @@ -package ru.noties.markwon.sample.recycler; +package io.noties.markwon.sample.recycler; import android.app.Activity; import android.content.Context; -import android.graphics.Color; -import android.graphics.drawable.ColorDrawable; import android.net.Uri; import android.os.Bundle; import android.support.annotation.NonNull; @@ -12,9 +10,6 @@ import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.text.TextUtils; -import com.squareup.picasso.Picasso; -import com.squareup.picasso.RequestCreator; - import org.commonmark.ext.gfm.tables.TableBlock; import org.commonmark.node.FencedCodeBlock; @@ -23,24 +18,22 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import io.noties.markwon.AbstractMarkwonPlugin; +import io.noties.markwon.Markwon; +import io.noties.markwon.MarkwonConfiguration; +import io.noties.markwon.MarkwonVisitor; +import io.noties.markwon.core.CorePlugin; +import io.noties.markwon.html.HtmlPlugin; +import io.noties.markwon.image.picasso.PicassoImagesPlugin; +import io.noties.markwon.recycler.MarkwonAdapter; +import io.noties.markwon.recycler.SimpleEntry; +import io.noties.markwon.recycler.table.TableEntry; +import io.noties.markwon.recycler.table.TableEntryPlugin; +import io.noties.markwon.sample.R; +import io.noties.markwon.urlprocessor.UrlProcessor; +import io.noties.markwon.urlprocessor.UrlProcessorRelativeToAbsolute; import ru.noties.debug.AndroidLogDebugOutput; import ru.noties.debug.Debug; -import ru.noties.markwon.AbstractMarkwonPlugin; -import ru.noties.markwon.Markwon; -import ru.noties.markwon.MarkwonConfiguration; -import ru.noties.markwon.MarkwonVisitor; -import ru.noties.markwon.core.CorePlugin; -import ru.noties.markwon.html.HtmlPlugin; -import ru.noties.markwon.image.AsyncDrawable; -import ru.noties.markwon.image.glide.GlideImagesPlugin; -import ru.noties.markwon.image.picasso.PicassoImagesPlugin; -import ru.noties.markwon.recycler.MarkwonAdapter; -import ru.noties.markwon.recycler.SimpleEntry; -import ru.noties.markwon.recycler.table.TableEntry; -import ru.noties.markwon.recycler.table.TableEntryPlugin; -import ru.noties.markwon.sample.R; -import ru.noties.markwon.urlprocessor.UrlProcessor; -import ru.noties.markwon.urlprocessor.UrlProcessorRelativeToAbsolute; public class RecyclerActivity extends Activity { diff --git a/sample/src/main/java/ru/noties/markwon/sample/theme/ThemeActivity.java b/sample/src/main/java/io/noties/markwon/sample/theme/ThemeActivity.java similarity index 81% rename from sample/src/main/java/ru/noties/markwon/sample/theme/ThemeActivity.java rename to sample/src/main/java/io/noties/markwon/sample/theme/ThemeActivity.java index 33ee500a..bec1afa6 100644 --- a/sample/src/main/java/ru/noties/markwon/sample/theme/ThemeActivity.java +++ b/sample/src/main/java/io/noties/markwon/sample/theme/ThemeActivity.java @@ -1,10 +1,10 @@ -package ru.noties.markwon.sample.theme; +package io.noties.markwon.sample.theme; import android.app.Activity; import android.os.Bundle; import android.support.annotation.Nullable; -import ru.noties.markwon.sample.R; +import io.noties.markwon.sample.R; public class ThemeActivity extends Activity { diff --git a/sample/src/test/java/ru/noties/markwon/sample/MainActivityTest.java b/sample/src/test/java/io/noties/markwon/sample/MainActivityTest.java similarity index 95% rename from sample/src/test/java/ru/noties/markwon/sample/MainActivityTest.java rename to sample/src/test/java/io/noties/markwon/sample/MainActivityTest.java index dec6b07e..f5f197e9 100644 --- a/sample/src/test/java/ru/noties/markwon/sample/MainActivityTest.java +++ b/sample/src/test/java/io/noties/markwon/sample/MainActivityTest.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.sample; +package io.noties.markwon.sample; import android.content.Context; From ab4c80dca57659051a9929fd61e1c02f7aa34fca Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Wed, 5 Jun 2019 00:35:39 +0300 Subject: [PATCH 17/42] Update dependencies --- .../main/java/io/noties/markwon/app/App.java | 4 +- .../io/noties/markwon/app/MainActivity.java | 2 +- .../io/noties/markwon/app/MarkdownLoader.java | 2 +- .../noties/markwon/app/MarkdownRenderer.java | 2 +- build.gradle | 4 +- .../noties/markwon/sample/MainActivity.java | 35 ++++--- .../java/io/noties/markwon/sample/Sample.java | 30 ++++++ .../io/noties/markwon/sample/SampleItem.java | 91 ++++++++++++++----- .../noties/markwon/sample/SampleItemView.java | 75 --------------- .../sample/recycler/RecyclerActivity.java | 4 +- .../markwon/sample/MainActivityTest.java | 2 +- 11 files changed, 127 insertions(+), 124 deletions(-) create mode 100644 sample/src/main/java/io/noties/markwon/sample/Sample.java delete mode 100644 sample/src/main/java/io/noties/markwon/sample/SampleItemView.java diff --git a/app/src/main/java/io/noties/markwon/app/App.java b/app/src/main/java/io/noties/markwon/app/App.java index ce64314a..0b8bced2 100644 --- a/app/src/main/java/io/noties/markwon/app/App.java +++ b/app/src/main/java/io/noties/markwon/app/App.java @@ -4,8 +4,8 @@ import android.app.Application; import android.content.Context; import android.support.annotation.NonNull; -import ru.noties.debug.AndroidLogDebugOutput; -import ru.noties.debug.Debug; +import io.noties.debug.AndroidLogDebugOutput; +import io.noties.debug.Debug; public class App extends Application { diff --git a/app/src/main/java/io/noties/markwon/app/MainActivity.java b/app/src/main/java/io/noties/markwon/app/MainActivity.java index 85594e59..4aa34b47 100644 --- a/app/src/main/java/io/noties/markwon/app/MainActivity.java +++ b/app/src/main/java/io/noties/markwon/app/MainActivity.java @@ -13,7 +13,7 @@ import android.widget.TextView; import javax.inject.Inject; import io.noties.markwon.Markwon; -import ru.noties.debug.Debug; +import io.noties.debug.Debug; public class MainActivity extends Activity { diff --git a/app/src/main/java/io/noties/markwon/app/MarkdownLoader.java b/app/src/main/java/io/noties/markwon/app/MarkdownLoader.java index b08d8d25..05aaa5fc 100644 --- a/app/src/main/java/io/noties/markwon/app/MarkdownLoader.java +++ b/app/src/main/java/io/noties/markwon/app/MarkdownLoader.java @@ -24,7 +24,7 @@ import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; import okhttp3.ResponseBody; -import ru.noties.debug.Debug; +import io.noties.debug.Debug; @ActivityScope public class MarkdownLoader { diff --git a/app/src/main/java/io/noties/markwon/app/MarkdownRenderer.java b/app/src/main/java/io/noties/markwon/app/MarkdownRenderer.java index a924cedd..667ef6a4 100644 --- a/app/src/main/java/io/noties/markwon/app/MarkdownRenderer.java +++ b/app/src/main/java/io/noties/markwon/app/MarkdownRenderer.java @@ -33,7 +33,7 @@ import io.noties.markwon.syntax.Prism4jThemeDefault; import io.noties.markwon.syntax.SyntaxHighlightPlugin; import io.noties.markwon.urlprocessor.UrlProcessor; import io.noties.markwon.urlprocessor.UrlProcessorRelativeToAbsolute; -import ru.noties.debug.Debug; +import io.noties.debug.Debug; import ru.noties.prism4j.Prism4j; @ActivityScope diff --git a/build.gradle b/build.gradle index f34a6c05..17105439 100644 --- a/build.gradle +++ b/build.gradle @@ -69,8 +69,8 @@ ext { 'jlatexmath-android' : 'ru.noties:jlatexmath-android:0.1.0', 'okhttp' : 'com.squareup.okhttp3:okhttp:3.9.0', 'prism4j' : 'ru.noties:prism4j:1.1.0', - 'debug' : 'ru.noties:debug:3.0.0@jar', - 'adapt' : 'ru.noties:adapt:1.1.0', + 'debug' : 'io.noties:debug:5.0.0@jar', + 'adapt' : 'io.noties:adapt:2.0.0', 'dagger' : "com.google.dagger:dagger:$daggerVersion", 'picasso' : 'com.squareup.picasso:picasso:2.71828', 'glide' : 'com.github.bumptech.glide:glide:4.9.0' diff --git a/sample/src/main/java/io/noties/markwon/sample/MainActivity.java b/sample/src/main/java/io/noties/markwon/sample/MainActivity.java index 9348f6bf..4d9bee65 100644 --- a/sample/src/main/java/io/noties/markwon/sample/MainActivity.java +++ b/sample/src/main/java/io/noties/markwon/sample/MainActivity.java @@ -8,20 +8,20 @@ import android.support.annotation.NonNull; import android.support.annotation.VisibleForTesting; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; -import android.view.View; -import java.util.Arrays; +import java.util.ArrayList; +import java.util.List; +import io.noties.adapt.Adapt; +import io.noties.adapt.Item; +import io.noties.debug.AndroidLogDebugOutput; +import io.noties.debug.Debug; import io.noties.markwon.Markwon; import io.noties.markwon.sample.basicplugins.BasicPluginsActivity; import io.noties.markwon.sample.core.CoreActivity; import io.noties.markwon.sample.customextension.CustomExtensionActivity; import io.noties.markwon.sample.latex.LatexActivity; import io.noties.markwon.sample.recycler.RecyclerActivity; -import ru.noties.adapt.Adapt; -import ru.noties.adapt.OnClickViewProcessor; -import ru.noties.debug.AndroidLogDebugOutput; -import ru.noties.debug.Debug; public class MainActivity extends Activity { @@ -38,21 +38,20 @@ public class MainActivity extends Activity { // here we are creating as core markwon (no additional plugins are registered) final Markwon markwon = Markwon.create(this); - final Adapt adapt = Adapt.builder(SampleItem.class) - .include(SampleItem.class, new SampleItemView(markwon), new OnClickViewProcessor() { - @Override - public void onClick(@NonNull SampleItem item, @NonNull View view) { - showSample(item); - } - }) - .build(); - adapt.setItems(Arrays.asList(SampleItem.values())); + final Adapt adapt = Adapt.create(); + + final List items = new ArrayList<>(); + final SampleItem.OnClickListener onClickListener = this::showSample; + for (Sample sample : Sample.values()) { + items.add(new SampleItem(sample, markwon, onClickListener)); + } + adapt.setItems(items); final RecyclerView recyclerView = findViewById(R.id.recycler_view); recyclerView.setLayoutManager(new LinearLayoutManager(this)); recyclerView.setHasFixedSize(true); recyclerView.addItemDecoration(createSampleItemDecoration()); - recyclerView.setAdapter(adapt.recyclerViewAdapter()); + recyclerView.setAdapter(adapt); } @NonNull @@ -66,12 +65,12 @@ public class MainActivity extends Activity { ); } - private void showSample(@NonNull SampleItem item) { + private void showSample(@NonNull Sample item) { startActivity(sampleItemIntent(this, item)); } @VisibleForTesting - static Intent sampleItemIntent(@NonNull Context context, @NonNull SampleItem item) { + static Intent sampleItemIntent(@NonNull Context context, @NonNull Sample item) { final Class activity; diff --git a/sample/src/main/java/io/noties/markwon/sample/Sample.java b/sample/src/main/java/io/noties/markwon/sample/Sample.java new file mode 100644 index 00000000..8e20c80d --- /dev/null +++ b/sample/src/main/java/io/noties/markwon/sample/Sample.java @@ -0,0 +1,30 @@ +package io.noties.markwon.sample; + +import android.support.annotation.StringRes; + +public enum Sample { + + // all usages of markwon without plugins (parse, render, setMarkwon, etc) + CORE(R.string.sample_core), + + BASIC_PLUGINS(R.string.sample_basic_plugins), + + LATEX(R.string.sample_latex), + + CUSTOM_EXTENSION(R.string.sample_custom_extension), + + RECYCLER(R.string.sample_recycler), + + ; + + private final int textResId; + + Sample(@StringRes int textResId) { + this.textResId = textResId; + } + + @StringRes + public int textResId() { + return textResId; + } +} diff --git a/sample/src/main/java/io/noties/markwon/sample/SampleItem.java b/sample/src/main/java/io/noties/markwon/sample/SampleItem.java index 0c7f8b86..57266e49 100644 --- a/sample/src/main/java/io/noties/markwon/sample/SampleItem.java +++ b/sample/src/main/java/io/noties/markwon/sample/SampleItem.java @@ -1,30 +1,79 @@ package io.noties.markwon.sample; -import android.support.annotation.StringRes; +import android.support.annotation.NonNull; +import android.text.Spanned; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; -public enum SampleItem { +import io.noties.adapt.Item; +import io.noties.markwon.Markwon; +import io.noties.markwon.utils.NoCopySpannableFactory; - // all usages of markwon without plugins (parse, render, setMarkwon, etc) - CORE(R.string.sample_core), +class SampleItem extends Item { - BASIC_PLUGINS(R.string.sample_basic_plugins), - - LATEX(R.string.sample_latex), - - CUSTOM_EXTENSION(R.string.sample_custom_extension), - - RECYCLER(R.string.sample_recycler), - - ; - - private final int textResId; - - SampleItem(@StringRes int textResId) { - this.textResId = textResId; + interface OnClickListener { + void onClick(@NonNull Sample sample); } - @StringRes - public int textResId() { - return textResId; + private final Sample sample; + + private final Markwon markwon; + + private final OnClickListener onClickListener; + + // instance specific cache + private Spanned cache; + + SampleItem(@NonNull Sample sample, @NonNull Markwon markwon, @NonNull OnClickListener onClickListener) { + super(sample.ordinal()); + this.sample = sample; + this.markwon = markwon; + this.onClickListener = onClickListener; + } + + @NonNull + @Override + public SampleHolder createHolder(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) { + + final SampleHolder holder = new SampleHolder(inflater.inflate( + R.layout.adapt_sample_item, + parent, + false)); + + // set Spannable.Factory so when TextView will receive a new content + // it won't create new Spannable and copy all the spans but instead + // re-use existing Spannable thus improving performance + holder.textView.setSpannableFactory(NoCopySpannableFactory.getInstance()); + + return holder; + } + + @Override + public void render(@NonNull SampleHolder holder) { + + // retrieve an item from cache or create new one + // simple lazy loading pattern (cache on first call then re-use) + Spanned spanned = this.cache; + if (spanned == null) { + spanned = cache = markwon.toMarkdown( + holder.textView.getResources().getString(sample.textResId())); + } + + holder.textView.setText(spanned); + + holder.itemView.setOnClickListener(v -> onClickListener.onClick(sample)); + } + + static class SampleHolder extends Item.Holder { + + final TextView textView; + + SampleHolder(@NonNull View view) { + super(view); + + this.textView = requireView(R.id.text); + } } } diff --git a/sample/src/main/java/io/noties/markwon/sample/SampleItemView.java b/sample/src/main/java/io/noties/markwon/sample/SampleItemView.java deleted file mode 100644 index fa2a202e..00000000 --- a/sample/src/main/java/io/noties/markwon/sample/SampleItemView.java +++ /dev/null @@ -1,75 +0,0 @@ -package io.noties.markwon.sample; - -import android.support.annotation.NonNull; -import android.text.Spannable; -import android.text.Spanned; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; - -import java.util.EnumMap; - -import io.noties.markwon.Markwon; -import io.noties.markwon.utils.NoCopySpannableFactory; -import ru.noties.adapt.Holder; -import ru.noties.adapt.ItemView; - -class SampleItemView extends ItemView { - - private final Markwon markwon; - - // instance specific factory - private final Spannable.Factory factory; - - // instance specific cache - private final EnumMap cache; - - SampleItemView(@NonNull Markwon markwon) { - this.markwon = markwon; - this.factory = NoCopySpannableFactory.getInstance(); - this.cache = new EnumMap<>(SampleItem.class); - } - - @NonNull - @Override - public SampleHolder createHolder(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) { - - final SampleHolder holder = new SampleHolder(inflater.inflate( - R.layout.adapt_sample_item, - parent, - false)); - - // set Spannable.Factory so when TextView will receive a new content - // it won't create new Spannable and copy all the spans but instead - // re-use existing Spannable thus improving performance - holder.textView.setSpannableFactory(factory); - - return holder; - } - - @Override - public void bindHolder(@NonNull SampleHolder holder, @NonNull SampleItem item) { - - // retrieve an item from cache or create new one - // simple lazy loading pattern (cache on first call then re-use) - Spanned spanned = cache.get(item); - if (spanned == null) { - spanned = markwon.toMarkdown(context(holder).getString(item.textResId())); - cache.put(item, spanned); - } - - holder.textView.setText(spanned); - } - - static class SampleHolder extends Holder { - - final TextView textView; - - SampleHolder(@NonNull View view) { - super(view); - - this.textView = requireView(R.id.text); - } - } -} diff --git a/sample/src/main/java/io/noties/markwon/sample/recycler/RecyclerActivity.java b/sample/src/main/java/io/noties/markwon/sample/recycler/RecyclerActivity.java index 2c4f5b4d..077bf967 100644 --- a/sample/src/main/java/io/noties/markwon/sample/recycler/RecyclerActivity.java +++ b/sample/src/main/java/io/noties/markwon/sample/recycler/RecyclerActivity.java @@ -32,8 +32,8 @@ import io.noties.markwon.recycler.table.TableEntryPlugin; import io.noties.markwon.sample.R; import io.noties.markwon.urlprocessor.UrlProcessor; import io.noties.markwon.urlprocessor.UrlProcessorRelativeToAbsolute; -import ru.noties.debug.AndroidLogDebugOutput; -import ru.noties.debug.Debug; +import io.noties.debug.AndroidLogDebugOutput; +import io.noties.debug.Debug; public class RecyclerActivity extends Activity { diff --git a/sample/src/test/java/io/noties/markwon/sample/MainActivityTest.java b/sample/src/test/java/io/noties/markwon/sample/MainActivityTest.java index f5f197e9..15694be2 100644 --- a/sample/src/test/java/io/noties/markwon/sample/MainActivityTest.java +++ b/sample/src/test/java/io/noties/markwon/sample/MainActivityTest.java @@ -17,7 +17,7 @@ public class MainActivityTest { @Test public void all_sample_items_have_activity_associated() { final Context context = RuntimeEnvironment.application; - for (SampleItem item : SampleItem.values()) { + for (Sample item : Sample.values()) { // we assert as not null, but in case of an error this method should throw assertNotNull(MainActivity.sampleItemIntent(context, item)); } From 173425ed536e7fbd545845f86597defb0d48e35c Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Wed, 5 Jun 2019 15:17:53 +0300 Subject: [PATCH 18/42] Image loader tests --- .../markwon/MarkwonBuilderImplTest.java | 1 - .../noties/markwon/core/CorePluginTest.java | 6 +- .../markwon/syntax/SyntaxHighlightTest.java | 3 +- markwon-ext-latex/README.md | 10 +- markwon-ext-strikethrough/README.md | 8 +- markwon-image/build.gradle | 7 +- .../image/AsyncDrawableLoaderBuilder.java | 11 + .../image/AsyncDrawableLoaderImpl.java | 9 +- .../markwon/image/gif/GifMediaDecoder.java | 23 +- .../markwon/image/svg/SvgMediaDecoder.java | 14 +- .../image/AsyncDrawableLoaderBuilderTest.java | 18 +- .../image/AsyncDrawableLoaderImplTest.java | 520 +++++++++++++++++- .../markwon/image/ImagesPluginTest.java | 1 - 13 files changed, 585 insertions(+), 46 deletions(-) diff --git a/markwon-core/src/test/java/io/noties/markwon/MarkwonBuilderImplTest.java b/markwon-core/src/test/java/io/noties/markwon/MarkwonBuilderImplTest.java index 56b1ee60..84a3a38e 100644 --- a/markwon-core/src/test/java/io/noties/markwon/MarkwonBuilderImplTest.java +++ b/markwon-core/src/test/java/io/noties/markwon/MarkwonBuilderImplTest.java @@ -88,7 +88,6 @@ public class MarkwonBuilderImplTest { verify(plugin, times(1)).configureConfiguration(any(MarkwonConfiguration.Builder.class)); verify(plugin, times(1)).configureVisitor(any(MarkwonVisitor.Builder.class)); verify(plugin, times(1)).configureSpansFactory(any(MarkwonSpansFactory.Builder.class)); - verify(plugin, times(1)).configureHtmlRenderer(any(MarkwonHtmlRenderer.Builder.class)); // note, no render props -> they must be configured on render stage verify(plugin, times(0)).processMarkdown(anyString()); diff --git a/markwon-core/src/test/java/io/noties/markwon/core/CorePluginTest.java b/markwon-core/src/test/java/io/noties/markwon/core/CorePluginTest.java index 3d9834dc..cda6c9b8 100644 --- a/markwon-core/src/test/java/io/noties/markwon/core/CorePluginTest.java +++ b/markwon-core/src/test/java/io/noties/markwon/core/CorePluginTest.java @@ -3,6 +3,7 @@ package io.noties.markwon.core; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.text.method.MovementMethod; +import android.widget.ImageView; import android.widget.TextView; import org.commonmark.node.BlockQuote; @@ -12,6 +13,7 @@ import org.commonmark.node.Emphasis; import org.commonmark.node.FencedCodeBlock; import org.commonmark.node.HardLineBreak; import org.commonmark.node.Heading; +import org.commonmark.node.Image; import org.commonmark.node.IndentedCodeBlock; import org.commonmark.node.Link; import org.commonmark.node.ListItem; @@ -84,7 +86,8 @@ public class CorePluginTest { SoftLineBreak.class, StrongEmphasis.class, Text.class, - ThematicBreak.class + ThematicBreak.class, + Image.class }; final CorePlugin plugin = CorePlugin.create(); @@ -202,6 +205,7 @@ public class CorePluginTest { add("beforeSetText"); add("afterSetText"); add("priority"); + add("addOnTextAddedListener"); }}; // we will use declaredMethods because it won't return inherited ones diff --git a/markwon-core/src/test/java/io/noties/markwon/syntax/SyntaxHighlightTest.java b/markwon-core/src/test/java/io/noties/markwon/syntax/SyntaxHighlightTest.java index 3024fcc0..a591303e 100644 --- a/markwon-core/src/test/java/io/noties/markwon/syntax/SyntaxHighlightTest.java +++ b/markwon-core/src/test/java/io/noties/markwon/syntax/SyntaxHighlightTest.java @@ -26,7 +26,6 @@ import io.noties.markwon.SpanFactory; import io.noties.markwon.SpannableBuilder; import io.noties.markwon.core.CorePluginBridge; import io.noties.markwon.core.MarkwonTheme; -import io.noties.markwon.html.MarkwonHtmlRenderer; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -83,7 +82,7 @@ public class SyntaxHighlightTest { final MarkwonConfiguration configuration = MarkwonConfiguration.builder() .syntaxHighlight(highlight) - .build(mock(MarkwonTheme.class), mock(MarkwonHtmlRenderer.class), spansFactory); + .build(mock(MarkwonTheme.class), spansFactory); final Map, MarkwonVisitor.NodeVisitor> visitorMap = Collections.emptyMap(); diff --git a/markwon-ext-latex/README.md b/markwon-ext-latex/README.md index 620b05fa..442fc61e 100644 --- a/markwon-ext-latex/README.md +++ b/markwon-ext-latex/README.md @@ -1,3 +1,11 @@ # LaTeX -[Documentation](https://noties.github.io/Markwon/docs/ext-latex) +![stable](https://img.shields.io/maven-central/v/io.noties.markwon/ext-latex.svg) +![snapshot](https://img.shields.io/nexus/s/https/oss.sonatype.org/io.noties.markwon/ext-latex.svg) + +```kotlin +implementation "io.noties.markwon:ext-strikethrough:${markwonVersion}" +``` + + +[Documentation](https://noties.github.io/Markwon/docs/v3/ext-latex) diff --git a/markwon-ext-strikethrough/README.md b/markwon-ext-strikethrough/README.md index 1f99b846..8ef64b38 100644 --- a/markwon-ext-strikethrough/README.md +++ b/markwon-ext-strikethrough/README.md @@ -1,6 +1,12 @@ # Strikethrough -[![ext-strikethrough](https://img.shields.io/maven-central/v/io.noties.markwon/ext-strikethrough.svg?label=ext-strikethrough)](http://search.maven.org/#search|ga|1|g%3A%22io.noties.markwon%22%20AND%20a%3A%22ext-strikethrough%22) +![stable](https://img.shields.io/maven-central/v/io.noties.markwon/ext-strikethrough.svg) +![snapshot](https://img.shields.io/nexus/s/https/oss.sonatype.org/io.noties.markwon/ext-strikethrough.svg) + +```kotlin +implementation "io.noties.markwon:ext-strikethrough:${markwonVersion}" +``` + This module adds `strikethrough` functionality to `Markwon` via `StrikethroughPlugin`: diff --git a/markwon-image/build.gradle b/markwon-image/build.gradle index 2e0c86dd..16c70814 100644 --- a/markwon-image/build.gradle +++ b/markwon-image/build.gradle @@ -17,10 +17,11 @@ dependencies { api project(':markwon-core') + // todo: note that it includes these implicitly deps.with { - compileOnly it['android-gif'] - compileOnly it['android-svg'] - compileOnly it['okhttp'] + api it['android-gif'] + api it['android-svg'] + api it['okhttp'] } deps['test'].with { diff --git a/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderBuilder.java b/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderBuilder.java index 7f8c0dcb..7ee1116e 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderBuilder.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderBuilder.java @@ -9,7 +9,9 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import io.noties.markwon.image.data.DataUriSchemeHandler; +import io.noties.markwon.image.gif.GifMediaDecoder; import io.noties.markwon.image.network.NetworkSchemeHandler; +import io.noties.markwon.image.svg.SvgMediaDecoder; class AsyncDrawableLoaderBuilder { @@ -30,6 +32,15 @@ class AsyncDrawableLoaderBuilder { addSchemeHandler(DataUriSchemeHandler.create()); addSchemeHandler(NetworkSchemeHandler.create()); + // add SVG and GIF, but only if they are present in the class-path + if (SvgMediaDecoder.available()) { + addMediaDecoder(SvgMediaDecoder.create()); + } + + if (GifMediaDecoder.available()) { + addMediaDecoder(GifMediaDecoder.create()); + } + defaultMediaDecoder = DefaultImageMediaDecoder.create(); } diff --git a/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderImpl.java b/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderImpl.java index c03529d7..54e6c1b2 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderImpl.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderImpl.java @@ -92,8 +92,15 @@ class AsyncDrawableLoaderImpl extends AsyncDrawableLoader { Drawable drawable = null; try { + + final String scheme = uri.getScheme(); + if (scheme == null + || scheme.length() == 0) { + throw new IllegalStateException("No scheme is found: " + destination); + } + // obtain scheme handler - final SchemeHandler schemeHandler = schemeHandlers.get(uri.getScheme()); + final SchemeHandler schemeHandler = schemeHandlers.get(scheme); if (schemeHandler != null) { // handle scheme diff --git a/markwon-image/src/main/java/io/noties/markwon/image/gif/GifMediaDecoder.java b/markwon-image/src/main/java/io/noties/markwon/image/gif/GifMediaDecoder.java index d8757df4..508c6667 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/gif/GifMediaDecoder.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/gif/GifMediaDecoder.java @@ -10,9 +10,9 @@ import java.io.InputStream; import java.util.Collection; import java.util.Collections; +import io.noties.markwon.image.DrawableUtils; import io.noties.markwon.image.MediaDecoder; import pl.droidsonroids.gif.GifDrawable; -import io.noties.markwon.image.DrawableUtils; /** * @since 1.1.0 @@ -22,11 +22,29 @@ public class GifMediaDecoder extends MediaDecoder { public static final String CONTENT_TYPE = "image/gif"; + /** + * Creates a {@link GifMediaDecoder} with {@code autoPlayGif = true} + * + * @since 4.0.0-SNAPSHOT + */ + @NonNull + public static GifMediaDecoder create() { + return create(true); + } + @NonNull public static GifMediaDecoder create(boolean autoPlayGif) { return new GifMediaDecoder(autoPlayGif); } + /** + * @return boolean indicating if GIF dependency is satisfied + * @since 4.0.0-SNAPSHOT + */ + public static boolean available() { + return Holder.HAS_GIF; + } + private final boolean autoPlayGif; protected GifMediaDecoder(boolean autoPlayGif) { @@ -105,7 +123,8 @@ public class GifMediaDecoder extends MediaDecoder { static void validate() { if (!HAS_GIF) { throw new IllegalStateException("`pl.droidsonroids.gif:android-gif-drawable:*` " + - "dependency is missing, please add to your project explicitly"); + "dependency is missing, please add to your project explicitly if you " + + "wish to use GIF media decoder"); } } } diff --git a/markwon-image/src/main/java/io/noties/markwon/image/svg/SvgMediaDecoder.java b/markwon-image/src/main/java/io/noties/markwon/image/svg/SvgMediaDecoder.java index 229899c2..7482262e 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/svg/SvgMediaDecoder.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/svg/SvgMediaDecoder.java @@ -15,8 +15,8 @@ import java.io.InputStream; import java.util.Collection; import java.util.Collections; -import io.noties.markwon.image.MediaDecoder; import io.noties.markwon.image.DrawableUtils; +import io.noties.markwon.image.MediaDecoder; /** * @since 1.1.0 @@ -31,7 +31,7 @@ public class SvgMediaDecoder extends MediaDecoder { */ @NonNull public static SvgMediaDecoder create() { - return new SvgMediaDecoder(Resources.getSystem()); + return create(Resources.getSystem()); } @NonNull @@ -39,6 +39,14 @@ public class SvgMediaDecoder extends MediaDecoder { return new SvgMediaDecoder(resources); } + /** + * @return boolean indicating if SVG dependency is satisfied + * @since 4.0.0-SNAPSHOT + */ + public static boolean available() { + return Holder.HAS_SVG; + } + private final Resources resources; @SuppressWarnings("WeakerAccess") @@ -102,7 +110,7 @@ public class SvgMediaDecoder extends MediaDecoder { static void validate() { if (!HAS_SVG) { throw new IllegalStateException("`com.caverock:androidsvg:*` dependency is missing, " + - "please add to your project explicitly"); + "please add to your project explicitly if you wish to use SVG media decoder"); } } } diff --git a/markwon-image/src/test/java/io/noties/markwon/image/AsyncDrawableLoaderBuilderTest.java b/markwon-image/src/test/java/io/noties/markwon/image/AsyncDrawableLoaderBuilderTest.java index e08328d2..51006e38 100644 --- a/markwon-image/src/test/java/io/noties/markwon/image/AsyncDrawableLoaderBuilderTest.java +++ b/markwon-image/src/test/java/io/noties/markwon/image/AsyncDrawableLoaderBuilderTest.java @@ -10,8 +10,8 @@ import java.util.Arrays; import java.util.Collections; import java.util.concurrent.ExecutorService; -import io.noties.markwon.image.network.NetworkSchemeHandler; import io.noties.markwon.image.data.DataUriSchemeHandler; +import io.noties.markwon.image.network.NetworkSchemeHandler; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -62,7 +62,7 @@ public class AsyncDrawableLoaderBuilderTest { public void defaults_initialized() { // default-media-decoder and executor-service must be initialized - assertNull(builder.defaultMediaDecoder); + assertNotNull(builder.defaultMediaDecoder); assertNull(builder.executorService); builder.build(); @@ -71,6 +71,18 @@ public class AsyncDrawableLoaderBuilderTest { assertNotNull(builder.executorService); } + @Test + public void default_media_decoder_removed() { + // we init default-media-decoder right away, but further it can be removed (nulled-out) + + assertNotNull(builder.defaultMediaDecoder); + + builder.defaultMediaDecoder(null); + builder.build(); + + assertNull(builder.defaultMediaDecoder); + } + @Test public void executor() { // supplied executor-service must be used @@ -155,7 +167,7 @@ public class AsyncDrawableLoaderBuilderTest { @Test public void default_media_decoder() { - assertNull(builder.defaultMediaDecoder); + assertNotNull(builder.defaultMediaDecoder); final MediaDecoder mediaDecoder = mock(MediaDecoder.class); builder.defaultMediaDecoder(mediaDecoder); diff --git a/markwon-image/src/test/java/io/noties/markwon/image/AsyncDrawableLoaderImplTest.java b/markwon-image/src/test/java/io/noties/markwon/image/AsyncDrawableLoaderImplTest.java index 2737fcc6..c2e65dcd 100644 --- a/markwon-image/src/test/java/io/noties/markwon/image/AsyncDrawableLoaderImplTest.java +++ b/markwon-image/src/test/java/io/noties/markwon/image/AsyncDrawableLoaderImplTest.java @@ -1,5 +1,7 @@ package io.noties.markwon.image; +import android.graphics.drawable.Drawable; +import android.net.Uri; import android.os.Handler; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -7,15 +9,31 @@ import android.support.annotation.Nullable; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; +import java.io.InputStream; +import java.util.Collection; +import java.util.Collections; import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import io.noties.markwon.image.ImagesPlugin.ErrorHandler; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; @RunWith(RobolectricTestRunner.class) @Config(manifest = Config.NONE) @@ -40,60 +58,508 @@ public class AsyncDrawableLoaderImplTest { .providePlaceholder(any(AsyncDrawable.class)); } + @Test + public void load_cancel() { + // verify that load/cancel works as expected + + final ExecutorService executorService = mock(ExecutorService.class); + final Future future = mock(Future.class); + { + //noinspection unchecked + when(executorService.submit(any(Runnable.class))) + .thenReturn(future); + } + + final Handler handler = mock(Handler.class); + + final AsyncDrawable drawable = mock(AsyncDrawable.class); + + impl = builder + .executorService(executorService) + .handler(handler) + .build(); + + impl.load(drawable); + + verify(executorService, times(1)).submit(any(Runnable.class)); + + impl.cancel(drawable); + + verify(future, times(1)).cancel(eq(true)); + verify(handler, times(1)).removeCallbacksAndMessages(eq(drawable)); + } + + @Test + public void load_no_scheme_handler() { + // when loading is triggered for a scheme which has no registered scheme-handler + + final ErrorHandler errorHandler = mock(ErrorHandler.class); + + impl = builder + .executorService(immediateExecutorService()) + .errorHandler(errorHandler) + .build(); + + final String destination = "blah://blah.JPEG"; + + impl.load(asyncDrawable(destination)); + + final ArgumentCaptor throwableCaptor = ArgumentCaptor.forClass(Throwable.class); + verify(errorHandler, times(1)) + .handleError(eq(destination), throwableCaptor.capture()); + final Throwable value = throwableCaptor.getValue(); + assertTrue(value.getClass().getName(), value instanceof IllegalStateException); + assertTrue(value.getMessage(), value.getMessage().contains("No scheme-handler is found")); + assertTrue(value.getMessage(), value.getMessage().contains(destination)); + } + + @Test + public void load_scheme_handler_throws() { + + final ErrorHandler errorHandler = mock(ErrorHandler.class); + final SchemeHandler schemeHandler = new SchemeHandler() { + @NonNull + @Override + public ImageItem handle(@NonNull String raw, @NonNull Uri uri) { + throw new RuntimeException("We throw!"); + } + + @NonNull + @Override + public Collection supportedSchemes() { + return Collections.singleton("hey"); + } + }; + + impl = builder + .executorService(immediateExecutorService()) + .errorHandler(errorHandler) + .addSchemeHandler(schemeHandler) + .build(); + + final String destination = "hey://whe.er"; + + impl.load(asyncDrawable(destination)); + + final ArgumentCaptor captor = ArgumentCaptor.forClass(Throwable.class); + verify(errorHandler, times(1)) + .handleError(eq(destination), captor.capture()); + + final Throwable throwable = captor.getValue(); + assertTrue(throwable.getClass().getName(), throwable instanceof RuntimeException); + assertEquals("We throw!", throwable.getMessage()); + } + + @Test + public void load_scheme_handler_returns_result() { + + final Drawable drawable = mock(Drawable.class); + final SchemeHandler schemeHandler = new SchemeHandler() { + @NonNull + @Override + public ImageItem handle(@NonNull String raw, @NonNull Uri uri) { + return ImageItem.withResult(drawable); + } + + @NonNull + @Override + public Collection supportedSchemes() { + return Collections.singleton("*"); + } + }; + + final String destination = "*://yo"; + + final Future future = mock(Future.class); + final ExecutorService executorService = immediateExecutorService(future); + final Handler handler = mock(Handler.class); + + impl = builder + .executorService(executorService) + .handler(handler) + .addSchemeHandler(schemeHandler) + .build(); + + final AsyncDrawable asyncDrawable = asyncDrawable(destination); + + impl.load(asyncDrawable); + + verify(executorService, times(1)) + .submit(any(Runnable.class)); + + // we must use captor in order to let the internal (async) logic settle + final ArgumentCaptor captor = ArgumentCaptor.forClass(Runnable.class); + verify(handler, times(1)) + .postAtTime(captor.capture(), eq(asyncDrawable), anyLong()); + + captor.getValue().run(); + + verify(asyncDrawable, times(1)) + .setResult(eq(drawable)); + + // now, let's cancel the request (at this point it must be removed from referencing) + impl.cancel(asyncDrawable); + + verify(future, never()).cancel(anyBoolean()); + + // this method will be called anyway (we have no mean to check if token has queue) +// verify(handler, never()).removeCallbacksAndMessages(eq(asyncDrawable)); + } + + @Test + public void load_scheme_handler_returns_decoding_default_used() { + // we won't be registering media decoder, but provide a default one (which must be used) + + final MediaDecoder mediaDecoder = mock(MediaDecoder.class); + final InputStream inputStream = mock(InputStream.class); + final Drawable drawable = mock(Drawable.class); + + { + when(mediaDecoder.decode(any(String.class), any(InputStream.class))) + .thenReturn(drawable); + } + + impl = builder + .executorService(immediateExecutorService(mock(Future.class))) + .defaultMediaDecoder(mediaDecoder) + .addSchemeHandler(new SchemeHandler() { + @NonNull + @Override + public ImageItem handle(@NonNull String raw, @NonNull Uri uri) { + return ImageItem.withDecodingNeeded("no/op", inputStream); + } + + @NonNull + @Override + public Collection supportedSchemes() { + return Collections.singleton("whatever"); + } + }) + .build(); + + final String destination = "whatever://yeah-yeah-yeah"; + final AsyncDrawable asyncDrawable = asyncDrawable(destination); + + impl.load(asyncDrawable); + + verify(mediaDecoder, times(1)) + .decode(eq("no/op"), eq(inputStream)); + + final ArgumentCaptor captor = ArgumentCaptor.forClass(Runnable.class); + verify(builder._handler, times(1)) + .postAtTime(captor.capture(), eq(asyncDrawable), anyLong()); + + captor.getValue().run(); + + verify(asyncDrawable, times(1)) + .setResult(eq(drawable)); + } + + @Test + public void load_no_media_decoder_present() { + // if some content-type is requested (and it has no registered media-decoder), + // and default-media-decoder is not added -> throws + + final ErrorHandler errorHandler = mock(ErrorHandler.class); + + impl = builder + .defaultMediaDecoder(null) + .executorService(immediateExecutorService()) + .errorHandler(errorHandler) + .addSchemeHandler(new SchemeHandler() { + @NonNull + @Override + public ImageItem handle(@NonNull String raw, @NonNull Uri uri) { + return ImageItem.withDecodingNeeded("np/op", mock(InputStream.class)); + } + + @NonNull + @Override + public Collection supportedSchemes() { + return Collections.singleton("ftp"); + } + }) + .build(); + + final String destination = "ftp://xxx"; + final AsyncDrawable asyncDrawable = asyncDrawable(destination); + + impl.load(asyncDrawable); + + final ArgumentCaptor captor = ArgumentCaptor.forClass(Throwable.class); + + verify(errorHandler, times(1)) + .handleError(eq(destination), captor.capture()); + + final Throwable throwable = captor.getValue(); + assertTrue(throwable.getClass().getName(), throwable instanceof IllegalStateException); + assertTrue(throwable.getMessage(), throwable.getMessage().contains("No media-decoder is found")); + assertTrue(throwable.getMessage(), throwable.getMessage().contains(destination)); + } + + @Test + public void load_error_handler_drawable() { + // error-handler can return optional error-drawable that can be used as a result + + final ErrorHandler errorHandler = mock(ErrorHandler.class); + final Drawable drawable = mock(Drawable.class); + { + when(errorHandler.handleError(any(String.class), any(Throwable.class))) + .thenReturn(drawable); + } + + impl = builder + .executorService(immediateExecutorService(mock(Future.class))) + .errorHandler(errorHandler) + .build(); + + // we will rely on _internal_ error, which is also delivered to error-handler + // in this case -> no scheme-handler + + final String destination = "uo://uo?true=false"; + final AsyncDrawable asyncDrawable = asyncDrawable(destination); + + impl.load(asyncDrawable); + + verify(errorHandler, times(1)) + .handleError(eq(destination), any(Throwable.class)); + + final ArgumentCaptor captor = ArgumentCaptor.forClass(Runnable.class); + verify(builder._handler, times(1)) + .postAtTime(captor.capture(), eq(asyncDrawable), anyLong()); + + captor.getValue().run(); + + verify(asyncDrawable, times(1)) + .setResult(eq(drawable)); + } + + @Test + public void load_success_request_cancelled() { + // when loading finishes it must check if request had been cancelled and not deliver result + + impl = builder + .executorService(immediateExecutorService(mock(Future.class))) + .addSchemeHandler(new SchemeHandler() { + @NonNull + @Override + public ImageItem handle(@NonNull String raw, @NonNull Uri uri) { + return ImageItem.withResult(mock(Drawable.class)); + } + + @NonNull + @Override + public Collection supportedSchemes() { + return Collections.singleton("ja"); + } + }) + .build(); + + final String destination = "ja://jajaja"; + final AsyncDrawable asyncDrawable = asyncDrawable(destination); + + impl.load(asyncDrawable); + + final ArgumentCaptor captor = ArgumentCaptor.forClass(Runnable.class); + verify(builder._handler, times(1)) + .postAtTime(captor.capture(), eq(asyncDrawable), anyLong()); + + // now, cancel + impl.cancel(asyncDrawable); + + captor.getValue().run(); + + verify(asyncDrawable, never()) + .setResult(any(Drawable.class)); + } + + @Test + public void load_success_async_drawable_not_attached() { + // when loading finishes, it must check if async-drawable is attached + + impl = builder + .executorService(immediateExecutorService(mock(Future.class))) + .addSchemeHandler(new SchemeHandler() { + @NonNull + @Override + public ImageItem handle(@NonNull String raw, @NonNull Uri uri) { + return ImageItem.withResult(mock(Drawable.class)); + } + + @NonNull + @Override + public Collection supportedSchemes() { + return Collections.singleton("ha"); + } + }) + .build(); + + final String destination = "ha://hahaha"; + final AsyncDrawable asyncDrawable = asyncDrawable(destination); + when(asyncDrawable.isAttached()).thenReturn(false); + + impl.load(asyncDrawable); + + final ArgumentCaptor captor = ArgumentCaptor.forClass(Runnable.class); + verify(builder._handler, times(1)) + .postAtTime(captor.capture(), eq(asyncDrawable), anyLong()); + + captor.getValue().run(); + + verify(asyncDrawable, never()) + .setResult(any(Drawable.class)); + } + + @Test + public void load_success_result_null() { + // if result is null (but no exception) - no result must be delivered + + // we won't be adding scheme-handler, thus causing internal error + // (will have to mock error-handler because for the tests we re-throw errors) + impl = builder + .executorService(immediateExecutorService(mock(Future.class))) + .errorHandler(mock(ErrorHandler.class)) + .build(); + + final String destination = "xa://xaxaxa"; + final AsyncDrawable asyncDrawable = asyncDrawable(destination); + + impl.load(asyncDrawable); + + final ArgumentCaptor captor = ArgumentCaptor.forClass(Runnable.class); + verify(builder._handler, times(1)) + .postAtTime(captor.capture(), eq(asyncDrawable), anyLong()); + + captor.getValue().run(); + + verify(asyncDrawable, never()) + .setResult(any(Drawable.class)); + } + + @Test + public void media_decoder_is_used() { + + final MediaDecoder mediaDecoder = mock(MediaDecoder.class); + + { + when(mediaDecoder.decode(any(String.class), any(InputStream.class))) + .thenReturn(mock(Drawable.class)); + when(mediaDecoder.supportedTypes()) + .thenReturn(Collections.singleton("fa/ke")); + } + + impl = builder.executorService(immediateExecutorService()) + .addSchemeHandler(new SchemeHandler() { + @NonNull + @Override + public ImageItem handle(@NonNull String raw, @NonNull Uri uri) { + return ImageItem.withDecodingNeeded("fa/ke", mock(InputStream.class)); + } + + @NonNull + @Override + public Collection supportedSchemes() { + return Collections.singleton("fake"); + } + }) + .addMediaDecoder(mediaDecoder) + .build(); + + final String destination = "fake://1234"; + + impl.load(asyncDrawable(destination)); + + verify(mediaDecoder, times(1)) + .decode(eq("fa/ke"), any(InputStream.class)); + } + private static class BuilderImpl { - AsyncDrawableLoaderBuilder builder; - Handler handler = mock(Handler.class); + AsyncDrawableLoaderBuilder _builder = new AsyncDrawableLoaderBuilder(); + Handler _handler = mock(Handler.class); - public BuilderImpl executorService(@NonNull ExecutorService executorService) { - builder.executorService(executorService); + { + // be default it just logs the exception, let's rethrow + _builder.errorHandler(new ErrorHandler() { + @Nullable + @Override + public Drawable handleError(@NonNull String url, @NonNull Throwable throwable) { + throw new AsyncDrawableException(url, throwable); + } + }); + } + + BuilderImpl executorService(@NonNull ExecutorService executorService) { + _builder.executorService(executorService); return this; } - public BuilderImpl addSchemeHandler(@NonNull SchemeHandler schemeHandler) { - builder.addSchemeHandler(schemeHandler); + BuilderImpl addSchemeHandler(@NonNull SchemeHandler schemeHandler) { + _builder.addSchemeHandler(schemeHandler); return this; } - public BuilderImpl addMediaDecoder(@NonNull MediaDecoder mediaDecoder) { - builder.addMediaDecoder(mediaDecoder); + BuilderImpl addMediaDecoder(@NonNull MediaDecoder mediaDecoder) { + _builder.addMediaDecoder(mediaDecoder); return this; } - public BuilderImpl defaultMediaDecoder(@Nullable MediaDecoder mediaDecoder) { - builder.defaultMediaDecoder(mediaDecoder); + BuilderImpl defaultMediaDecoder(@Nullable MediaDecoder mediaDecoder) { + _builder.defaultMediaDecoder(mediaDecoder); return this; } - public BuilderImpl removeSchemeHandler(@NonNull String scheme) { - builder.removeSchemeHandler(scheme); + BuilderImpl placeholderProvider(@NonNull ImagesPlugin.PlaceholderProvider placeholderDrawableProvider) { + _builder.placeholderProvider(placeholderDrawableProvider); return this; } - public BuilderImpl removeMediaDecoder(@NonNull String contentType) { - builder.removeMediaDecoder(contentType); - return this; - } - - public BuilderImpl placeholderProvider(@NonNull ImagesPlugin.PlaceholderProvider placeholderDrawableProvider) { - builder.placeholderProvider(placeholderDrawableProvider); - return this; - } - - public BuilderImpl errorHandler(@NonNull ImagesPlugin.ErrorHandler errorHandler) { - builder.errorHandler(errorHandler); + BuilderImpl errorHandler(@NonNull ErrorHandler errorHandler) { + _builder.errorHandler(errorHandler); return this; } @NonNull - public BuilderImpl handler(Handler handler) { - this.handler = handler; + BuilderImpl handler(Handler handler) { + this._handler = handler; return this; } @NonNull AsyncDrawableLoaderImpl build() { - return new AsyncDrawableLoaderImpl(builder, handler); + return new AsyncDrawableLoaderImpl(_builder, _handler); + } + + private static class AsyncDrawableException extends RuntimeException { + AsyncDrawableException(String message, Throwable cause) { + super(message, cause); + } } } + + @NonNull + private static ExecutorService immediateExecutorService() { + return immediateExecutorService(null); + } + + @NonNull + private static ExecutorService immediateExecutorService(@Nullable final Future future) { + final ExecutorService service = mock(ExecutorService.class); + when(service.submit(any(Runnable.class))).then(new Answer() { + @Override + public Future answer(InvocationOnMock invocation) { + ((Runnable) invocation.getArgument(0)).run(); + return future; + } + }); + return service; + } + + @NonNull + private static AsyncDrawable asyncDrawable(@NonNull String destination) { + final AsyncDrawable drawable = mock(AsyncDrawable.class); + when(drawable.getDestination()).thenReturn(destination); + when(drawable.isAttached()).thenReturn(true); + return drawable; + } } \ No newline at end of file diff --git a/markwon-image/src/test/java/io/noties/markwon/image/ImagesPluginTest.java b/markwon-image/src/test/java/io/noties/markwon/image/ImagesPluginTest.java index 20e7feb5..27f2fbb9 100644 --- a/markwon-image/src/test/java/io/noties/markwon/image/ImagesPluginTest.java +++ b/markwon-image/src/test/java/io/noties/markwon/image/ImagesPluginTest.java @@ -18,7 +18,6 @@ import java.util.concurrent.ExecutorService; import io.noties.markwon.MarkwonConfiguration; import io.noties.markwon.MarkwonSpansFactory; import io.noties.markwon.SpanFactory; -import ru.noties.markwon.image.R; import io.noties.markwon.image.data.DataUriSchemeHandler; import static org.junit.Assert.assertNotNull; From a2a5857f06c041dab5513fff6c465dc6f9d50bb3 Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Sat, 8 Jun 2019 15:50:07 +0300 Subject: [PATCH 19/42] registryImpl test --- _CHANGES.md | 3 +- .../noties/markwon/app/MarkdownRenderer.java | 15 +- build.gradle | 2 +- .../io/noties/markwon/MarkwonBuilderImpl.java | 107 +--------- .../noties/markwon/MarkwonConfiguration.java | 42 ---- .../java/io/noties/markwon/RegistryImpl.java | 118 +++++++++++ .../markwon/html/MarkwonHtmlParserNoOp.java | 27 --- .../java/io/noties/markwon/MarkwonAssert.java | 15 ++ .../markwon/MarkwonBuilderImplTest.java | 34 --- .../io/noties/markwon/RegistryImplTest.java | 194 ++++++++++++++++++ .../io/noties/markwon/html/HtmlPlugin.java | 21 +- .../java/io/noties/markwon/html/HtmlTag.java | 0 .../markwon/html/MarkwonHtmlParser.java | 8 - .../markwon/html/MarkwonHtmlRenderer.java | 8 - .../markwon/html/MarkwonHtmlRendererNoOp.java | 0 .../io/noties/markwon/html/TagHandler.java | 0 .../io/noties/markwon/image/ImagesPlugin.java | 20 +- .../image/AsyncDrawableLoaderBuilderTest.java | 13 ++ .../markwon/image/ImagesPluginTest.java | 67 ++++++ 19 files changed, 447 insertions(+), 247 deletions(-) create mode 100644 markwon-core/src/main/java/io/noties/markwon/RegistryImpl.java delete mode 100644 markwon-core/src/main/java/io/noties/markwon/html/MarkwonHtmlParserNoOp.java create mode 100644 markwon-core/src/test/java/io/noties/markwon/MarkwonAssert.java create mode 100644 markwon-core/src/test/java/io/noties/markwon/RegistryImplTest.java rename {markwon-core => markwon-html}/src/main/java/io/noties/markwon/html/HtmlTag.java (100%) rename {markwon-core => markwon-html}/src/main/java/io/noties/markwon/html/MarkwonHtmlParser.java (91%) rename {markwon-core => markwon-html}/src/main/java/io/noties/markwon/html/MarkwonHtmlRenderer.java (73%) rename {markwon-core => markwon-html}/src/main/java/io/noties/markwon/html/MarkwonHtmlRendererNoOp.java (100%) rename {markwon-core => markwon-html}/src/main/java/io/noties/markwon/html/TagHandler.java (100%) diff --git a/_CHANGES.md b/_CHANGES.md index 28856328..0c8ea7de 100644 --- a/_CHANGES.md +++ b/_CHANGES.md @@ -8,4 +8,5 @@ * removed priority * images-plugin moved to standalone again * removed MarkwonPlugin#configureHtmlRenderer -> now part of HtmlPlugin -* TagHandler now has `supportedTags()` method \ No newline at end of file +* TagHandler now has `supportedTags()` method +* html is moved completely to html-plugin \ No newline at end of file diff --git a/app/src/main/java/io/noties/markwon/app/MarkdownRenderer.java b/app/src/main/java/io/noties/markwon/app/MarkdownRenderer.java index 667ef6a4..8d23ca68 100644 --- a/app/src/main/java/io/noties/markwon/app/MarkdownRenderer.java +++ b/app/src/main/java/io/noties/markwon/app/MarkdownRenderer.java @@ -13,27 +13,24 @@ import java.util.concurrent.Future; import javax.inject.Inject; +import io.noties.debug.Debug; import io.noties.markwon.AbstractMarkwonPlugin; import io.noties.markwon.Markwon; import io.noties.markwon.MarkwonConfiguration; +import io.noties.markwon.app.gif.GifAwarePlugin; import io.noties.markwon.ext.strikethrough.StrikethroughPlugin; import io.noties.markwon.ext.tables.TablePlugin; import io.noties.markwon.ext.tasklist.TaskListPlugin; -import io.noties.markwon.app.gif.GifAwarePlugin; import io.noties.markwon.html.HtmlPlugin; import io.noties.markwon.image.ImagesPlugin; -import io.noties.markwon.image.data.DataUriSchemeHandler; import io.noties.markwon.image.file.FileSchemeHandler; -import io.noties.markwon.image.gif.GifMediaDecoder; import io.noties.markwon.image.network.OkHttpNetworkSchemeHandler; -import io.noties.markwon.image.svg.SvgMediaDecoder; import io.noties.markwon.syntax.Prism4jTheme; import io.noties.markwon.syntax.Prism4jThemeDarkula; import io.noties.markwon.syntax.Prism4jThemeDefault; import io.noties.markwon.syntax.SyntaxHighlightPlugin; import io.noties.markwon.urlprocessor.UrlProcessor; import io.noties.markwon.urlprocessor.UrlProcessorRelativeToAbsolute; -import io.noties.debug.Debug; import ru.noties.prism4j.Prism4j; @ActivityScope @@ -102,12 +99,12 @@ public class MarkdownRenderer { .usePlugin(ImagesPlugin.create(new ImagesPlugin.ImagesConfigure() { @Override public void configureImages(@NonNull ImagesPlugin plugin) { + // data uri scheme handler is added automatically + // SVG & GIF will be added if required dependencies are present in the classpath + // default-media-decoder is also added automatically plugin - .addSchemeHandler(DataUriSchemeHandler.create()) .addSchemeHandler(OkHttpNetworkSchemeHandler.create()) - .addSchemeHandler(FileSchemeHandler.createWithAssets(context.getAssets())) - .addMediaDecoder(GifMediaDecoder.create(false)) - .addMediaDecoder(SvgMediaDecoder.create()); + .addSchemeHandler(FileSchemeHandler.createWithAssets(context.getAssets())); } })) .usePlugin(SyntaxHighlightPlugin.create(prism4j, prism4jTheme)) diff --git a/build.gradle b/build.gradle index 17105439..daec9a93 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ buildscript { } dependencies { classpath 'com.android.tools.build:gradle:3.4.1' - classpath 'com.github.ben-manes:gradle-versions-plugin:0.20.0' + classpath 'com.github.ben-manes:gradle-versions-plugin:0.21.0' } } diff --git a/markwon-core/src/main/java/io/noties/markwon/MarkwonBuilderImpl.java b/markwon-core/src/main/java/io/noties/markwon/MarkwonBuilderImpl.java index 7166aedc..4362fbfc 100644 --- a/markwon-core/src/main/java/io/noties/markwon/MarkwonBuilderImpl.java +++ b/markwon-core/src/main/java/io/noties/markwon/MarkwonBuilderImpl.java @@ -2,18 +2,14 @@ package io.noties.markwon; import android.content.Context; import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.VisibleForTesting; import android.widget.TextView; import org.commonmark.parser.Parser; import java.util.ArrayList; import java.util.Collections; -import java.util.HashSet; import java.util.Iterator; import java.util.List; -import java.util.Set; import io.noties.markwon.core.MarkwonTheme; @@ -106,109 +102,8 @@ class MarkwonBuilderImpl implements Markwon.Builder { ); } - @VisibleForTesting @NonNull - static List preparePlugins(@NonNull List plugins) { + private static List preparePlugins(@NonNull List plugins) { return new RegistryImpl(plugins).process(); } - - // @since 4.0.0-SNAPSHOT - private static class RegistryImpl implements MarkwonPlugin.Registry { - - private final List origin; - private final List plugins; - private final Set pending; - - RegistryImpl(@NonNull List origin) { - this.origin = origin; - this.plugins = new ArrayList<>(origin.size()); - this.pending = new HashSet<>(3); - } - - @NonNull - @Override - public

P require(@NonNull Class

plugin) { - return get(plugin); - } - - @Override - public

void require( - @NonNull Class

plugin, - @NonNull MarkwonPlugin.Action action) { - action.apply(get(plugin)); - } - - @NonNull - List process() { - for (MarkwonPlugin plugin : origin) { - configure(plugin); - } - return plugins; - } - - private void configure(@NonNull MarkwonPlugin plugin) { - - // important -> check if it's in plugins - // if it is -> no need to configure (already configured) - - if (!plugins.contains(plugin)) { - - if (pending.contains(plugin)) { - throw new IllegalStateException("Cyclic dependency chain found: " + pending); - } - - // start tracking plugins that are pending for configuration - pending.add(plugin); - - plugin.configure(this); - - // stop pending tracking - pending.remove(plugin); - - // check again if it's included (a child might've configured it already) - // add to out-collection if not already present - // this is a bit different from `find` method as it does check for exact instance - // and not a sub-type - if (!plugins.contains(plugin)) { - plugins.add(plugin); - } - } - } - - @NonNull - private

P get(@NonNull Class

type) { - - // check if present already in plugins - // find in origin, if not found -> throw, else add to out-plugins - - P plugin = find(plugins, type); - - if (plugin == null) { - - plugin = find(origin, type); - - if (plugin == null) { - throw new IllegalStateException("Requested plugin is not added: " + - "" + type.getName() + ", plugins: " + origin); - } - - configure(plugin); - } - - return plugin; - } - - @Nullable - private static

P find( - @NonNull List plugins, - @NonNull Class

type) { - for (MarkwonPlugin plugin : plugins) { - if (type.isAssignableFrom(plugin.getClass())) { - //noinspection unchecked - return (P) plugin; - } - } - return null; - } - } } diff --git a/markwon-core/src/main/java/io/noties/markwon/MarkwonConfiguration.java b/markwon-core/src/main/java/io/noties/markwon/MarkwonConfiguration.java index 9b4ffb95..a544ef6e 100644 --- a/markwon-core/src/main/java/io/noties/markwon/MarkwonConfiguration.java +++ b/markwon-core/src/main/java/io/noties/markwon/MarkwonConfiguration.java @@ -4,8 +4,6 @@ import android.support.annotation.NonNull; import io.noties.markwon.core.MarkwonTheme; import io.noties.markwon.core.spans.LinkSpan; -import io.noties.markwon.html.MarkwonHtmlParser; -import io.noties.markwon.html.MarkwonHtmlRenderer; import io.noties.markwon.image.AsyncDrawableLoader; import io.noties.markwon.image.ImageSizeResolver; import io.noties.markwon.image.ImageSizeResolverDef; @@ -31,8 +29,6 @@ public class MarkwonConfiguration { private final LinkSpan.Resolver linkResolver; private final UrlProcessor urlProcessor; private final ImageSizeResolver imageSizeResolver; - private final MarkwonHtmlParser htmlParser; - private final MarkwonHtmlRenderer htmlRenderer; // @since 3.0.0 private final MarkwonSpansFactory spansFactory; @@ -45,8 +41,6 @@ public class MarkwonConfiguration { this.urlProcessor = builder.urlProcessor; this.imageSizeResolver = builder.imageSizeResolver; this.spansFactory = builder.spansFactory; - this.htmlParser = builder.htmlParser; - this.htmlRenderer = builder.htmlRenderer; } @NonNull @@ -79,16 +73,6 @@ public class MarkwonConfiguration { return imageSizeResolver; } - @NonNull - public MarkwonHtmlParser htmlParser() { - return htmlParser; - } - - @NonNull - public MarkwonHtmlRenderer htmlRenderer() { - return htmlRenderer; - } - /** * @since 3.0.0 */ @@ -106,8 +90,6 @@ public class MarkwonConfiguration { private LinkSpan.Resolver linkResolver; private UrlProcessor urlProcessor; private ImageSizeResolver imageSizeResolver; - private MarkwonHtmlParser htmlParser; - private MarkwonHtmlRenderer htmlRenderer; private MarkwonSpansFactory spansFactory; Builder() { @@ -122,15 +104,6 @@ public class MarkwonConfiguration { return this; } - /** - * @since 4.0.0-SNAPSHOT - */ - @NonNull - public Builder htmlRenderer(@NonNull MarkwonHtmlRenderer htmlRenderer) { - this.htmlRenderer = htmlRenderer; - return this; - } - @NonNull public Builder syntaxHighlight(@NonNull SyntaxHighlight syntaxHighlight) { this.syntaxHighlight = syntaxHighlight; @@ -149,12 +122,6 @@ public class MarkwonConfiguration { return this; } - @NonNull - public Builder htmlParser(@NonNull MarkwonHtmlParser htmlParser) { - this.htmlParser = htmlParser; - return this; - } - /** * @since 1.0.1 */ @@ -177,11 +144,6 @@ public class MarkwonConfiguration { asyncDrawableLoader = AsyncDrawableLoader.noOp(); } - // @since 4.0.0-SNAPSHOT - if (htmlRenderer == null) { - htmlRenderer = MarkwonHtmlRenderer.noOp(); - } - if (syntaxHighlight == null) { syntaxHighlight = new SyntaxHighlightNoOp(); } @@ -198,10 +160,6 @@ public class MarkwonConfiguration { imageSizeResolver = new ImageSizeResolverDef(); } - if (htmlParser == null) { - htmlParser = MarkwonHtmlParser.noOp(); - } - return new MarkwonConfiguration(this); } } diff --git a/markwon-core/src/main/java/io/noties/markwon/RegistryImpl.java b/markwon-core/src/main/java/io/noties/markwon/RegistryImpl.java new file mode 100644 index 00000000..17a85dc8 --- /dev/null +++ b/markwon-core/src/main/java/io/noties/markwon/RegistryImpl.java @@ -0,0 +1,118 @@ +package io.noties.markwon; + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import io.noties.markwon.core.CorePlugin; + +// @since 4.0.0-SNAPSHOT +class RegistryImpl implements MarkwonPlugin.Registry { + + // todo: core-plugin must be (better be) first any way + + private final List origin; + private final List plugins; + private final Set pending; + + RegistryImpl(@NonNull List origin) { + this.origin = origin; + this.plugins = new ArrayList<>(origin.size()); + this.pending = new HashSet<>(3); + } + + @NonNull + @Override + public

P require(@NonNull Class

plugin) { + return get(plugin); + } + + @Override + public

void require( + @NonNull Class

plugin, + @NonNull MarkwonPlugin.Action action) { + action.apply(get(plugin)); + } + + @NonNull + List process() { + for (MarkwonPlugin plugin : origin) { + configure(plugin); + } + return plugins; + } + + private void configure(@NonNull MarkwonPlugin plugin) { + + // important -> check if it's in plugins + // if it is -> no need to configure (already configured) + + if (!plugins.contains(plugin)) { + + if (pending.contains(plugin)) { + throw new IllegalStateException("Cyclic dependency chain found: " + pending); + } + + // start tracking plugins that are pending for configuration + pending.add(plugin); + + plugin.configure(this); + + // stop pending tracking + pending.remove(plugin); + + // check again if it's included (a child might've configured it already) + // add to out-collection if not already present + // this is a bit different from `find` method as it does check for exact instance + // and not a sub-type + if (!plugins.contains(plugin)) { + // core-plugin must always be the first one (if it's present) + if (CorePlugin.class.isAssignableFrom(plugin.getClass())) { + plugins.add(0, plugin); + } else { + plugins.add(plugin); + } + } + } + } + + @NonNull + private

P get(@NonNull Class

type) { + + // check if present already in plugins + // find in origin, if not found -> throw, else add to out-plugins + + P plugin = find(plugins, type); + + if (plugin == null) { + + plugin = find(origin, type); + + if (plugin == null) { + throw new IllegalStateException("Requested plugin is not added: " + + "" + type.getName() + ", plugins: " + origin); + } + + configure(plugin); + } + + return plugin; + } + + @Nullable + private static

P find( + @NonNull List plugins, + @NonNull Class

type) { + for (MarkwonPlugin plugin : plugins) { + if (type.isAssignableFrom(plugin.getClass())) { + //noinspection unchecked + return (P) plugin; + } + } + return null; + } +} diff --git a/markwon-core/src/main/java/io/noties/markwon/html/MarkwonHtmlParserNoOp.java b/markwon-core/src/main/java/io/noties/markwon/html/MarkwonHtmlParserNoOp.java deleted file mode 100644 index 9057630b..00000000 --- a/markwon-core/src/main/java/io/noties/markwon/html/MarkwonHtmlParserNoOp.java +++ /dev/null @@ -1,27 +0,0 @@ -package io.noties.markwon.html; - -import android.support.annotation.NonNull; - -import java.util.Collections; - -class MarkwonHtmlParserNoOp extends MarkwonHtmlParser { - @Override - public void processFragment(@NonNull T output, @NonNull String htmlFragment) { - // no op - } - - @Override - public void flushInlineTags(int documentLength, @NonNull FlushAction action) { - action.apply(Collections.emptyList()); - } - - @Override - public void flushBlockTags(int documentLength, @NonNull FlushAction action) { - action.apply(Collections.emptyList()); - } - - @Override - public void reset() { - // no op - } -} diff --git a/markwon-core/src/test/java/io/noties/markwon/MarkwonAssert.java b/markwon-core/src/test/java/io/noties/markwon/MarkwonAssert.java new file mode 100644 index 00000000..b220c7f8 --- /dev/null +++ b/markwon-core/src/test/java/io/noties/markwon/MarkwonAssert.java @@ -0,0 +1,15 @@ +package io.noties.markwon; + +import android.support.annotation.NonNull; + +import org.junit.Assert; + +public abstract class MarkwonAssert { + + public static void assertMessageContains(@NonNull Throwable t, @NonNull String contains) { + Assert.assertTrue(t.getMessage(), t.getMessage().contains(contains)); + } + + private MarkwonAssert() { + } +} diff --git a/markwon-core/src/test/java/io/noties/markwon/MarkwonBuilderImplTest.java b/markwon-core/src/test/java/io/noties/markwon/MarkwonBuilderImplTest.java index 84a3a38e..bc0fd409 100644 --- a/markwon-core/src/test/java/io/noties/markwon/MarkwonBuilderImplTest.java +++ b/markwon-core/src/test/java/io/noties/markwon/MarkwonBuilderImplTest.java @@ -12,7 +12,6 @@ import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import io.noties.markwon.core.MarkwonTheme; -import io.noties.markwon.html.MarkwonHtmlRenderer; import static org.hamcrest.Matchers.containsString; import static org.junit.Assert.assertThat; @@ -27,39 +26,6 @@ import static org.mockito.Mockito.verify; @Config(manifest = Config.NONE) public class MarkwonBuilderImplTest { - @Test - public void prepare_plugins() { - // validate that prepare plugins is calling `ensureImplicitCoreIfHasDependents` and - // priority processor - -// final PriorityProcessor priorityProcessor = mock(PriorityProcessor.class); -// when(priorityProcessor.process(ArgumentMatchers.anyList())) -// .thenAnswer(new Answer() { -// @Override -// public Object answer(InvocationOnMock invocation) { -// return invocation.getArgument(0); -// } -// }); -// -// final MarkwonPlugin plugin = new AbstractMarkwonPlugin() { -// @NonNull -// @Override -// public Priority priority() { -// return Priority.after(CorePlugin.class); -// } -// }; -// -// final List plugins = preparePlugins(priorityProcessor, Collections.singletonList(plugin)); -// assertThat(plugins, hasSize(2)); -// assertThat(plugins, hasItem(plugin)); -// assertThat(plugins, hasItem(isA(CorePlugin.class))); -// -// verify(priorityProcessor, times(1)) -// .process(ArgumentMatchers.anyList()); - - fail(); - } - @Test public void no_plugins_added_throws() { // there is no sense in having an instance with no plugins registered diff --git a/markwon-core/src/test/java/io/noties/markwon/RegistryImplTest.java b/markwon-core/src/test/java/io/noties/markwon/RegistryImplTest.java new file mode 100644 index 00000000..283a799e --- /dev/null +++ b/markwon-core/src/test/java/io/noties/markwon/RegistryImplTest.java @@ -0,0 +1,194 @@ +package io.noties.markwon; + +import android.support.annotation.NonNull; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import io.noties.markwon.core.CorePlugin; + +import static io.noties.markwon.MarkwonAssert.assertMessageContains; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; + +@RunWith(RobolectricTestRunner.class) +@Config(manifest = Config.NONE) +public class RegistryImplTest { + + @Test + public void single_plugin_requires_self() { + // detect recursive require + + final class Plugin extends AbstractMarkwonPlugin { + @Override + public void configure(@NonNull Registry registry) { + registry.require(Plugin.class); + } + } + final MarkwonPlugin plugin = new Plugin(); + + final RegistryImpl impl = new RegistryImpl(Collections.singletonList(plugin)); + + try { + impl.process(); + } catch (Throwable t) { + assertMessageContains(t, "Cyclic dependency chain found"); + } + } + + @Test + public void plugins_dependency_cycle() { + + final Map> map = new HashMap<>(); + + final class A extends AbstractMarkwonPlugin { + @Override + public void configure(@NonNull Registry registry) { + //noinspection ConstantConditions + registry.require(map.get("A")); + } + } + + final class B extends AbstractMarkwonPlugin { + @Override + public void configure(@NonNull Registry registry) { + //noinspection ConstantConditions + registry.require(map.get("B")); + } + } + + final class C extends AbstractMarkwonPlugin { + @Override + public void configure(@NonNull Registry registry) { + //noinspection ConstantConditions + registry.require(map.get("C")); + } + } + + map.put("A", B.class); + map.put("B", C.class); + map.put("C", A.class); + + final RegistryImpl impl = + new RegistryImpl(Arrays.asList((MarkwonPlugin) new A(), new B(), new C())); + + try { + impl.process(); + fail(); + } catch (Throwable t) { + assertMessageContains(t, "Cyclic dependency chain found"); + } + } + + @Test + public void plugins_no_dependency_cycle() { + + final class C extends AbstractMarkwonPlugin { + } + + final class B extends AbstractMarkwonPlugin { + @Override + public void configure(@NonNull Registry registry) { + registry.require(C.class); + } + } + + final class A extends AbstractMarkwonPlugin { + @Override + public void configure(@NonNull Registry registry) { + registry.require(B.class); + } + } + + final RegistryImpl impl = + new RegistryImpl(Arrays.asList((MarkwonPlugin) new A(), new B(), new C())); + + impl.process(); + } + + @Test + public void dependency_not_satisfied() { + // when require is called for plugin not added + + final class A extends AbstractMarkwonPlugin { + } + + final class B extends AbstractMarkwonPlugin { + @Override + public void configure(@NonNull Registry registry) { + registry.require(A.class); + } + } + + final RegistryImpl impl = + new RegistryImpl(Collections.singletonList((MarkwonPlugin) new B())); + + try { + impl.process(); + fail(); + } catch (Throwable t) { + assertMessageContains(t, "Requested plugin is not added"); + assertMessageContains(t, A.class.getName()); // ? if it's null for local class? + } + } + + @Test + public void core_plugin_first() { + // if core-plugin is present, hen it should be the first one + + final CorePlugin plugin = CorePlugin.create(); + + final RegistryImpl impl = new RegistryImpl(Arrays.asList( + mock(MarkwonPlugin.class), + mock(MarkwonPlugin.class), + plugin + )); + + final List plugins = impl.process(); + assertEquals(3, plugins.size()); + assertEquals(plugin, plugins.get(0)); + } + + @Test + public void correct_order() { + + final class A extends AbstractMarkwonPlugin { + } + + final class B extends AbstractMarkwonPlugin { + @Override + public void configure(@NonNull Registry registry) { + registry.require(A.class); + } + } + + final class C extends AbstractMarkwonPlugin { + @Override + public void configure(@NonNull Registry registry) { + registry.require(B.class); + } + } + + final A a = new A(); + final B b = new B(); + final C c = new C(); + + final RegistryImpl impl = new RegistryImpl(Arrays.asList( + (MarkwonPlugin) c, b, a)); + + final List plugins = impl.process(); + assertEquals(3, plugins.size()); + assertEquals(a, plugins.get(0)); + assertEquals(b, plugins.get(1)); + assertEquals(c, plugins.get(2)); + } +} \ No newline at end of file diff --git a/markwon-html/src/main/java/io/noties/markwon/html/HtmlPlugin.java b/markwon-html/src/main/java/io/noties/markwon/html/HtmlPlugin.java index 526fb323..6a20ada6 100644 --- a/markwon-html/src/main/java/io/noties/markwon/html/HtmlPlugin.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/HtmlPlugin.java @@ -7,13 +7,13 @@ import org.commonmark.node.HtmlBlock; import org.commonmark.node.HtmlInline; import org.commonmark.node.Node; -import io.noties.markwon.html.tag.ImageHandler; import io.noties.markwon.AbstractMarkwonPlugin; import io.noties.markwon.MarkwonConfiguration; import io.noties.markwon.MarkwonVisitor; import io.noties.markwon.html.tag.BlockquoteHandler; import io.noties.markwon.html.tag.EmphasisHandler; import io.noties.markwon.html.tag.HeadingHandler; +import io.noties.markwon.html.tag.ImageHandler; import io.noties.markwon.html.tag.LinkHandler; import io.noties.markwon.html.tag.ListHandler; import io.noties.markwon.html.tag.StrikeHandler; @@ -53,10 +53,13 @@ public class HtmlPlugin extends AbstractMarkwonPlugin { public static final float SCRIPT_DEF_TEXT_SIZE_RATIO = .75F; private final MarkwonHtmlRendererImpl.Builder builder; + private final MarkwonHtmlParser htmlParser; + private MarkwonHtmlRenderer htmlRenderer; @SuppressWarnings("WeakerAccess") HtmlPlugin() { this.builder = new MarkwonHtmlRendererImpl.Builder(); + this.htmlParser = MarkwonHtmlParserImpl.create(); } /** @@ -104,6 +107,8 @@ public class HtmlPlugin extends AbstractMarkwonPlugin { @Override public void configureConfiguration(@NonNull MarkwonConfiguration.Builder configurationBuilder) { + // @since 4.0.0-SNAPSHOT we init internal html-renderer here (marks the end of configuration) + final MarkwonHtmlRendererImpl.Builder builder = this.builder; if (!builder.excludeDefaults()) { @@ -123,15 +128,17 @@ public class HtmlPlugin extends AbstractMarkwonPlugin { builder.addDefaultTagHandler(new HeadingHandler()); } - configurationBuilder - .htmlRenderer(builder.build()) - .htmlParser(MarkwonHtmlParserImpl.create()); + htmlRenderer = builder.build(); } @Override public void afterRender(@NonNull Node node, @NonNull MarkwonVisitor visitor) { - final MarkwonConfiguration configuration = visitor.configuration(); - configuration.htmlRenderer().render(visitor, configuration.htmlParser()); + final MarkwonHtmlRenderer htmlRenderer = this.htmlRenderer; + if (htmlRenderer != null) { + htmlRenderer.render(visitor, htmlParser); + } else { + throw new IllegalStateException("Unexpected state, html-renderer is not defined"); + } } @Override @@ -153,7 +160,7 @@ public class HtmlPlugin extends AbstractMarkwonPlugin { private void visitHtml(@NonNull MarkwonVisitor visitor, @Nullable String html) { if (html != null) { - visitor.configuration().htmlParser().processFragment(visitor.builder(), html); + htmlParser.processFragment(visitor.builder(), html); } } } diff --git a/markwon-core/src/main/java/io/noties/markwon/html/HtmlTag.java b/markwon-html/src/main/java/io/noties/markwon/html/HtmlTag.java similarity index 100% rename from markwon-core/src/main/java/io/noties/markwon/html/HtmlTag.java rename to markwon-html/src/main/java/io/noties/markwon/html/HtmlTag.java diff --git a/markwon-core/src/main/java/io/noties/markwon/html/MarkwonHtmlParser.java b/markwon-html/src/main/java/io/noties/markwon/html/MarkwonHtmlParser.java similarity index 91% rename from markwon-core/src/main/java/io/noties/markwon/html/MarkwonHtmlParser.java rename to markwon-html/src/main/java/io/noties/markwon/html/MarkwonHtmlParser.java index ec3b32c8..368306a7 100644 --- a/markwon-core/src/main/java/io/noties/markwon/html/MarkwonHtmlParser.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/MarkwonHtmlParser.java @@ -9,14 +9,6 @@ import java.util.List; */ public abstract class MarkwonHtmlParser { - /** - * Factory method to create a `no-op` implementation (no parsing) - */ - @NonNull - public static MarkwonHtmlParser noOp() { - return new MarkwonHtmlParserNoOp(); - } - public interface FlushAction { void apply(@NonNull List tags); } diff --git a/markwon-core/src/main/java/io/noties/markwon/html/MarkwonHtmlRenderer.java b/markwon-html/src/main/java/io/noties/markwon/html/MarkwonHtmlRenderer.java similarity index 73% rename from markwon-core/src/main/java/io/noties/markwon/html/MarkwonHtmlRenderer.java rename to markwon-html/src/main/java/io/noties/markwon/html/MarkwonHtmlRenderer.java index 26970f2a..f0e87f37 100644 --- a/markwon-core/src/main/java/io/noties/markwon/html/MarkwonHtmlRenderer.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/MarkwonHtmlRenderer.java @@ -10,14 +10,6 @@ import io.noties.markwon.MarkwonVisitor; */ public abstract class MarkwonHtmlRenderer { - /** - * @since 4.0.0-SNAPSHOT - */ - @NonNull - public static MarkwonHtmlRenderer noOp() { - return new MarkwonHtmlRendererNoOp(); - } - public abstract void render( @NonNull MarkwonVisitor visitor, @NonNull MarkwonHtmlParser parser diff --git a/markwon-core/src/main/java/io/noties/markwon/html/MarkwonHtmlRendererNoOp.java b/markwon-html/src/main/java/io/noties/markwon/html/MarkwonHtmlRendererNoOp.java similarity index 100% rename from markwon-core/src/main/java/io/noties/markwon/html/MarkwonHtmlRendererNoOp.java rename to markwon-html/src/main/java/io/noties/markwon/html/MarkwonHtmlRendererNoOp.java diff --git a/markwon-core/src/main/java/io/noties/markwon/html/TagHandler.java b/markwon-html/src/main/java/io/noties/markwon/html/TagHandler.java similarity index 100% rename from markwon-core/src/main/java/io/noties/markwon/html/TagHandler.java rename to markwon-html/src/main/java/io/noties/markwon/html/TagHandler.java diff --git a/markwon-image/src/main/java/io/noties/markwon/image/ImagesPlugin.java b/markwon-image/src/main/java/io/noties/markwon/image/ImagesPlugin.java index 4d7ad275..7a9a8df8 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/ImagesPlugin.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/ImagesPlugin.java @@ -3,6 +3,7 @@ package io.noties.markwon.image; import android.graphics.drawable.Drawable; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.support.annotation.VisibleForTesting; import android.text.Spanned; import android.widget.TextView; @@ -10,16 +11,16 @@ import org.commonmark.node.Image; import java.util.concurrent.ExecutorService; +import io.noties.markwon.AbstractMarkwonPlugin; +import io.noties.markwon.MarkwonConfiguration; import io.noties.markwon.MarkwonPlugin; +import io.noties.markwon.MarkwonSpansFactory; import io.noties.markwon.image.data.DataUriSchemeHandler; import io.noties.markwon.image.file.FileSchemeHandler; import io.noties.markwon.image.gif.GifMediaDecoder; import io.noties.markwon.image.network.NetworkSchemeHandler; import io.noties.markwon.image.network.OkHttpNetworkSchemeHandler; import io.noties.markwon.image.svg.SvgMediaDecoder; -import io.noties.markwon.AbstractMarkwonPlugin; -import io.noties.markwon.MarkwonConfiguration; -import io.noties.markwon.MarkwonSpansFactory; @SuppressWarnings({"UnusedReturnValue", "WeakerAccess"}) public class ImagesPlugin extends AbstractMarkwonPlugin { @@ -70,7 +71,18 @@ public class ImagesPlugin extends AbstractMarkwonPlugin { return plugin; } - private final AsyncDrawableLoaderBuilder builder = new AsyncDrawableLoaderBuilder(); + private final AsyncDrawableLoaderBuilder builder; + + // @since 4.0.0-SNAPSHOT + ImagesPlugin() { + this(new AsyncDrawableLoaderBuilder()); + } + + // @since 4.0.0-SNAPSHOT + @VisibleForTesting + ImagesPlugin(@NonNull AsyncDrawableLoaderBuilder builder) { + this.builder = builder; + } /** * Optional (by default new cached thread executor will be used) diff --git a/markwon-image/src/test/java/io/noties/markwon/image/AsyncDrawableLoaderBuilderTest.java b/markwon-image/src/test/java/io/noties/markwon/image/AsyncDrawableLoaderBuilderTest.java index 51006e38..a5861f6b 100644 --- a/markwon-image/src/test/java/io/noties/markwon/image/AsyncDrawableLoaderBuilderTest.java +++ b/markwon-image/src/test/java/io/noties/markwon/image/AsyncDrawableLoaderBuilderTest.java @@ -18,6 +18,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -203,4 +204,16 @@ public class AsyncDrawableLoaderBuilderTest { builder.removeMediaDecoder(media); assertNull(builder.mediaDecoders.get(media)); } + + @Test + public void cannot_build_twice() { + + builder.build(); + try { + builder.build(); + fail(); + } catch (Throwable t) { + assertTrue(t.getMessage(), t.getMessage().contains("has already been configured")); + } + } } \ No newline at end of file diff --git a/markwon-image/src/test/java/io/noties/markwon/image/ImagesPluginTest.java b/markwon-image/src/test/java/io/noties/markwon/image/ImagesPluginTest.java index 27f2fbb9..f19b1563 100644 --- a/markwon-image/src/test/java/io/noties/markwon/image/ImagesPluginTest.java +++ b/markwon-image/src/test/java/io/noties/markwon/image/ImagesPluginTest.java @@ -27,6 +27,7 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; @RunWith(RobolectricTestRunner.class) @@ -175,4 +176,70 @@ public class ImagesPluginTest { verify(textView, times(1)) .getTag(eq(R.id.markwon_drawables_scheduler_last_text_hashcode)); } + + @Test + public void methods_redirected_to_builder() { + + final AsyncDrawableLoaderBuilder builder = mock(AsyncDrawableLoaderBuilder.class); + final ImagesPlugin plugin = new ImagesPlugin(builder); + + // executor service + { + final ExecutorService executorService = mock(ExecutorService.class); + plugin.executorService(executorService); + verify(builder, times(1)).executorService(eq(executorService)); + } + + // add scheme-handler + { + final SchemeHandler schemeHandler = mock(SchemeHandler.class); + plugin.addSchemeHandler(schemeHandler); + verify(builder, times(1)).addSchemeHandler(eq(schemeHandler)); + } + + // add media-decoder + { + final MediaDecoder mediaDecoder = mock(MediaDecoder.class); + plugin.addMediaDecoder(mediaDecoder); + verify(builder, times(1)).addMediaDecoder(eq(mediaDecoder)); + } + + // default-media-decoder + { + final MediaDecoder mediaDecoder = mock(MediaDecoder.class); + plugin.defaultMediaDecoder(mediaDecoder); + verify(builder, times(1)).defaultMediaDecoder(eq(mediaDecoder)); + } + + // remove scheme-handler + { + final String scheme = "yo"; + plugin.removeSchemeHandler(scheme); + verify(builder, times(1)).removeSchemeHandler(eq(scheme)); + } + + // remove media-decoder + { + final String contentType = "fa/ke"; + plugin.removeMediaDecoder(contentType); + verify(builder, times(1)).removeMediaDecoder(eq(contentType)); + } + + // placeholder provider + { + final ImagesPlugin.PlaceholderProvider placeholderProvider = + mock(ImagesPlugin.PlaceholderProvider.class); + plugin.placeholderProvider(placeholderProvider); + verify(builder, times(1)).placeholderProvider(eq(placeholderProvider)); + } + + // error-handler + { + final ImagesPlugin.ErrorHandler errorHandler = mock(ImagesPlugin.ErrorHandler.class); + plugin.errorHandler(errorHandler); + verify(builder, times(1)).errorHandler(eq(errorHandler)); + } + + verifyNoMoreInteractions(builder); + } } \ No newline at end of file From 9aade9d6caf82068824d069826085120a5977506 Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Tue, 11 Jun 2019 18:42:14 +0300 Subject: [PATCH 20/42] Migrate to androidx --- README.md | 2 +- .../debug/DebugCheckboxDrawableView.java | 2 +- .../main/java/io/noties/markwon/app/App.java | 3 +- .../io/noties/markwon/app/AppBarItem.java | 3 +- .../java/io/noties/markwon/app/AppModule.java | 4 +- .../io/noties/markwon/app/MainActivity.java | 7 +- .../io/noties/markwon/app/MarkdownLoader.java | 7 +- .../noties/markwon/app/MarkdownRenderer.java | 7 +- .../java/io/noties/markwon/app/Themes.java | 3 +- .../io/noties/markwon/app/UriProcessor.java | 3 +- .../noties/markwon/app/UriProcessorImpl.java | 5 +- .../app/UrlProcessorInitialReadme.java | 3 +- .../java/io/noties/markwon/app/Views.java | 5 +- .../app/gif/GifAwareAsyncDrawable.java | 5 +- .../markwon/app/gif/GifAwarePlugin.java | 3 +- .../markwon/app/gif/GifPlaceholder.java | 7 +- .../noties/markwon/app/gif/GifProcessor.java | 5 +- build.gradle | 10 +- gradle.properties | 2 + markwon-core/build.gradle | 2 +- .../noties/markwon/AbstractMarkwonPlugin.java | 3 +- .../io/noties/markwon/LinkResolverDef.java | 3 +- .../main/java/io/noties/markwon/Markwon.java | 5 +- .../io/noties/markwon/MarkwonBuilderImpl.java | 3 +- .../noties/markwon/MarkwonConfiguration.java | 2 +- .../java/io/noties/markwon/MarkwonImpl.java | 5 +- .../noties/markwon/MarkwonNodeRenderer.java | 184 ------------------ .../java/io/noties/markwon/MarkwonPlugin.java | 3 +- .../io/noties/markwon/MarkwonReducer.java | 2 +- .../noties/markwon/MarkwonSpansFactory.java | 4 +- .../markwon/MarkwonSpansFactoryImpl.java | 4 +- .../io/noties/markwon/MarkwonVisitor.java | 4 +- .../io/noties/markwon/MarkwonVisitorImpl.java | 4 +- .../src/main/java/io/noties/markwon/Prop.java | 4 +- .../java/io/noties/markwon/RegistryImpl.java | 6 +- .../java/io/noties/markwon/RenderProps.java | 4 +- .../io/noties/markwon/RenderPropsImpl.java | 4 +- .../java/io/noties/markwon/SpanFactory.java | 4 +- .../io/noties/markwon/SpannableBuilder.java | 7 +- .../io/noties/markwon/core/CorePlugin.java | 13 +- .../io/noties/markwon/core/MarkwonTheme.java | 11 +- .../markwon/core/SimpleBlockNodeVisitor.java | 2 +- .../core/factory/BlockQuoteSpanFactory.java | 6 +- .../core/factory/CodeBlockSpanFactory.java | 6 +- .../markwon/core/factory/CodeSpanFactory.java | 6 +- .../core/factory/EmphasisSpanFactory.java | 6 +- .../core/factory/HeadingSpanFactory.java | 8 +- .../markwon/core/factory/LinkSpanFactory.java | 8 +- .../core/factory/ListItemSpanFactory.java | 10 +- .../factory/StrongEmphasisSpanFactory.java | 6 +- .../factory/ThematicBreakSpanFactory.java | 6 +- .../markwon/core/spans/BlockQuoteSpan.java | 3 +- .../core/spans/BulletListItemSpan.java | 5 +- .../markwon/core/spans/CodeBlockSpan.java | 3 +- .../noties/markwon/core/spans/CodeSpan.java | 3 +- .../core/spans/CustomTypefaceSpan.java | 3 +- .../markwon/core/spans/HeadingSpan.java | 5 +- .../noties/markwon/core/spans/LinkSpan.java | 3 +- .../core/spans/OrderedListItemSpan.java | 3 +- .../markwon/core/spans/ThematicBreakSpan.java | 3 +- .../noties/markwon/image/AsyncDrawable.java | 7 +- .../markwon/image/AsyncDrawableLoader.java | 5 +- .../image/AsyncDrawableLoaderNoOp.java | 5 +- .../markwon/image/AsyncDrawableScheduler.java | 5 +- .../markwon/image/AsyncDrawableSpan.java | 9 +- .../noties/markwon/image/DrawableUtils.java | 5 +- .../io/noties/markwon/image/ImageSize.java | 2 +- .../markwon/image/ImageSizeResolver.java | 5 +- .../markwon/image/ImageSizeResolverDef.java | 5 +- .../markwon/image/ImageSpanFactory.java | 4 +- .../movement/MovementMethodPlugin.java | 3 +- .../markwon/syntax/SyntaxHighlight.java | 4 +- .../markwon/syntax/SyntaxHighlightNoOp.java | 4 +- .../markwon/urlprocessor/UrlProcessor.java | 2 +- .../UrlProcessorAndroidAssets.java | 5 +- .../urlprocessor/UrlProcessorNoOp.java | 2 +- .../UrlProcessorRelativeToAbsolute.java | 4 +- .../java/io/noties/markwon/utils/Dip.java | 3 +- .../noties/markwon/utils/DrawableUtils.java | 3 +- .../io/noties/markwon/utils/DumpNodes.java | 4 +- .../markwon/utils/NoCopySpannableFactory.java | 3 +- .../markwon/AbstractMarkwonVisitorImpl.java | 2 +- .../java/io/noties/markwon/MarkwonAssert.java | 2 +- .../io/noties/markwon/RegistryImplTest.java | 2 +- .../noties/markwon/SpannableBuilderTest.java | 2 +- .../noties/markwon/core/CorePluginBridge.java | 4 +- .../noties/markwon/core/CorePluginTest.java | 4 +- .../java/io/noties/markwon/core/CoreTest.java | 2 +- .../markwon/core/suite/BaseSuiteTest.java | 4 +- .../markwon/image/AsyncDrawableTest.java | 4 +- .../io/noties/markwon/image/ImageTest.java | 2 +- .../markwon/syntax/SyntaxHighlightTest.java | 5 +- .../markwon/ext/latex/JLatexMathPlugin.java | 15 +- .../strikethrough/StrikethroughPlugin.java | 3 +- .../StrikethroughPluginTest.java | 2 +- .../io/noties/markwon/ext/tables/Table.java | 5 +- .../markwon/ext/tables/TablePlugin.java | 3 +- .../markwon/ext/tables/TableRowSpan.java | 9 +- .../ext/tables/TableRowsScheduler.java | 5 +- .../noties/markwon/ext/tables/TableTheme.java | 7 +- markwon-ext-tasklist/build.gradle | 1 + .../ext/tasklist/TaskListBlockParser.java | 4 +- .../ext/tasklist/TaskListDrawable.java | 14 +- .../markwon/ext/tasklist/TaskListPlugin.java | 7 +- .../markwon/ext/tasklist/TaskListSpan.java | 3 +- .../ext/tasklist/TaskListSpanFactory.java | 5 +- .../markwon/ext/tasklist/TaskListTest.java | 2 +- markwon-html/build.gradle | 3 - .../noties/markwon/html/AppendableUtils.java | 2 +- .../markwon/html/CssInlineStyleParser.java | 5 +- .../io/noties/markwon/html/CssProperty.java | 2 +- .../markwon/html/HtmlEmptyTagReplacement.java | 4 +- .../io/noties/markwon/html/HtmlPlugin.java | 4 +- .../java/io/noties/markwon/html/HtmlTag.java | 4 +- .../io/noties/markwon/html/HtmlTagImpl.java | 4 +- .../markwon/html/MarkwonHtmlParser.java | 2 +- .../markwon/html/MarkwonHtmlParserImpl.java | 6 +- .../markwon/html/MarkwonHtmlRenderer.java | 4 +- .../markwon/html/MarkwonHtmlRendererImpl.java | 6 +- .../markwon/html/MarkwonHtmlRendererNoOp.java | 4 +- .../io/noties/markwon/html/TagHandler.java | 2 +- .../noties/markwon/html/TagHandlerNoOp.java | 2 +- .../noties/markwon/html/TrimmingAppender.java | 2 +- .../html/jsoup/nodes/CommonMarkEntities.java | 2 +- .../markwon/html/jsoup/parser/Token.java | 4 +- .../markwon/html/span/SubScriptSpan.java | 3 +- .../markwon/html/span/SuperScriptSpan.java | 3 +- .../markwon/html/tag/BlockquoteHandler.java | 8 +- .../markwon/html/tag/EmphasisHandler.java | 6 +- .../markwon/html/tag/HeadingHandler.java | 8 +- .../noties/markwon/html/tag/ImageHandler.java | 7 +- .../markwon/html/tag/ImageSizeParserImpl.java | 7 +- .../noties/markwon/html/tag/LinkHandler.java | 9 +- .../noties/markwon/html/tag/ListHandler.java | 10 +- .../markwon/html/tag/SimpleTagHandler.java | 10 +- .../markwon/html/tag/StrikeHandler.java | 11 +- .../html/tag/StrongEmphasisHandler.java | 6 +- .../markwon/html/tag/SubScriptHandler.java | 6 +- .../markwon/html/tag/SuperScriptHandler.java | 6 +- .../markwon/html/tag/UnderlineHandler.java | 7 +- .../html/CssInlineStyleParserTest.java | 2 +- .../html/MarkwonHtmlParserImplTest.java | 4 +- .../html/tag/ImageSizeParserImplTest.java | 4 +- .../markwon/image/gif/GifMediaDecoder.java | 4 +- .../noties/markwon/image/gif/GifPlugin.java | 2 +- .../image/glide/GlideImagesPlugin.java | 9 +- .../image/okhttp/OkHttpImagesPlugin.java | 2 +- .../image/okhttp/OkHttpSchemeHandler.java | 4 +- .../image/picasso/PicassoImagesPlugin.java | 5 +- .../markwon/image/svg/SvgMediaDecoder.java | 4 +- .../noties/markwon/image/svg/SvgPlugin.java | 2 +- markwon-image/build.gradle | 7 +- .../image/AsyncDrawableLoaderBuilder.java | 4 +- .../image/AsyncDrawableLoaderImpl.java | 7 +- .../image/DefaultImageMediaDecoder.java | 5 +- .../io/noties/markwon/image/ImageItem.java | 5 +- .../io/noties/markwon/image/ImagesPlugin.java | 7 +- .../io/noties/markwon/image/MediaDecoder.java | 5 +- .../noties/markwon/image/SchemeHandler.java | 3 +- .../io/noties/markwon/image/data/DataUri.java | 2 +- .../markwon/image/data/DataUriDecoder.java | 4 +- .../markwon/image/data/DataUriParser.java | 4 +- .../image/data/DataUriSchemeHandler.java | 2 +- .../markwon/image/file/FileSchemeHandler.java | 4 +- .../markwon/image/gif/GifMediaDecoder.java | 6 +- .../image/network/NetworkSchemeHandler.java | 4 +- .../network/OkHttpNetworkSchemeHandler.java | 2 +- .../markwon/image/svg/SvgMediaDecoder.java | 6 +- .../image/AsyncDrawableLoaderImplTest.java | 4 +- .../markwon/image/ImagesPluginTest.java | 2 +- .../image/data/DataUriSchemeHandlerTest.java | 2 +- .../noties/markwon/linkify/LinkifyPlugin.java | 5 +- .../recycler/table/TableBorderDrawable.java | 9 +- .../markwon/recycler/table/TableEntry.java | 17 +- .../recycler/table/TableEntryPlugin.java | 3 +- .../recycler/table/TableEntryTheme.java | 9 +- markwon-recycler/build.gradle | 2 +- .../markwon/recycler/MarkwonAdapter.java | 11 +- .../markwon/recycler/MarkwonAdapterImpl.java | 3 +- .../noties/markwon/recycler/SimpleEntry.java | 7 +- markwon-syntax-highlight/build.gradle | 1 - .../syntax/Prism4jSyntaxHighlight.java | 7 +- .../markwon/syntax/Prism4jSyntaxVisitor.java | 7 +- .../noties/markwon/syntax/Prism4jTheme.java | 7 +- .../markwon/syntax/Prism4jThemeBase.java | 13 +- .../markwon/syntax/Prism4jThemeDarkula.java | 9 +- .../markwon/syntax/Prism4jThemeDefault.java | 7 +- .../markwon/syntax/SyntaxHighlightPlugin.java | 6 +- markwon-test-span/build.gradle | 2 +- .../java/io/noties/markwon/test/TestSpan.java | 2 +- .../noties/markwon/test/TestSpanDocument.java | 2 +- .../markwon/test/TestSpanEnumerator.java | 2 +- .../noties/markwon/test/TestSpanMatcher.java | 2 +- .../io/noties/markwon/test/TestSpanSpan.java | 2 +- .../io/noties/markwon/test/TestSpanText.java | 2 +- sample/build.gradle | 7 +- .../noties/markwon/sample/MainActivity.java | 9 +- .../java/io/noties/markwon/sample/Sample.java | 2 +- .../io/noties/markwon/sample/SampleItem.java | 3 +- .../markwon/sample/SampleItemDecoration.java | 7 +- .../basicplugins/BasicPluginsActivity.java | 19 +- .../markwon/sample/core/CoreActivity.java | 5 +- .../CustomExtensionActivity.java | 3 +- .../sample/customextension/IconNode.java | 2 +- .../sample/customextension/IconPlugin.java | 3 +- .../sample/customextension/IconProcessor.java | 3 +- .../sample/customextension/IconSpan.java | 7 +- .../customextension/IconSpanProvider.java | 5 +- .../markwon/sample/latex/LatexActivity.java | 5 +- .../sample/recycler/RecyclerActivity.java | 13 +- .../markwon/sample/theme/ThemeActivity.java | 3 +- sample/src/main/res/layout/activity_main.xml | 2 +- .../src/main/res/layout/activity_recycler.xml | 2 +- 213 files changed, 555 insertions(+), 647 deletions(-) delete mode 100644 markwon-core/src/main/java/io/noties/markwon/MarkwonNodeRenderer.java diff --git a/README.md b/README.md index 34db2572..075186b0 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ features listed in [commonmark-spec] are supported ![stable](https://img.shields.io/maven-central/v/io.noties.markwon/core.svg?label=stable) ![snapshot](https://img.shields.io/nexus/s/https/oss.sonatype.org/io.noties.markwon/core.svg?label=snapshot) -```groovy +```kotlin implementation "io.noties.markwon:core:${markwonVersion}" ``` diff --git a/app/src/debug/java/io/noties/markwon/debug/DebugCheckboxDrawableView.java b/app/src/debug/java/io/noties/markwon/debug/DebugCheckboxDrawableView.java index 759ab4dc..7a506fc8 100644 --- a/app/src/debug/java/io/noties/markwon/debug/DebugCheckboxDrawableView.java +++ b/app/src/debug/java/io/noties/markwon/debug/DebugCheckboxDrawableView.java @@ -4,7 +4,7 @@ import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.drawable.Drawable; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import android.util.AttributeSet; import android.view.View; diff --git a/app/src/main/java/io/noties/markwon/app/App.java b/app/src/main/java/io/noties/markwon/app/App.java index 0b8bced2..46e15e4b 100644 --- a/app/src/main/java/io/noties/markwon/app/App.java +++ b/app/src/main/java/io/noties/markwon/app/App.java @@ -2,7 +2,8 @@ package io.noties.markwon.app; import android.app.Application; import android.content.Context; -import android.support.annotation.NonNull; + +import androidx.annotation.NonNull; import io.noties.debug.AndroidLogDebugOutput; import io.noties.debug.Debug; diff --git a/app/src/main/java/io/noties/markwon/app/AppBarItem.java b/app/src/main/java/io/noties/markwon/app/AppBarItem.java index ce6094c3..a8b8a322 100644 --- a/app/src/main/java/io/noties/markwon/app/AppBarItem.java +++ b/app/src/main/java/io/noties/markwon/app/AppBarItem.java @@ -1,10 +1,11 @@ package io.noties.markwon.app; -import android.support.annotation.NonNull; import android.text.TextUtils; import android.view.View; import android.widget.TextView; +import androidx.annotation.NonNull; + abstract class AppBarItem { static class State { diff --git a/app/src/main/java/io/noties/markwon/app/AppModule.java b/app/src/main/java/io/noties/markwon/app/AppModule.java index 4e4acc5a..45673165 100644 --- a/app/src/main/java/io/noties/markwon/app/AppModule.java +++ b/app/src/main/java/io/noties/markwon/app/AppModule.java @@ -16,8 +16,8 @@ import io.noties.markwon.syntax.Prism4jThemeDarkula; import io.noties.markwon.syntax.Prism4jThemeDefault; import okhttp3.Cache; import okhttp3.OkHttpClient; -import ru.noties.prism4j.Prism4j; -import ru.noties.prism4j.annotations.PrismBundle; +import io.noties.prism4j.Prism4j; +import io.noties.prism4j.annotations.PrismBundle; @Module @PrismBundle(includeAll = true) diff --git a/app/src/main/java/io/noties/markwon/app/MainActivity.java b/app/src/main/java/io/noties/markwon/app/MainActivity.java index 4aa34b47..c72542b3 100644 --- a/app/src/main/java/io/noties/markwon/app/MainActivity.java +++ b/app/src/main/java/io/noties/markwon/app/MainActivity.java @@ -4,16 +4,17 @@ import android.app.Activity; import android.content.Intent; import android.net.Uri; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.text.Spanned; import android.view.View; import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import javax.inject.Inject; -import io.noties.markwon.Markwon; import io.noties.debug.Debug; +import io.noties.markwon.Markwon; public class MainActivity extends Activity { diff --git a/app/src/main/java/io/noties/markwon/app/MarkdownLoader.java b/app/src/main/java/io/noties/markwon/app/MarkdownLoader.java index 05aaa5fc..db135dc4 100644 --- a/app/src/main/java/io/noties/markwon/app/MarkdownLoader.java +++ b/app/src/main/java/io/noties/markwon/app/MarkdownLoader.java @@ -4,10 +4,11 @@ import android.content.ContentResolver; import android.content.Context; import android.net.Uri; import android.os.Handler; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.text.TextUtils; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; @@ -20,11 +21,11 @@ import java.util.concurrent.Future; import javax.inject.Inject; +import io.noties.debug.Debug; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; import okhttp3.ResponseBody; -import io.noties.debug.Debug; @ActivityScope public class MarkdownLoader { diff --git a/app/src/main/java/io/noties/markwon/app/MarkdownRenderer.java b/app/src/main/java/io/noties/markwon/app/MarkdownRenderer.java index 8d23ca68..9bcb8e0f 100644 --- a/app/src/main/java/io/noties/markwon/app/MarkdownRenderer.java +++ b/app/src/main/java/io/noties/markwon/app/MarkdownRenderer.java @@ -4,10 +4,11 @@ import android.content.Context; import android.net.Uri; import android.os.Handler; import android.os.SystemClock; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.text.Spanned; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; @@ -31,7 +32,7 @@ import io.noties.markwon.syntax.Prism4jThemeDefault; import io.noties.markwon.syntax.SyntaxHighlightPlugin; import io.noties.markwon.urlprocessor.UrlProcessor; import io.noties.markwon.urlprocessor.UrlProcessorRelativeToAbsolute; -import ru.noties.prism4j.Prism4j; +import io.noties.prism4j.Prism4j; @ActivityScope public class MarkdownRenderer { diff --git a/app/src/main/java/io/noties/markwon/app/Themes.java b/app/src/main/java/io/noties/markwon/app/Themes.java index f2dc5571..14dc1f61 100644 --- a/app/src/main/java/io/noties/markwon/app/Themes.java +++ b/app/src/main/java/io/noties/markwon/app/Themes.java @@ -2,7 +2,8 @@ package io.noties.markwon.app; import android.content.Context; import android.content.SharedPreferences; -import android.support.annotation.NonNull; + +import androidx.annotation.NonNull; import javax.inject.Inject; import javax.inject.Singleton; diff --git a/app/src/main/java/io/noties/markwon/app/UriProcessor.java b/app/src/main/java/io/noties/markwon/app/UriProcessor.java index 4fcc48dd..45364c67 100644 --- a/app/src/main/java/io/noties/markwon/app/UriProcessor.java +++ b/app/src/main/java/io/noties/markwon/app/UriProcessor.java @@ -1,7 +1,8 @@ package io.noties.markwon.app; import android.net.Uri; -import android.support.annotation.NonNull; + +import androidx.annotation.NonNull; @SuppressWarnings("WeakerAccess") public interface UriProcessor { diff --git a/app/src/main/java/io/noties/markwon/app/UriProcessorImpl.java b/app/src/main/java/io/noties/markwon/app/UriProcessorImpl.java index 843a2403..a4bb3137 100644 --- a/app/src/main/java/io/noties/markwon/app/UriProcessorImpl.java +++ b/app/src/main/java/io/noties/markwon/app/UriProcessorImpl.java @@ -1,7 +1,8 @@ package io.noties.markwon.app; import android.net.Uri; -import android.support.annotation.NonNull; + +import androidx.annotation.NonNull; import java.util.List; @@ -32,7 +33,7 @@ class UriProcessorImpl implements UriProcessor { .fragment(uri.getFragment()) .query(uri.getQuery()); - for (String segment: segments) { + for (String segment : segments) { final String part; if ("blob".equals(segment)) { part = "raw"; diff --git a/app/src/main/java/io/noties/markwon/app/UrlProcessorInitialReadme.java b/app/src/main/java/io/noties/markwon/app/UrlProcessorInitialReadme.java index 535a4810..571bb395 100644 --- a/app/src/main/java/io/noties/markwon/app/UrlProcessorInitialReadme.java +++ b/app/src/main/java/io/noties/markwon/app/UrlProcessorInitialReadme.java @@ -1,9 +1,10 @@ package io.noties.markwon.app; import android.net.Uri; -import android.support.annotation.NonNull; import android.text.TextUtils; +import androidx.annotation.NonNull; + import io.noties.markwon.urlprocessor.UrlProcessor; import io.noties.markwon.urlprocessor.UrlProcessorRelativeToAbsolute; diff --git a/app/src/main/java/io/noties/markwon/app/Views.java b/app/src/main/java/io/noties/markwon/app/Views.java index db438375..587b2c9f 100644 --- a/app/src/main/java/io/noties/markwon/app/Views.java +++ b/app/src/main/java/io/noties/markwon/app/Views.java @@ -1,9 +1,10 @@ package io.noties.markwon.app; -import android.support.annotation.IntDef; -import android.support.annotation.NonNull; import android.view.View; +import androidx.annotation.IntDef; +import androidx.annotation.NonNull; + @SuppressWarnings("WeakerAccess") public abstract class Views { diff --git a/app/src/main/java/io/noties/markwon/app/gif/GifAwareAsyncDrawable.java b/app/src/main/java/io/noties/markwon/app/gif/GifAwareAsyncDrawable.java index 553bcd90..58c0bad3 100644 --- a/app/src/main/java/io/noties/markwon/app/gif/GifAwareAsyncDrawable.java +++ b/app/src/main/java/io/noties/markwon/app/gif/GifAwareAsyncDrawable.java @@ -2,8 +2,9 @@ package io.noties.markwon.app.gif; import android.graphics.Canvas; import android.graphics.drawable.Drawable; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import io.noties.markwon.image.AsyncDrawable; import io.noties.markwon.image.AsyncDrawableLoader; diff --git a/app/src/main/java/io/noties/markwon/app/gif/GifAwarePlugin.java b/app/src/main/java/io/noties/markwon/app/gif/GifAwarePlugin.java index ad5ab813..30b33f5b 100644 --- a/app/src/main/java/io/noties/markwon/app/gif/GifAwarePlugin.java +++ b/app/src/main/java/io/noties/markwon/app/gif/GifAwarePlugin.java @@ -1,9 +1,10 @@ package io.noties.markwon.app.gif; import android.content.Context; -import android.support.annotation.NonNull; import android.widget.TextView; +import androidx.annotation.NonNull; + import org.commonmark.node.Image; import io.noties.markwon.AbstractMarkwonPlugin; diff --git a/app/src/main/java/io/noties/markwon/app/gif/GifPlaceholder.java b/app/src/main/java/io/noties/markwon/app/gif/GifPlaceholder.java index 326d1b22..8417545b 100644 --- a/app/src/main/java/io/noties/markwon/app/gif/GifPlaceholder.java +++ b/app/src/main/java/io/noties/markwon/app/gif/GifPlaceholder.java @@ -6,9 +6,10 @@ import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.drawable.Drawable; -import android.support.annotation.ColorInt; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; + +import androidx.annotation.ColorInt; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; public class GifPlaceholder extends Drawable { diff --git a/app/src/main/java/io/noties/markwon/app/gif/GifProcessor.java b/app/src/main/java/io/noties/markwon/app/gif/GifProcessor.java index 266c5a03..59d4dfef 100644 --- a/app/src/main/java/io/noties/markwon/app/gif/GifProcessor.java +++ b/app/src/main/java/io/noties/markwon/app/gif/GifProcessor.java @@ -1,13 +1,14 @@ package io.noties.markwon.app.gif; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.text.Spannable; import android.text.Spanned; import android.text.style.ClickableSpan; import android.view.View; import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import io.noties.markwon.image.AsyncDrawableSpan; import pl.droidsonroids.gif.GifDrawable; diff --git a/build.gradle b/build.gradle index daec9a93..157757aa 100644 --- a/build.gradle +++ b/build.gradle @@ -53,14 +53,12 @@ ext { 'push-aar-gradle': 'https://raw.githubusercontent.com/noties/gradle-mvn-push/master/gradle-mvn-push-aar.gradle' ] - final def supportVersion = '28.0.0' final def commonMarkVersion = '0.12.1' final def daggerVersion = '2.10' deps = [ - 'support-annotations' : "com.android.support:support-annotations:$supportVersion", - 'support-app-compat' : "com.android.support:appcompat-v7:$supportVersion", - 'support-recycler-view' : "com.android.support:recyclerview-v7:$supportVersion", + 'x-annotations' : 'androidx.annotation:annotation:1.1.0', + 'x-recycler-view' : 'androidx.recyclerview:recyclerview:1.0.0', 'commonmark' : "com.atlassian.commonmark:commonmark:$commonMarkVersion", 'commonmark-strikethrough': "com.atlassian.commonmark:commonmark-ext-gfm-strikethrough:$commonMarkVersion", 'commonmark-table' : "com.atlassian.commonmark:commonmark-ext-gfm-tables:$commonMarkVersion", @@ -68,7 +66,7 @@ ext { 'android-gif' : 'pl.droidsonroids.gif:android-gif-drawable:1.2.14', 'jlatexmath-android' : 'ru.noties:jlatexmath-android:0.1.0', 'okhttp' : 'com.squareup.okhttp3:okhttp:3.9.0', - 'prism4j' : 'ru.noties:prism4j:1.1.0', + 'prism4j' : 'io.noties:prism4j:2.0.0', 'debug' : 'io.noties:debug:5.0.0@jar', 'adapt' : 'io.noties:adapt:2.0.0', 'dagger' : "com.google.dagger:dagger:$daggerVersion", @@ -77,7 +75,7 @@ ext { ] deps['annotationProcessor'] = [ - 'prism4j-bundler': 'ru.noties:prism4j-bundler:1.1.0', + 'prism4j-bundler': 'io.noties:prism4j-bundler:2.0.0', 'dagger-compiler': "com.google.dagger:dagger-compiler:$daggerVersion" ] diff --git a/gradle.properties b/gradle.properties index 59be8bf9..2642f708 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,6 +3,8 @@ org.gradle.jvmargs=-Xmx5g -Dfile.encoding=UTF-8 #org.gradle.parallel=true org.gradle.configureondemand=true +android.useAndroidX=true +android.enableJetifier=true android.enableBuildCache=true android.buildCacheDir=build/pre-dex-cache diff --git a/markwon-core/build.gradle b/markwon-core/build.gradle index 0f6f15db..946d760e 100644 --- a/markwon-core/build.gradle +++ b/markwon-core/build.gradle @@ -16,7 +16,7 @@ android { dependencies { deps.with { - api it['support-annotations'] + api it['x-annotations'] api it['commonmark'] } diff --git a/markwon-core/src/main/java/io/noties/markwon/AbstractMarkwonPlugin.java b/markwon-core/src/main/java/io/noties/markwon/AbstractMarkwonPlugin.java index d7d9f744..65db542a 100644 --- a/markwon-core/src/main/java/io/noties/markwon/AbstractMarkwonPlugin.java +++ b/markwon-core/src/main/java/io/noties/markwon/AbstractMarkwonPlugin.java @@ -1,9 +1,10 @@ package io.noties.markwon; -import android.support.annotation.NonNull; import android.text.Spanned; import android.widget.TextView; +import androidx.annotation.NonNull; + import org.commonmark.node.Node; import org.commonmark.parser.Parser; diff --git a/markwon-core/src/main/java/io/noties/markwon/LinkResolverDef.java b/markwon-core/src/main/java/io/noties/markwon/LinkResolverDef.java index da08c9fc..0b9e30fb 100644 --- a/markwon-core/src/main/java/io/noties/markwon/LinkResolverDef.java +++ b/markwon-core/src/main/java/io/noties/markwon/LinkResolverDef.java @@ -5,10 +5,11 @@ import android.content.Context; import android.content.Intent; import android.net.Uri; import android.provider.Browser; -import android.support.annotation.NonNull; import android.util.Log; import android.view.View; +import androidx.annotation.NonNull; + import io.noties.markwon.core.spans.LinkSpan; public class LinkResolverDef implements LinkSpan.Resolver { diff --git a/markwon-core/src/main/java/io/noties/markwon/Markwon.java b/markwon-core/src/main/java/io/noties/markwon/Markwon.java index 6f7af7bf..1f3896ce 100644 --- a/markwon-core/src/main/java/io/noties/markwon/Markwon.java +++ b/markwon-core/src/main/java/io/noties/markwon/Markwon.java @@ -1,11 +1,12 @@ package io.noties.markwon; import android.content.Context; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.text.Spanned; import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import org.commonmark.node.Node; import io.noties.markwon.core.CorePlugin; diff --git a/markwon-core/src/main/java/io/noties/markwon/MarkwonBuilderImpl.java b/markwon-core/src/main/java/io/noties/markwon/MarkwonBuilderImpl.java index 4362fbfc..38ad7573 100644 --- a/markwon-core/src/main/java/io/noties/markwon/MarkwonBuilderImpl.java +++ b/markwon-core/src/main/java/io/noties/markwon/MarkwonBuilderImpl.java @@ -1,9 +1,10 @@ package io.noties.markwon; import android.content.Context; -import android.support.annotation.NonNull; import android.widget.TextView; +import androidx.annotation.NonNull; + import org.commonmark.parser.Parser; import java.util.ArrayList; diff --git a/markwon-core/src/main/java/io/noties/markwon/MarkwonConfiguration.java b/markwon-core/src/main/java/io/noties/markwon/MarkwonConfiguration.java index a544ef6e..c7f0f04d 100644 --- a/markwon-core/src/main/java/io/noties/markwon/MarkwonConfiguration.java +++ b/markwon-core/src/main/java/io/noties/markwon/MarkwonConfiguration.java @@ -1,6 +1,6 @@ package io.noties.markwon; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import io.noties.markwon.core.MarkwonTheme; import io.noties.markwon.core.spans.LinkSpan; diff --git a/markwon-core/src/main/java/io/noties/markwon/MarkwonImpl.java b/markwon-core/src/main/java/io/noties/markwon/MarkwonImpl.java index d76925ae..199beb0b 100644 --- a/markwon-core/src/main/java/io/noties/markwon/MarkwonImpl.java +++ b/markwon-core/src/main/java/io/noties/markwon/MarkwonImpl.java @@ -1,10 +1,11 @@ package io.noties.markwon; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.text.Spanned; import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import org.commonmark.node.Node; import org.commonmark.parser.Parser; diff --git a/markwon-core/src/main/java/io/noties/markwon/MarkwonNodeRenderer.java b/markwon-core/src/main/java/io/noties/markwon/MarkwonNodeRenderer.java deleted file mode 100644 index 7038a620..00000000 --- a/markwon-core/src/main/java/io/noties/markwon/MarkwonNodeRenderer.java +++ /dev/null @@ -1,184 +0,0 @@ -package io.noties.markwon; - -import android.content.Context; -import android.support.annotation.IdRes; -import android.support.annotation.LayoutRes; -import android.support.annotation.NonNull; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; - -import org.commonmark.node.Node; - -import java.util.HashMap; -import java.util.Map; - -/** - * @since 3.0.0 - */ -public abstract class MarkwonNodeRenderer { - - public interface ViewProvider { - - /** - * Please note that you should not attach created View to specified group. It will be done - * automatically. - */ - @NonNull - View provide( - @NonNull LayoutInflater inflater, - @NonNull ViewGroup group, - @NonNull Markwon markwon, - @NonNull N n); - } - - @NonNull - public static Builder builder(@NonNull ViewProvider defaultViewProvider) { - return new Builder(defaultViewProvider); - } - - /** - * @param defaultViewProviderLayoutResId layout resource id to be used in default view provider - * @param defaultViewProviderTextViewId id of a TextView in specified layout - * @return Builder - * @see SimpleTextViewProvider - */ - @NonNull - public static Builder builder( - @LayoutRes int defaultViewProviderLayoutResId, - @IdRes int defaultViewProviderTextViewId) { - return new Builder(new SimpleTextViewProvider( - defaultViewProviderLayoutResId, - defaultViewProviderTextViewId)); - } - - public abstract void render(@NonNull ViewGroup group, @NonNull Markwon markwon, @NonNull String markdown); - - public abstract void render(@NonNull ViewGroup group, @NonNull Markwon markwon, @NonNull Node root); - - - public static class Builder { - - private final ViewProvider defaultViewProvider; - - private MarkwonReducer reducer; - private Map, ViewProvider> viewProviders; - private LayoutInflater inflater; - - public Builder(@NonNull ViewProvider defaultViewProvider) { - this.defaultViewProvider = defaultViewProvider; - this.viewProviders = new HashMap<>(3); - } - - @NonNull - public Builder reducer(@NonNull MarkwonReducer reducer) { - this.reducer = reducer; - return this; - } - - @NonNull - public Builder viewProvider( - @NonNull Class type, - @NonNull ViewProvider viewProvider) { - //noinspection unchecked - viewProviders.put(type, (ViewProvider) viewProvider); - return this; - } - - @NonNull - public Builder inflater(@NonNull LayoutInflater inflater) { - this.inflater = inflater; - return this; - } - - @NonNull - public MarkwonNodeRenderer build() { - if (reducer == null) { - reducer = MarkwonReducer.directChildren(); - } - return new Impl(this); - } - } - - public static class SimpleTextViewProvider implements ViewProvider { - - private final int layoutResId; - private final int textViewId; - - public SimpleTextViewProvider(@LayoutRes int layoutResId, @IdRes int textViewId) { - this.layoutResId = layoutResId; - this.textViewId = textViewId; - } - - @NonNull - @Override - public View provide( - @NonNull LayoutInflater inflater, - @NonNull ViewGroup group, - @NonNull Markwon markwon, - @NonNull Node node) { - final View view = inflater.inflate(layoutResId, group, false); - final TextView textView = view.findViewById(textViewId); - markwon.setParsedMarkdown(textView, markwon.render(node)); - return view; - } - } - - static class Impl extends MarkwonNodeRenderer { - - private final MarkwonReducer reducer; - private final Map, ViewProvider> viewProviders; - private final ViewProvider defaultViewProvider; - - private LayoutInflater inflater; - - Impl(@NonNull Builder builder) { - this.reducer = builder.reducer; - this.viewProviders = builder.viewProviders; - this.defaultViewProvider = builder.defaultViewProvider; - this.inflater = builder.inflater; - } - - @Override - public void render(@NonNull ViewGroup group, @NonNull Markwon markwon, @NonNull String markdown) { - render(group, markwon, markwon.parse(markdown)); - } - - @Override - public void render(@NonNull ViewGroup group, @NonNull Markwon markwon, @NonNull Node root) { - - final LayoutInflater inflater = ensureLayoutInflater(group.getContext()); - - ViewProvider viewProvider; - - for (Node node : reducer.reduce(root)) { - viewProvider = viewProvider(node); - group.addView(viewProvider.provide(inflater, group, markwon, node)); - } - } - - @NonNull - private LayoutInflater ensureLayoutInflater(@NonNull Context context) { - LayoutInflater inflater = this.inflater; - if (inflater == null) { - inflater = this.inflater = LayoutInflater.from(context); - } - return inflater; - } - - @NonNull - private ViewProvider viewProvider(@NonNull Node node) { - - // check for specific node view provider - final ViewProvider provider = viewProviders.get(node.getClass()); - if (provider != null) { - return provider; - } - - // if it's not present, then we can return a default one - return defaultViewProvider; - } - } - -} diff --git a/markwon-core/src/main/java/io/noties/markwon/MarkwonPlugin.java b/markwon-core/src/main/java/io/noties/markwon/MarkwonPlugin.java index f84ab62a..a916540a 100644 --- a/markwon-core/src/main/java/io/noties/markwon/MarkwonPlugin.java +++ b/markwon-core/src/main/java/io/noties/markwon/MarkwonPlugin.java @@ -1,9 +1,10 @@ package io.noties.markwon; -import android.support.annotation.NonNull; import android.text.Spanned; import android.widget.TextView; +import androidx.annotation.NonNull; + import org.commonmark.node.Node; import org.commonmark.parser.Parser; diff --git a/markwon-core/src/main/java/io/noties/markwon/MarkwonReducer.java b/markwon-core/src/main/java/io/noties/markwon/MarkwonReducer.java index 82a61963..c54f8c2d 100644 --- a/markwon-core/src/main/java/io/noties/markwon/MarkwonReducer.java +++ b/markwon-core/src/main/java/io/noties/markwon/MarkwonReducer.java @@ -1,6 +1,6 @@ package io.noties.markwon; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import org.commonmark.node.Node; diff --git a/markwon-core/src/main/java/io/noties/markwon/MarkwonSpansFactory.java b/markwon-core/src/main/java/io/noties/markwon/MarkwonSpansFactory.java index 2dd6b156..c4153075 100644 --- a/markwon-core/src/main/java/io/noties/markwon/MarkwonSpansFactory.java +++ b/markwon-core/src/main/java/io/noties/markwon/MarkwonSpansFactory.java @@ -1,7 +1,7 @@ package io.noties.markwon; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import org.commonmark.node.Node; diff --git a/markwon-core/src/main/java/io/noties/markwon/MarkwonSpansFactoryImpl.java b/markwon-core/src/main/java/io/noties/markwon/MarkwonSpansFactoryImpl.java index 66c3823d..ab2c1f84 100644 --- a/markwon-core/src/main/java/io/noties/markwon/MarkwonSpansFactoryImpl.java +++ b/markwon-core/src/main/java/io/noties/markwon/MarkwonSpansFactoryImpl.java @@ -1,7 +1,7 @@ package io.noties.markwon; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import org.commonmark.node.Node; diff --git a/markwon-core/src/main/java/io/noties/markwon/MarkwonVisitor.java b/markwon-core/src/main/java/io/noties/markwon/MarkwonVisitor.java index b2dd95c2..9fd6ffc7 100644 --- a/markwon-core/src/main/java/io/noties/markwon/MarkwonVisitor.java +++ b/markwon-core/src/main/java/io/noties/markwon/MarkwonVisitor.java @@ -1,7 +1,7 @@ package io.noties.markwon; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import org.commonmark.node.Node; import org.commonmark.node.Visitor; diff --git a/markwon-core/src/main/java/io/noties/markwon/MarkwonVisitorImpl.java b/markwon-core/src/main/java/io/noties/markwon/MarkwonVisitorImpl.java index f443bcd4..42db74ac 100644 --- a/markwon-core/src/main/java/io/noties/markwon/MarkwonVisitorImpl.java +++ b/markwon-core/src/main/java/io/noties/markwon/MarkwonVisitorImpl.java @@ -1,7 +1,7 @@ package io.noties.markwon; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import org.commonmark.node.BlockQuote; import org.commonmark.node.BulletList; diff --git a/markwon-core/src/main/java/io/noties/markwon/Prop.java b/markwon-core/src/main/java/io/noties/markwon/Prop.java index 552a4340..bc87c2f2 100644 --- a/markwon-core/src/main/java/io/noties/markwon/Prop.java +++ b/markwon-core/src/main/java/io/noties/markwon/Prop.java @@ -1,7 +1,7 @@ package io.noties.markwon; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; /** * Class to hold data in {@link RenderProps}. Represents a certain property. diff --git a/markwon-core/src/main/java/io/noties/markwon/RegistryImpl.java b/markwon-core/src/main/java/io/noties/markwon/RegistryImpl.java index 17a85dc8..76805be8 100644 --- a/markwon-core/src/main/java/io/noties/markwon/RegistryImpl.java +++ b/markwon-core/src/main/java/io/noties/markwon/RegistryImpl.java @@ -1,7 +1,7 @@ package io.noties.markwon; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import java.util.ArrayList; import java.util.HashSet; @@ -13,8 +13,6 @@ import io.noties.markwon.core.CorePlugin; // @since 4.0.0-SNAPSHOT class RegistryImpl implements MarkwonPlugin.Registry { - // todo: core-plugin must be (better be) first any way - private final List origin; private final List plugins; private final Set pending; diff --git a/markwon-core/src/main/java/io/noties/markwon/RenderProps.java b/markwon-core/src/main/java/io/noties/markwon/RenderProps.java index 61442969..b7b0a4e2 100644 --- a/markwon-core/src/main/java/io/noties/markwon/RenderProps.java +++ b/markwon-core/src/main/java/io/noties/markwon/RenderProps.java @@ -1,7 +1,7 @@ package io.noties.markwon; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; /** * @since 3.0.0 diff --git a/markwon-core/src/main/java/io/noties/markwon/RenderPropsImpl.java b/markwon-core/src/main/java/io/noties/markwon/RenderPropsImpl.java index 9b0fc241..e400e528 100644 --- a/markwon-core/src/main/java/io/noties/markwon/RenderPropsImpl.java +++ b/markwon-core/src/main/java/io/noties/markwon/RenderPropsImpl.java @@ -1,7 +1,7 @@ package io.noties.markwon; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import java.util.HashMap; import java.util.Map; diff --git a/markwon-core/src/main/java/io/noties/markwon/SpanFactory.java b/markwon-core/src/main/java/io/noties/markwon/SpanFactory.java index 6a90a533..a9f7418b 100644 --- a/markwon-core/src/main/java/io/noties/markwon/SpanFactory.java +++ b/markwon-core/src/main/java/io/noties/markwon/SpanFactory.java @@ -1,7 +1,7 @@ package io.noties.markwon; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; /** * @since 3.0.0 diff --git a/markwon-core/src/main/java/io/noties/markwon/SpannableBuilder.java b/markwon-core/src/main/java/io/noties/markwon/SpannableBuilder.java index a9f3a48d..6a15a9a8 100644 --- a/markwon-core/src/main/java/io/noties/markwon/SpannableBuilder.java +++ b/markwon-core/src/main/java/io/noties/markwon/SpannableBuilder.java @@ -1,11 +1,12 @@ package io.noties.markwon; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.VisibleForTesting; import android.text.SpannableStringBuilder; import android.text.Spanned; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; + import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collections; diff --git a/markwon-core/src/main/java/io/noties/markwon/core/CorePlugin.java b/markwon-core/src/main/java/io/noties/markwon/core/CorePlugin.java index 2604ecdc..084fb0d2 100644 --- a/markwon-core/src/main/java/io/noties/markwon/core/CorePlugin.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/CorePlugin.java @@ -1,12 +1,13 @@ package io.noties.markwon.core; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.VisibleForTesting; import android.text.Spanned; import android.text.method.LinkMovementMethod; import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; + import org.commonmark.node.BlockQuote; import org.commonmark.node.BulletList; import org.commonmark.node.Code; @@ -30,15 +31,13 @@ import org.commonmark.node.ThematicBreak; import java.util.ArrayList; import java.util.List; -import io.noties.markwon.SpannableBuilder; -import io.noties.markwon.core.spans.OrderedListItemSpan; -import io.noties.markwon.image.ImageProps; import io.noties.markwon.AbstractMarkwonPlugin; import io.noties.markwon.MarkwonConfiguration; import io.noties.markwon.MarkwonSpansFactory; import io.noties.markwon.MarkwonVisitor; import io.noties.markwon.RenderProps; import io.noties.markwon.SpanFactory; +import io.noties.markwon.SpannableBuilder; import io.noties.markwon.core.factory.BlockQuoteSpanFactory; import io.noties.markwon.core.factory.CodeBlockSpanFactory; import io.noties.markwon.core.factory.CodeSpanFactory; @@ -48,6 +47,8 @@ import io.noties.markwon.core.factory.LinkSpanFactory; import io.noties.markwon.core.factory.ListItemSpanFactory; import io.noties.markwon.core.factory.StrongEmphasisSpanFactory; import io.noties.markwon.core.factory.ThematicBreakSpanFactory; +import io.noties.markwon.core.spans.OrderedListItemSpan; +import io.noties.markwon.image.ImageProps; /** * @see CoreProps diff --git a/markwon-core/src/main/java/io/noties/markwon/core/MarkwonTheme.java b/markwon-core/src/main/java/io/noties/markwon/core/MarkwonTheme.java index 8a9dcee6..7c8142de 100644 --- a/markwon-core/src/main/java/io/noties/markwon/core/MarkwonTheme.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/MarkwonTheme.java @@ -3,13 +3,14 @@ package io.noties.markwon.core; import android.content.Context; import android.graphics.Paint; import android.graphics.Typeface; -import android.support.annotation.ColorInt; -import android.support.annotation.IntRange; -import android.support.annotation.NonNull; -import android.support.annotation.Px; -import android.support.annotation.Size; import android.text.TextPaint; +import androidx.annotation.ColorInt; +import androidx.annotation.IntRange; +import androidx.annotation.NonNull; +import androidx.annotation.Px; +import androidx.annotation.Size; + import java.util.Arrays; import java.util.Locale; diff --git a/markwon-core/src/main/java/io/noties/markwon/core/SimpleBlockNodeVisitor.java b/markwon-core/src/main/java/io/noties/markwon/core/SimpleBlockNodeVisitor.java index 03ffaeff..91742773 100644 --- a/markwon-core/src/main/java/io/noties/markwon/core/SimpleBlockNodeVisitor.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/SimpleBlockNodeVisitor.java @@ -1,6 +1,6 @@ package io.noties.markwon.core; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import org.commonmark.node.Node; diff --git a/markwon-core/src/main/java/io/noties/markwon/core/factory/BlockQuoteSpanFactory.java b/markwon-core/src/main/java/io/noties/markwon/core/factory/BlockQuoteSpanFactory.java index 30fa2853..4541169c 100644 --- a/markwon-core/src/main/java/io/noties/markwon/core/factory/BlockQuoteSpanFactory.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/factory/BlockQuoteSpanFactory.java @@ -1,12 +1,12 @@ package io.noties.markwon.core.factory; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; -import io.noties.markwon.core.spans.BlockQuoteSpan; import io.noties.markwon.MarkwonConfiguration; import io.noties.markwon.RenderProps; import io.noties.markwon.SpanFactory; +import io.noties.markwon.core.spans.BlockQuoteSpan; public class BlockQuoteSpanFactory implements SpanFactory { @Nullable diff --git a/markwon-core/src/main/java/io/noties/markwon/core/factory/CodeBlockSpanFactory.java b/markwon-core/src/main/java/io/noties/markwon/core/factory/CodeBlockSpanFactory.java index 352a0e1f..656b1ade 100644 --- a/markwon-core/src/main/java/io/noties/markwon/core/factory/CodeBlockSpanFactory.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/factory/CodeBlockSpanFactory.java @@ -1,12 +1,12 @@ package io.noties.markwon.core.factory; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; -import io.noties.markwon.core.spans.CodeBlockSpan; import io.noties.markwon.MarkwonConfiguration; import io.noties.markwon.RenderProps; import io.noties.markwon.SpanFactory; +import io.noties.markwon.core.spans.CodeBlockSpan; public class CodeBlockSpanFactory implements SpanFactory { @Nullable diff --git a/markwon-core/src/main/java/io/noties/markwon/core/factory/CodeSpanFactory.java b/markwon-core/src/main/java/io/noties/markwon/core/factory/CodeSpanFactory.java index 9c4f0aef..6c3615b1 100644 --- a/markwon-core/src/main/java/io/noties/markwon/core/factory/CodeSpanFactory.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/factory/CodeSpanFactory.java @@ -1,12 +1,12 @@ package io.noties.markwon.core.factory; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; -import io.noties.markwon.core.spans.CodeSpan; import io.noties.markwon.MarkwonConfiguration; import io.noties.markwon.RenderProps; import io.noties.markwon.SpanFactory; +import io.noties.markwon.core.spans.CodeSpan; public class CodeSpanFactory implements SpanFactory { @Nullable diff --git a/markwon-core/src/main/java/io/noties/markwon/core/factory/EmphasisSpanFactory.java b/markwon-core/src/main/java/io/noties/markwon/core/factory/EmphasisSpanFactory.java index 3942b8b1..9ea0c609 100644 --- a/markwon-core/src/main/java/io/noties/markwon/core/factory/EmphasisSpanFactory.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/factory/EmphasisSpanFactory.java @@ -1,12 +1,12 @@ package io.noties.markwon.core.factory; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; -import io.noties.markwon.core.spans.EmphasisSpan; import io.noties.markwon.MarkwonConfiguration; import io.noties.markwon.RenderProps; import io.noties.markwon.SpanFactory; +import io.noties.markwon.core.spans.EmphasisSpan; public class EmphasisSpanFactory implements SpanFactory { @Nullable diff --git a/markwon-core/src/main/java/io/noties/markwon/core/factory/HeadingSpanFactory.java b/markwon-core/src/main/java/io/noties/markwon/core/factory/HeadingSpanFactory.java index f96ab110..d0f7df78 100644 --- a/markwon-core/src/main/java/io/noties/markwon/core/factory/HeadingSpanFactory.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/factory/HeadingSpanFactory.java @@ -1,13 +1,13 @@ package io.noties.markwon.core.factory; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; -import io.noties.markwon.core.CoreProps; -import io.noties.markwon.core.spans.HeadingSpan; import io.noties.markwon.MarkwonConfiguration; import io.noties.markwon.RenderProps; import io.noties.markwon.SpanFactory; +import io.noties.markwon.core.CoreProps; +import io.noties.markwon.core.spans.HeadingSpan; public class HeadingSpanFactory implements SpanFactory { @Nullable diff --git a/markwon-core/src/main/java/io/noties/markwon/core/factory/LinkSpanFactory.java b/markwon-core/src/main/java/io/noties/markwon/core/factory/LinkSpanFactory.java index 345e4e15..fe93ef77 100644 --- a/markwon-core/src/main/java/io/noties/markwon/core/factory/LinkSpanFactory.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/factory/LinkSpanFactory.java @@ -1,13 +1,13 @@ package io.noties.markwon.core.factory; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; -import io.noties.markwon.core.CoreProps; -import io.noties.markwon.core.spans.LinkSpan; import io.noties.markwon.MarkwonConfiguration; import io.noties.markwon.RenderProps; import io.noties.markwon.SpanFactory; +import io.noties.markwon.core.CoreProps; +import io.noties.markwon.core.spans.LinkSpan; public class LinkSpanFactory implements SpanFactory { @Nullable diff --git a/markwon-core/src/main/java/io/noties/markwon/core/factory/ListItemSpanFactory.java b/markwon-core/src/main/java/io/noties/markwon/core/factory/ListItemSpanFactory.java index fd55e9a4..24cac063 100644 --- a/markwon-core/src/main/java/io/noties/markwon/core/factory/ListItemSpanFactory.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/factory/ListItemSpanFactory.java @@ -1,14 +1,14 @@ package io.noties.markwon.core.factory; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; -import io.noties.markwon.core.CoreProps; -import io.noties.markwon.core.spans.BulletListItemSpan; -import io.noties.markwon.core.spans.OrderedListItemSpan; import io.noties.markwon.MarkwonConfiguration; import io.noties.markwon.RenderProps; import io.noties.markwon.SpanFactory; +import io.noties.markwon.core.CoreProps; +import io.noties.markwon.core.spans.BulletListItemSpan; +import io.noties.markwon.core.spans.OrderedListItemSpan; public class ListItemSpanFactory implements SpanFactory { diff --git a/markwon-core/src/main/java/io/noties/markwon/core/factory/StrongEmphasisSpanFactory.java b/markwon-core/src/main/java/io/noties/markwon/core/factory/StrongEmphasisSpanFactory.java index 029d3d25..46cadf17 100644 --- a/markwon-core/src/main/java/io/noties/markwon/core/factory/StrongEmphasisSpanFactory.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/factory/StrongEmphasisSpanFactory.java @@ -1,12 +1,12 @@ package io.noties.markwon.core.factory; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; -import io.noties.markwon.core.spans.StrongEmphasisSpan; import io.noties.markwon.MarkwonConfiguration; import io.noties.markwon.RenderProps; import io.noties.markwon.SpanFactory; +import io.noties.markwon.core.spans.StrongEmphasisSpan; public class StrongEmphasisSpanFactory implements SpanFactory { @Nullable diff --git a/markwon-core/src/main/java/io/noties/markwon/core/factory/ThematicBreakSpanFactory.java b/markwon-core/src/main/java/io/noties/markwon/core/factory/ThematicBreakSpanFactory.java index 6f5659fc..2b141a38 100644 --- a/markwon-core/src/main/java/io/noties/markwon/core/factory/ThematicBreakSpanFactory.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/factory/ThematicBreakSpanFactory.java @@ -1,12 +1,12 @@ package io.noties.markwon.core.factory; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; -import io.noties.markwon.core.spans.ThematicBreakSpan; import io.noties.markwon.MarkwonConfiguration; import io.noties.markwon.RenderProps; import io.noties.markwon.SpanFactory; +import io.noties.markwon.core.spans.ThematicBreakSpan; public class ThematicBreakSpanFactory implements SpanFactory { @Nullable diff --git a/markwon-core/src/main/java/io/noties/markwon/core/spans/BlockQuoteSpan.java b/markwon-core/src/main/java/io/noties/markwon/core/spans/BlockQuoteSpan.java index 0a7c7615..9f649d55 100644 --- a/markwon-core/src/main/java/io/noties/markwon/core/spans/BlockQuoteSpan.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/spans/BlockQuoteSpan.java @@ -3,10 +3,11 @@ package io.noties.markwon.core.spans; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Rect; -import android.support.annotation.NonNull; import android.text.Layout; import android.text.style.LeadingMarginSpan; +import androidx.annotation.NonNull; + import io.noties.markwon.core.MarkwonTheme; public class BlockQuoteSpan implements LeadingMarginSpan { diff --git a/markwon-core/src/main/java/io/noties/markwon/core/spans/BulletListItemSpan.java b/markwon-core/src/main/java/io/noties/markwon/core/spans/BulletListItemSpan.java index 59681b5a..6d8da746 100644 --- a/markwon-core/src/main/java/io/noties/markwon/core/spans/BulletListItemSpan.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/spans/BulletListItemSpan.java @@ -4,11 +4,12 @@ import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.RectF; -import android.support.annotation.IntRange; -import android.support.annotation.NonNull; import android.text.Layout; import android.text.style.LeadingMarginSpan; +import androidx.annotation.IntRange; +import androidx.annotation.NonNull; + import io.noties.markwon.core.MarkwonTheme; import io.noties.markwon.utils.LeadingMarginUtils; diff --git a/markwon-core/src/main/java/io/noties/markwon/core/spans/CodeBlockSpan.java b/markwon-core/src/main/java/io/noties/markwon/core/spans/CodeBlockSpan.java index 24626f12..c358a27e 100644 --- a/markwon-core/src/main/java/io/noties/markwon/core/spans/CodeBlockSpan.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/spans/CodeBlockSpan.java @@ -3,12 +3,13 @@ package io.noties.markwon.core.spans; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Rect; -import android.support.annotation.NonNull; import android.text.Layout; import android.text.TextPaint; import android.text.style.LeadingMarginSpan; import android.text.style.MetricAffectingSpan; +import androidx.annotation.NonNull; + import io.noties.markwon.core.MarkwonTheme; /** diff --git a/markwon-core/src/main/java/io/noties/markwon/core/spans/CodeSpan.java b/markwon-core/src/main/java/io/noties/markwon/core/spans/CodeSpan.java index 8e2b1051..455fe34b 100644 --- a/markwon-core/src/main/java/io/noties/markwon/core/spans/CodeSpan.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/spans/CodeSpan.java @@ -1,9 +1,10 @@ package io.noties.markwon.core.spans; -import android.support.annotation.NonNull; import android.text.TextPaint; import android.text.style.MetricAffectingSpan; +import androidx.annotation.NonNull; + import io.noties.markwon.core.MarkwonTheme; /** diff --git a/markwon-core/src/main/java/io/noties/markwon/core/spans/CustomTypefaceSpan.java b/markwon-core/src/main/java/io/noties/markwon/core/spans/CustomTypefaceSpan.java index 083c35f7..b12a80d6 100644 --- a/markwon-core/src/main/java/io/noties/markwon/core/spans/CustomTypefaceSpan.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/spans/CustomTypefaceSpan.java @@ -1,10 +1,11 @@ package io.noties.markwon.core.spans; import android.graphics.Typeface; -import android.support.annotation.NonNull; import android.text.TextPaint; import android.text.style.MetricAffectingSpan; +import androidx.annotation.NonNull; + /** * A span implementation that allow applying custom Typeface. Although it is * not used directly by the library, it\'s helpful for customizations. diff --git a/markwon-core/src/main/java/io/noties/markwon/core/spans/HeadingSpan.java b/markwon-core/src/main/java/io/noties/markwon/core/spans/HeadingSpan.java index 9d4e8e72..cb723a30 100644 --- a/markwon-core/src/main/java/io/noties/markwon/core/spans/HeadingSpan.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/spans/HeadingSpan.java @@ -3,13 +3,14 @@ package io.noties.markwon.core.spans; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Rect; -import android.support.annotation.IntRange; -import android.support.annotation.NonNull; import android.text.Layout; import android.text.TextPaint; import android.text.style.LeadingMarginSpan; import android.text.style.MetricAffectingSpan; +import androidx.annotation.IntRange; +import androidx.annotation.NonNull; + import io.noties.markwon.core.MarkwonTheme; import io.noties.markwon.utils.LeadingMarginUtils; diff --git a/markwon-core/src/main/java/io/noties/markwon/core/spans/LinkSpan.java b/markwon-core/src/main/java/io/noties/markwon/core/spans/LinkSpan.java index 32108b0c..4bcbfd11 100644 --- a/markwon-core/src/main/java/io/noties/markwon/core/spans/LinkSpan.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/spans/LinkSpan.java @@ -1,10 +1,11 @@ package io.noties.markwon.core.spans; -import android.support.annotation.NonNull; import android.text.TextPaint; import android.text.style.URLSpan; import android.view.View; +import androidx.annotation.NonNull; + import io.noties.markwon.core.MarkwonTheme; public class LinkSpan extends URLSpan { diff --git a/markwon-core/src/main/java/io/noties/markwon/core/spans/OrderedListItemSpan.java b/markwon-core/src/main/java/io/noties/markwon/core/spans/OrderedListItemSpan.java index 0109c14c..abcd3287 100644 --- a/markwon-core/src/main/java/io/noties/markwon/core/spans/OrderedListItemSpan.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/spans/OrderedListItemSpan.java @@ -2,13 +2,14 @@ package io.noties.markwon.core.spans; import android.graphics.Canvas; import android.graphics.Paint; -import android.support.annotation.NonNull; import android.text.Layout; import android.text.Spanned; import android.text.TextPaint; import android.text.style.LeadingMarginSpan; import android.widget.TextView; +import androidx.annotation.NonNull; + import io.noties.markwon.core.MarkwonTheme; import io.noties.markwon.utils.LeadingMarginUtils; diff --git a/markwon-core/src/main/java/io/noties/markwon/core/spans/ThematicBreakSpan.java b/markwon-core/src/main/java/io/noties/markwon/core/spans/ThematicBreakSpan.java index aa3f4259..6b3bcc5c 100644 --- a/markwon-core/src/main/java/io/noties/markwon/core/spans/ThematicBreakSpan.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/spans/ThematicBreakSpan.java @@ -3,10 +3,11 @@ package io.noties.markwon.core.spans; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Rect; -import android.support.annotation.NonNull; import android.text.Layout; import android.text.style.LeadingMarginSpan; +import androidx.annotation.NonNull; + import io.noties.markwon.core.MarkwonTheme; public class ThematicBreakSpan implements LeadingMarginSpan { diff --git a/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawable.java b/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawable.java index 422f4923..dfbf8d19 100644 --- a/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawable.java +++ b/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawable.java @@ -6,9 +6,10 @@ import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.drawable.Animatable; import android.graphics.drawable.Drawable; -import android.support.annotation.IntRange; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; + +import androidx.annotation.IntRange; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; public class AsyncDrawable extends Drawable { diff --git a/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawableLoader.java b/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawableLoader.java index 3a3a7d31..75c99384 100644 --- a/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawableLoader.java +++ b/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawableLoader.java @@ -1,8 +1,9 @@ package io.noties.markwon.image; import android.graphics.drawable.Drawable; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; public abstract class AsyncDrawableLoader { diff --git a/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderNoOp.java b/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderNoOp.java index c7d06d7b..2c5c57d0 100644 --- a/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderNoOp.java +++ b/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderNoOp.java @@ -1,8 +1,9 @@ package io.noties.markwon.image; import android.graphics.drawable.Drawable; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; class AsyncDrawableLoaderNoOp extends AsyncDrawableLoader { @Override diff --git a/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawableScheduler.java b/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawableScheduler.java index 251f9937..63ad3f68 100644 --- a/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawableScheduler.java +++ b/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawableScheduler.java @@ -4,12 +4,13 @@ import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.os.Looper; import android.os.SystemClock; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.text.Spanned; import android.view.View; import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import io.noties.markwon.R; public abstract class AsyncDrawableScheduler { diff --git a/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawableSpan.java b/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawableSpan.java index d7b7aaf7..0d70b62a 100644 --- a/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawableSpan.java +++ b/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawableSpan.java @@ -3,12 +3,13 @@ package io.noties.markwon.image; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Rect; -import android.support.annotation.IntDef; -import android.support.annotation.IntRange; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.text.style.ReplacementSpan; +import androidx.annotation.IntDef; +import androidx.annotation.IntRange; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/markwon-core/src/main/java/io/noties/markwon/image/DrawableUtils.java b/markwon-core/src/main/java/io/noties/markwon/image/DrawableUtils.java index 2cecf8c0..4017a669 100644 --- a/markwon-core/src/main/java/io/noties/markwon/image/DrawableUtils.java +++ b/markwon-core/src/main/java/io/noties/markwon/image/DrawableUtils.java @@ -2,8 +2,9 @@ package io.noties.markwon.image; import android.graphics.Rect; import android.graphics.drawable.Drawable; -import android.support.annotation.CheckResult; -import android.support.annotation.NonNull; + +import androidx.annotation.CheckResult; +import androidx.annotation.NonNull; /** * @since 3.0.1 diff --git a/markwon-core/src/main/java/io/noties/markwon/image/ImageSize.java b/markwon-core/src/main/java/io/noties/markwon/image/ImageSize.java index f06ec6d3..62b34292 100644 --- a/markwon-core/src/main/java/io/noties/markwon/image/ImageSize.java +++ b/markwon-core/src/main/java/io/noties/markwon/image/ImageSize.java @@ -1,6 +1,6 @@ package io.noties.markwon.image; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; /** * @since 1.0.1 diff --git a/markwon-core/src/main/java/io/noties/markwon/image/ImageSizeResolver.java b/markwon-core/src/main/java/io/noties/markwon/image/ImageSizeResolver.java index 85b5f44b..8542cac5 100644 --- a/markwon-core/src/main/java/io/noties/markwon/image/ImageSizeResolver.java +++ b/markwon-core/src/main/java/io/noties/markwon/image/ImageSizeResolver.java @@ -1,8 +1,9 @@ package io.noties.markwon.image; import android.graphics.Rect; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; /** * @since 1.0.1 diff --git a/markwon-core/src/main/java/io/noties/markwon/image/ImageSizeResolverDef.java b/markwon-core/src/main/java/io/noties/markwon/image/ImageSizeResolverDef.java index 9788b7fe..1135d271 100644 --- a/markwon-core/src/main/java/io/noties/markwon/image/ImageSizeResolverDef.java +++ b/markwon-core/src/main/java/io/noties/markwon/image/ImageSizeResolverDef.java @@ -1,8 +1,9 @@ package io.noties.markwon.image; import android.graphics.Rect; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; /** * @since 1.0.1 diff --git a/markwon-core/src/main/java/io/noties/markwon/image/ImageSpanFactory.java b/markwon-core/src/main/java/io/noties/markwon/image/ImageSpanFactory.java index df2dce06..b1e38362 100644 --- a/markwon-core/src/main/java/io/noties/markwon/image/ImageSpanFactory.java +++ b/markwon-core/src/main/java/io/noties/markwon/image/ImageSpanFactory.java @@ -1,7 +1,7 @@ package io.noties.markwon.image; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import io.noties.markwon.MarkwonConfiguration; import io.noties.markwon.RenderProps; diff --git a/markwon-core/src/main/java/io/noties/markwon/movement/MovementMethodPlugin.java b/markwon-core/src/main/java/io/noties/markwon/movement/MovementMethodPlugin.java index fd672783..0f9a7e10 100644 --- a/markwon-core/src/main/java/io/noties/markwon/movement/MovementMethodPlugin.java +++ b/markwon-core/src/main/java/io/noties/markwon/movement/MovementMethodPlugin.java @@ -1,11 +1,12 @@ package io.noties.markwon.movement; -import android.support.annotation.NonNull; import android.text.Spanned; import android.text.method.LinkMovementMethod; import android.text.method.MovementMethod; import android.widget.TextView; +import androidx.annotation.NonNull; + import io.noties.markwon.AbstractMarkwonPlugin; /** diff --git a/markwon-core/src/main/java/io/noties/markwon/syntax/SyntaxHighlight.java b/markwon-core/src/main/java/io/noties/markwon/syntax/SyntaxHighlight.java index 925fd1df..5a7dd839 100644 --- a/markwon-core/src/main/java/io/noties/markwon/syntax/SyntaxHighlight.java +++ b/markwon-core/src/main/java/io/noties/markwon/syntax/SyntaxHighlight.java @@ -1,7 +1,7 @@ package io.noties.markwon.syntax; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; @SuppressWarnings("WeakerAccess") public interface SyntaxHighlight { diff --git a/markwon-core/src/main/java/io/noties/markwon/syntax/SyntaxHighlightNoOp.java b/markwon-core/src/main/java/io/noties/markwon/syntax/SyntaxHighlightNoOp.java index e3931244..c3787bbc 100644 --- a/markwon-core/src/main/java/io/noties/markwon/syntax/SyntaxHighlightNoOp.java +++ b/markwon-core/src/main/java/io/noties/markwon/syntax/SyntaxHighlightNoOp.java @@ -1,7 +1,7 @@ package io.noties.markwon.syntax; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; public class SyntaxHighlightNoOp implements SyntaxHighlight { @NonNull diff --git a/markwon-core/src/main/java/io/noties/markwon/urlprocessor/UrlProcessor.java b/markwon-core/src/main/java/io/noties/markwon/urlprocessor/UrlProcessor.java index 03f1995d..b49585e5 100644 --- a/markwon-core/src/main/java/io/noties/markwon/urlprocessor/UrlProcessor.java +++ b/markwon-core/src/main/java/io/noties/markwon/urlprocessor/UrlProcessor.java @@ -1,6 +1,6 @@ package io.noties.markwon.urlprocessor; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; public interface UrlProcessor { @NonNull diff --git a/markwon-core/src/main/java/io/noties/markwon/urlprocessor/UrlProcessorAndroidAssets.java b/markwon-core/src/main/java/io/noties/markwon/urlprocessor/UrlProcessorAndroidAssets.java index 714f9553..bd3c74cb 100644 --- a/markwon-core/src/main/java/io/noties/markwon/urlprocessor/UrlProcessorAndroidAssets.java +++ b/markwon-core/src/main/java/io/noties/markwon/urlprocessor/UrlProcessorAndroidAssets.java @@ -1,10 +1,11 @@ package io.noties.markwon.urlprocessor; import android.net.Uri; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.text.TextUtils; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + /** * Processor that will assume that an URL without scheme points to android assets folder. * URL with a scheme will be processed by {@link #processor} (if it is specified) or returned `as-is`. diff --git a/markwon-core/src/main/java/io/noties/markwon/urlprocessor/UrlProcessorNoOp.java b/markwon-core/src/main/java/io/noties/markwon/urlprocessor/UrlProcessorNoOp.java index ba795b5e..1bc15a88 100644 --- a/markwon-core/src/main/java/io/noties/markwon/urlprocessor/UrlProcessorNoOp.java +++ b/markwon-core/src/main/java/io/noties/markwon/urlprocessor/UrlProcessorNoOp.java @@ -1,6 +1,6 @@ package io.noties.markwon.urlprocessor; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; public class UrlProcessorNoOp implements UrlProcessor { @NonNull diff --git a/markwon-core/src/main/java/io/noties/markwon/urlprocessor/UrlProcessorRelativeToAbsolute.java b/markwon-core/src/main/java/io/noties/markwon/urlprocessor/UrlProcessorRelativeToAbsolute.java index e67ab48c..99a19226 100644 --- a/markwon-core/src/main/java/io/noties/markwon/urlprocessor/UrlProcessorRelativeToAbsolute.java +++ b/markwon-core/src/main/java/io/noties/markwon/urlprocessor/UrlProcessorRelativeToAbsolute.java @@ -1,7 +1,7 @@ package io.noties.markwon.urlprocessor; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import java.net.MalformedURLException; import java.net.URL; diff --git a/markwon-core/src/main/java/io/noties/markwon/utils/Dip.java b/markwon-core/src/main/java/io/noties/markwon/utils/Dip.java index 6b8fdba2..8b579356 100644 --- a/markwon-core/src/main/java/io/noties/markwon/utils/Dip.java +++ b/markwon-core/src/main/java/io/noties/markwon/utils/Dip.java @@ -1,7 +1,8 @@ package io.noties.markwon.utils; import android.content.Context; -import android.support.annotation.NonNull; + +import androidx.annotation.NonNull; public class Dip { diff --git a/markwon-core/src/main/java/io/noties/markwon/utils/DrawableUtils.java b/markwon-core/src/main/java/io/noties/markwon/utils/DrawableUtils.java index 5201a828..f50a8b06 100644 --- a/markwon-core/src/main/java/io/noties/markwon/utils/DrawableUtils.java +++ b/markwon-core/src/main/java/io/noties/markwon/utils/DrawableUtils.java @@ -1,7 +1,8 @@ package io.noties.markwon.utils; import android.graphics.drawable.Drawable; -import android.support.annotation.NonNull; + +import androidx.annotation.NonNull; /** * @deprecated Please use {@link io.noties.markwon.image.DrawableUtils} diff --git a/markwon-core/src/main/java/io/noties/markwon/utils/DumpNodes.java b/markwon-core/src/main/java/io/noties/markwon/utils/DumpNodes.java index 0693da72..ffa2bf86 100644 --- a/markwon-core/src/main/java/io/noties/markwon/utils/DumpNodes.java +++ b/markwon-core/src/main/java/io/noties/markwon/utils/DumpNodes.java @@ -1,7 +1,7 @@ package io.noties.markwon.utils; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import org.commonmark.node.Block; import org.commonmark.node.Node; diff --git a/markwon-core/src/main/java/io/noties/markwon/utils/NoCopySpannableFactory.java b/markwon-core/src/main/java/io/noties/markwon/utils/NoCopySpannableFactory.java index 7609630e..dcb49813 100644 --- a/markwon-core/src/main/java/io/noties/markwon/utils/NoCopySpannableFactory.java +++ b/markwon-core/src/main/java/io/noties/markwon/utils/NoCopySpannableFactory.java @@ -1,9 +1,10 @@ package io.noties.markwon.utils; -import android.support.annotation.NonNull; import android.text.Spannable; import android.text.SpannableString; +import androidx.annotation.NonNull; + /** * Utility SpannableFactory that re-uses Spannable instance between multiple * `TextView#setText` calls. diff --git a/markwon-core/src/test/java/io/noties/markwon/AbstractMarkwonVisitorImpl.java b/markwon-core/src/test/java/io/noties/markwon/AbstractMarkwonVisitorImpl.java index 04298a06..ed4dae6b 100644 --- a/markwon-core/src/test/java/io/noties/markwon/AbstractMarkwonVisitorImpl.java +++ b/markwon-core/src/test/java/io/noties/markwon/AbstractMarkwonVisitorImpl.java @@ -1,6 +1,6 @@ package io.noties.markwon; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import org.commonmark.node.Node; diff --git a/markwon-core/src/test/java/io/noties/markwon/MarkwonAssert.java b/markwon-core/src/test/java/io/noties/markwon/MarkwonAssert.java index b220c7f8..85f686c8 100644 --- a/markwon-core/src/test/java/io/noties/markwon/MarkwonAssert.java +++ b/markwon-core/src/test/java/io/noties/markwon/MarkwonAssert.java @@ -1,6 +1,6 @@ package io.noties.markwon; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import org.junit.Assert; diff --git a/markwon-core/src/test/java/io/noties/markwon/RegistryImplTest.java b/markwon-core/src/test/java/io/noties/markwon/RegistryImplTest.java index 283a799e..4456bc47 100644 --- a/markwon-core/src/test/java/io/noties/markwon/RegistryImplTest.java +++ b/markwon-core/src/test/java/io/noties/markwon/RegistryImplTest.java @@ -1,6 +1,6 @@ package io.noties.markwon; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/markwon-core/src/test/java/io/noties/markwon/SpannableBuilderTest.java b/markwon-core/src/test/java/io/noties/markwon/SpannableBuilderTest.java index 3e68fe38..8a0ee7e4 100644 --- a/markwon-core/src/test/java/io/noties/markwon/SpannableBuilderTest.java +++ b/markwon-core/src/test/java/io/noties/markwon/SpannableBuilderTest.java @@ -1,6 +1,6 @@ package io.noties.markwon; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import android.text.SpannableStringBuilder; import android.text.Spanned; diff --git a/markwon-core/src/test/java/io/noties/markwon/core/CorePluginBridge.java b/markwon-core/src/test/java/io/noties/markwon/core/CorePluginBridge.java index 01520e54..d1bd2dbf 100644 --- a/markwon-core/src/test/java/io/noties/markwon/core/CorePluginBridge.java +++ b/markwon-core/src/test/java/io/noties/markwon/core/CorePluginBridge.java @@ -1,7 +1,7 @@ package io.noties.markwon.core; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import org.commonmark.node.Node; diff --git a/markwon-core/src/test/java/io/noties/markwon/core/CorePluginTest.java b/markwon-core/src/test/java/io/noties/markwon/core/CorePluginTest.java index cda6c9b8..e21a8ded 100644 --- a/markwon-core/src/test/java/io/noties/markwon/core/CorePluginTest.java +++ b/markwon-core/src/test/java/io/noties/markwon/core/CorePluginTest.java @@ -1,7 +1,7 @@ package io.noties.markwon.core; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import android.text.method.MovementMethod; import android.widget.ImageView; import android.widget.TextView; diff --git a/markwon-core/src/test/java/io/noties/markwon/core/CoreTest.java b/markwon-core/src/test/java/io/noties/markwon/core/CoreTest.java index 1d5b4830..b0c4556d 100644 --- a/markwon-core/src/test/java/io/noties/markwon/core/CoreTest.java +++ b/markwon-core/src/test/java/io/noties/markwon/core/CoreTest.java @@ -1,6 +1,6 @@ package io.noties.markwon.core; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import android.text.Spanned; import org.commonmark.node.Emphasis; diff --git a/markwon-core/src/test/java/io/noties/markwon/core/suite/BaseSuiteTest.java b/markwon-core/src/test/java/io/noties/markwon/core/suite/BaseSuiteTest.java index 7ecab39d..09d086fb 100644 --- a/markwon-core/src/test/java/io/noties/markwon/core/suite/BaseSuiteTest.java +++ b/markwon-core/src/test/java/io/noties/markwon/core/suite/BaseSuiteTest.java @@ -1,7 +1,7 @@ package io.noties.markwon.core.suite; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import android.text.Spanned; import org.apache.commons.io.IOUtils; diff --git a/markwon-core/src/test/java/io/noties/markwon/image/AsyncDrawableTest.java b/markwon-core/src/test/java/io/noties/markwon/image/AsyncDrawableTest.java index d725c00f..809cfd5f 100644 --- a/markwon-core/src/test/java/io/noties/markwon/image/AsyncDrawableTest.java +++ b/markwon-core/src/test/java/io/noties/markwon/image/AsyncDrawableTest.java @@ -4,8 +4,8 @@ import android.graphics.Canvas; import android.graphics.ColorFilter; import android.graphics.Rect; import android.graphics.drawable.Drawable; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import org.junit.Before; import org.junit.Test; diff --git a/markwon-core/src/test/java/io/noties/markwon/image/ImageTest.java b/markwon-core/src/test/java/io/noties/markwon/image/ImageTest.java index 71d13624..61721d16 100644 --- a/markwon-core/src/test/java/io/noties/markwon/image/ImageTest.java +++ b/markwon-core/src/test/java/io/noties/markwon/image/ImageTest.java @@ -1,7 +1,7 @@ package io.noties.markwon.image; import android.content.Context; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import org.commonmark.node.Image; import org.junit.Test; diff --git a/markwon-core/src/test/java/io/noties/markwon/syntax/SyntaxHighlightTest.java b/markwon-core/src/test/java/io/noties/markwon/syntax/SyntaxHighlightTest.java index a591303e..fdde1888 100644 --- a/markwon-core/src/test/java/io/noties/markwon/syntax/SyntaxHighlightTest.java +++ b/markwon-core/src/test/java/io/noties/markwon/syntax/SyntaxHighlightTest.java @@ -1,11 +1,12 @@ package io.noties.markwon.syntax; import android.os.Build; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.text.SpannableStringBuilder; import android.text.Spanned; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import org.commonmark.node.FencedCodeBlock; import org.commonmark.node.Node; import org.junit.Test; diff --git a/markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathPlugin.java b/markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathPlugin.java index f3d16403..1eda8358 100644 --- a/markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathPlugin.java +++ b/markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathPlugin.java @@ -4,12 +4,13 @@ import android.graphics.drawable.Drawable; import android.os.Handler; import android.os.Looper; import android.os.SystemClock; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.Px; import android.text.Spanned; import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.Px; + import org.commonmark.parser.Parser; import java.util.HashMap; @@ -18,15 +19,15 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; -import io.noties.markwon.image.AsyncDrawable; -import io.noties.markwon.image.AsyncDrawableScheduler; -import io.noties.markwon.image.AsyncDrawableSpan; -import ru.noties.jlatexmath.JLatexMathDrawable; import io.noties.markwon.AbstractMarkwonPlugin; import io.noties.markwon.MarkwonConfiguration; import io.noties.markwon.MarkwonVisitor; +import io.noties.markwon.image.AsyncDrawable; import io.noties.markwon.image.AsyncDrawableLoader; +import io.noties.markwon.image.AsyncDrawableScheduler; +import io.noties.markwon.image.AsyncDrawableSpan; import io.noties.markwon.image.ImageSize; +import ru.noties.jlatexmath.JLatexMathDrawable; /** * @since 3.0.0 diff --git a/markwon-ext-strikethrough/src/main/java/io/noties/markwon/ext/strikethrough/StrikethroughPlugin.java b/markwon-ext-strikethrough/src/main/java/io/noties/markwon/ext/strikethrough/StrikethroughPlugin.java index 08d7aa06..f805f612 100644 --- a/markwon-ext-strikethrough/src/main/java/io/noties/markwon/ext/strikethrough/StrikethroughPlugin.java +++ b/markwon-ext-strikethrough/src/main/java/io/noties/markwon/ext/strikethrough/StrikethroughPlugin.java @@ -1,8 +1,9 @@ package io.noties.markwon.ext.strikethrough; -import android.support.annotation.NonNull; import android.text.style.StrikethroughSpan; +import androidx.annotation.NonNull; + import org.commonmark.ext.gfm.strikethrough.Strikethrough; import org.commonmark.ext.gfm.strikethrough.StrikethroughExtension; import org.commonmark.parser.Parser; diff --git a/markwon-ext-strikethrough/src/test/java/io/noties/markwon/ext/strikethrough/StrikethroughPluginTest.java b/markwon-ext-strikethrough/src/test/java/io/noties/markwon/ext/strikethrough/StrikethroughPluginTest.java index db77c79d..c9d9421a 100644 --- a/markwon-ext-strikethrough/src/test/java/io/noties/markwon/ext/strikethrough/StrikethroughPluginTest.java +++ b/markwon-ext-strikethrough/src/test/java/io/noties/markwon/ext/strikethrough/StrikethroughPluginTest.java @@ -1,6 +1,6 @@ package io.noties.markwon.ext.strikethrough; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import android.text.style.StrikethroughSpan; import org.commonmark.Extension; diff --git a/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/Table.java b/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/Table.java index 774c52e2..1d973ddc 100644 --- a/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/Table.java +++ b/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/Table.java @@ -1,9 +1,10 @@ package io.noties.markwon.ext.tables; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.text.Spanned; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import org.commonmark.ext.gfm.tables.TableBlock; import org.commonmark.ext.gfm.tables.TableCell; import org.commonmark.ext.gfm.tables.TableHead; diff --git a/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TablePlugin.java b/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TablePlugin.java index 7846029c..4d931e9a 100644 --- a/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TablePlugin.java +++ b/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TablePlugin.java @@ -1,10 +1,11 @@ package io.noties.markwon.ext.tables; import android.content.Context; -import android.support.annotation.NonNull; import android.text.Spanned; import android.widget.TextView; +import androidx.annotation.NonNull; + import org.commonmark.ext.gfm.tables.TableBody; import org.commonmark.ext.gfm.tables.TableCell; import org.commonmark.ext.gfm.tables.TableHead; diff --git a/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TableRowSpan.java b/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TableRowSpan.java index a4bd08a7..6cbdcae4 100644 --- a/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TableRowSpan.java +++ b/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TableRowSpan.java @@ -4,15 +4,16 @@ import android.annotation.SuppressLint; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Rect; -import android.support.annotation.IntDef; -import android.support.annotation.IntRange; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.text.Layout; import android.text.StaticLayout; import android.text.TextPaint; import android.text.style.ReplacementSpan; +import androidx.annotation.IntDef; +import androidx.annotation.IntRange; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; diff --git a/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TableRowsScheduler.java b/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TableRowsScheduler.java index 5fbb6b4b..e3086c20 100644 --- a/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TableRowsScheduler.java +++ b/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TableRowsScheduler.java @@ -1,12 +1,13 @@ package io.noties.markwon.ext.tables; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.text.Spanned; import android.text.TextUtils; import android.view.View; import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + abstract class TableRowsScheduler { static void schedule(@NonNull final TextView view) { diff --git a/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TableTheme.java b/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TableTheme.java index eeab17d9..f4a1c5cc 100644 --- a/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TableTheme.java +++ b/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TableTheme.java @@ -2,9 +2,10 @@ package io.noties.markwon.ext.tables; import android.content.Context; import android.graphics.Paint; -import android.support.annotation.ColorInt; -import android.support.annotation.NonNull; -import android.support.annotation.Px; + +import androidx.annotation.ColorInt; +import androidx.annotation.NonNull; +import androidx.annotation.Px; import io.noties.markwon.utils.ColorUtils; import io.noties.markwon.utils.Dip; diff --git a/markwon-ext-tasklist/build.gradle b/markwon-ext-tasklist/build.gradle index 43a236df..8a0e6cd7 100644 --- a/markwon-ext-tasklist/build.gradle +++ b/markwon-ext-tasklist/build.gradle @@ -14,6 +14,7 @@ android { } dependencies { + api project(':markwon-core') deps['test'].with { diff --git a/markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListBlockParser.java b/markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListBlockParser.java index b36ce73a..f65c4f7b 100644 --- a/markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListBlockParser.java +++ b/markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListBlockParser.java @@ -1,7 +1,7 @@ package io.noties.markwon.ext.tasklist; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import org.commonmark.node.Block; import org.commonmark.parser.InlineParser; diff --git a/markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListDrawable.java b/markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListDrawable.java index b43ea1ec..4c67d345 100644 --- a/markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListDrawable.java +++ b/markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListDrawable.java @@ -8,10 +8,11 @@ import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.drawable.Drawable; -import android.support.annotation.ColorInt; -import android.support.annotation.IntRange; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; + +import androidx.annotation.ColorInt; +import androidx.annotation.IntRange; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; /** * @since 1.0.1 @@ -37,7 +38,10 @@ public class TaskListDrawable extends Drawable { // unfortunately we cannot rely on TextView to be LAYER_TYPE_SOFTWARE // if we could we would draw our checkMarkPath with PorterDuff.CLEAR - public TaskListDrawable(@ColorInt int checkedFillColor, @ColorInt int normalOutlineColor, @ColorInt int checkMarkColor) { + public TaskListDrawable( + @ColorInt int checkedFillColor, + @ColorInt int normalOutlineColor, + @ColorInt int checkMarkColor) { this.checkedFillColor = checkedFillColor; this.normalOutlineColor = normalOutlineColor; diff --git a/markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListPlugin.java b/markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListPlugin.java index 5c37ea8c..df71b2c4 100644 --- a/markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListPlugin.java +++ b/markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListPlugin.java @@ -3,11 +3,12 @@ package io.noties.markwon.ext.tasklist; import android.content.Context; import android.content.res.TypedArray; import android.graphics.drawable.Drawable; -import android.support.annotation.AttrRes; -import android.support.annotation.ColorInt; -import android.support.annotation.NonNull; import android.util.TypedValue; +import androidx.annotation.AttrRes; +import androidx.annotation.ColorInt; +import androidx.annotation.NonNull; + import org.commonmark.node.Node; import org.commonmark.parser.Parser; diff --git a/markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListSpan.java b/markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListSpan.java index 02d8a2a3..04ba8dbd 100644 --- a/markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListSpan.java +++ b/markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListSpan.java @@ -3,10 +3,11 @@ package io.noties.markwon.ext.tasklist; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.drawable.Drawable; -import android.support.annotation.NonNull; import android.text.Layout; import android.text.style.LeadingMarginSpan; +import androidx.annotation.NonNull; + import io.noties.markwon.core.MarkwonTheme; import io.noties.markwon.utils.LeadingMarginUtils; diff --git a/markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListSpanFactory.java b/markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListSpanFactory.java index 80864340..c5d64d60 100644 --- a/markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListSpanFactory.java +++ b/markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListSpanFactory.java @@ -1,8 +1,9 @@ package io.noties.markwon.ext.tasklist; import android.graphics.drawable.Drawable; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import io.noties.markwon.MarkwonConfiguration; import io.noties.markwon.RenderProps; diff --git a/markwon-ext-tasklist/src/test/java/io/noties/markwon/ext/tasklist/TaskListTest.java b/markwon-ext-tasklist/src/test/java/io/noties/markwon/ext/tasklist/TaskListTest.java index c28a8555..eefc50ab 100644 --- a/markwon-ext-tasklist/src/test/java/io/noties/markwon/ext/tasklist/TaskListTest.java +++ b/markwon-ext-tasklist/src/test/java/io/noties/markwon/ext/tasklist/TaskListTest.java @@ -1,6 +1,6 @@ package io.noties.markwon.ext.tasklist; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import org.apache.commons.io.IOUtils; import org.junit.Test; diff --git a/markwon-html/build.gradle b/markwon-html/build.gradle index c23a7b4f..28ead2d9 100644 --- a/markwon-html/build.gradle +++ b/markwon-html/build.gradle @@ -18,9 +18,6 @@ dependencies { api project(':markwon-core') deps.with { - api it['support-annotations'] - api it['commonmark'] - // add a compileOnly dependency, so if this artifact is present // we will try to obtain a SpanFactory for a Strikethrough node and use // it to be consistent with markdown (please note that we do not use markwon plugin diff --git a/markwon-html/src/main/java/io/noties/markwon/html/AppendableUtils.java b/markwon-html/src/main/java/io/noties/markwon/html/AppendableUtils.java index 29f25b83..bce490a1 100644 --- a/markwon-html/src/main/java/io/noties/markwon/html/AppendableUtils.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/AppendableUtils.java @@ -1,6 +1,6 @@ package io.noties.markwon.html; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import java.io.IOException; diff --git a/markwon-html/src/main/java/io/noties/markwon/html/CssInlineStyleParser.java b/markwon-html/src/main/java/io/noties/markwon/html/CssInlineStyleParser.java index c06f396d..4f9320e9 100644 --- a/markwon-html/src/main/java/io/noties/markwon/html/CssInlineStyleParser.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/CssInlineStyleParser.java @@ -1,9 +1,10 @@ package io.noties.markwon.html; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.text.TextUtils; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import java.util.Iterator; import java.util.NoSuchElementException; diff --git a/markwon-html/src/main/java/io/noties/markwon/html/CssProperty.java b/markwon-html/src/main/java/io/noties/markwon/html/CssProperty.java index 6805296e..e85f6ee4 100644 --- a/markwon-html/src/main/java/io/noties/markwon/html/CssProperty.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/CssProperty.java @@ -1,6 +1,6 @@ package io.noties.markwon.html; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; public class CssProperty { diff --git a/markwon-html/src/main/java/io/noties/markwon/html/HtmlEmptyTagReplacement.java b/markwon-html/src/main/java/io/noties/markwon/html/HtmlEmptyTagReplacement.java index 416346e6..48b8acb4 100644 --- a/markwon-html/src/main/java/io/noties/markwon/html/HtmlEmptyTagReplacement.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/HtmlEmptyTagReplacement.java @@ -1,7 +1,7 @@ package io.noties.markwon.html; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; /** * This class will be used to append some text to output in order to diff --git a/markwon-html/src/main/java/io/noties/markwon/html/HtmlPlugin.java b/markwon-html/src/main/java/io/noties/markwon/html/HtmlPlugin.java index 6a20ada6..c4462c99 100644 --- a/markwon-html/src/main/java/io/noties/markwon/html/HtmlPlugin.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/HtmlPlugin.java @@ -1,7 +1,7 @@ package io.noties.markwon.html; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import org.commonmark.node.HtmlBlock; import org.commonmark.node.HtmlInline; diff --git a/markwon-html/src/main/java/io/noties/markwon/html/HtmlTag.java b/markwon-html/src/main/java/io/noties/markwon/html/HtmlTag.java index a44ccd82..956de7c8 100644 --- a/markwon-html/src/main/java/io/noties/markwon/html/HtmlTag.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/HtmlTag.java @@ -1,7 +1,7 @@ package io.noties.markwon.html; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import java.util.List; import java.util.Map; diff --git a/markwon-html/src/main/java/io/noties/markwon/html/HtmlTagImpl.java b/markwon-html/src/main/java/io/noties/markwon/html/HtmlTagImpl.java index 3dfb2c00..c41cbad0 100644 --- a/markwon-html/src/main/java/io/noties/markwon/html/HtmlTagImpl.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/HtmlTagImpl.java @@ -1,7 +1,7 @@ package io.noties.markwon.html; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import java.util.Collections; import java.util.List; diff --git a/markwon-html/src/main/java/io/noties/markwon/html/MarkwonHtmlParser.java b/markwon-html/src/main/java/io/noties/markwon/html/MarkwonHtmlParser.java index 368306a7..d9e3e36d 100644 --- a/markwon-html/src/main/java/io/noties/markwon/html/MarkwonHtmlParser.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/MarkwonHtmlParser.java @@ -1,6 +1,6 @@ package io.noties.markwon.html; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import java.util.List; diff --git a/markwon-html/src/main/java/io/noties/markwon/html/MarkwonHtmlParserImpl.java b/markwon-html/src/main/java/io/noties/markwon/html/MarkwonHtmlParserImpl.java index ba0ce566..3bf73419 100644 --- a/markwon-html/src/main/java/io/noties/markwon/html/MarkwonHtmlParserImpl.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/MarkwonHtmlParserImpl.java @@ -1,8 +1,8 @@ package io.noties.markwon.html; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.VisibleForTesting; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; import java.util.ArrayList; import java.util.Arrays; diff --git a/markwon-html/src/main/java/io/noties/markwon/html/MarkwonHtmlRenderer.java b/markwon-html/src/main/java/io/noties/markwon/html/MarkwonHtmlRenderer.java index f0e87f37..e55cec2c 100644 --- a/markwon-html/src/main/java/io/noties/markwon/html/MarkwonHtmlRenderer.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/MarkwonHtmlRenderer.java @@ -1,7 +1,7 @@ package io.noties.markwon.html; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import io.noties.markwon.MarkwonVisitor; diff --git a/markwon-html/src/main/java/io/noties/markwon/html/MarkwonHtmlRendererImpl.java b/markwon-html/src/main/java/io/noties/markwon/html/MarkwonHtmlRendererImpl.java index fe3e1d97..0877f732 100644 --- a/markwon-html/src/main/java/io/noties/markwon/html/MarkwonHtmlRendererImpl.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/MarkwonHtmlRendererImpl.java @@ -1,7 +1,7 @@ package io.noties.markwon.html; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import java.util.Collections; import java.util.HashMap; @@ -116,7 +116,7 @@ class MarkwonHtmlRendererImpl extends MarkwonHtmlRenderer { checkState(); this.excludeDefaults = excludeDefaults; } - + boolean excludeDefaults() { return excludeDefaults; } diff --git a/markwon-html/src/main/java/io/noties/markwon/html/MarkwonHtmlRendererNoOp.java b/markwon-html/src/main/java/io/noties/markwon/html/MarkwonHtmlRendererNoOp.java index f8194ca3..8d446325 100644 --- a/markwon-html/src/main/java/io/noties/markwon/html/MarkwonHtmlRendererNoOp.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/MarkwonHtmlRendererNoOp.java @@ -1,7 +1,7 @@ package io.noties.markwon.html; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import io.noties.markwon.MarkwonVisitor; diff --git a/markwon-html/src/main/java/io/noties/markwon/html/TagHandler.java b/markwon-html/src/main/java/io/noties/markwon/html/TagHandler.java index 60332b61..66a30e06 100644 --- a/markwon-html/src/main/java/io/noties/markwon/html/TagHandler.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/TagHandler.java @@ -1,6 +1,6 @@ package io.noties.markwon.html; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import java.util.Collection; diff --git a/markwon-html/src/main/java/io/noties/markwon/html/TagHandlerNoOp.java b/markwon-html/src/main/java/io/noties/markwon/html/TagHandlerNoOp.java index 944a10f9..79ba8dea 100644 --- a/markwon-html/src/main/java/io/noties/markwon/html/TagHandlerNoOp.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/TagHandlerNoOp.java @@ -1,6 +1,6 @@ package io.noties.markwon.html; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import java.util.Arrays; import java.util.Collection; diff --git a/markwon-html/src/main/java/io/noties/markwon/html/TrimmingAppender.java b/markwon-html/src/main/java/io/noties/markwon/html/TrimmingAppender.java index 0115a531..fa585991 100644 --- a/markwon-html/src/main/java/io/noties/markwon/html/TrimmingAppender.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/TrimmingAppender.java @@ -1,6 +1,6 @@ package io.noties.markwon.html; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import static io.noties.markwon.html.AppendableUtils.appendQuietly; diff --git a/markwon-html/src/main/java/io/noties/markwon/html/jsoup/nodes/CommonMarkEntities.java b/markwon-html/src/main/java/io/noties/markwon/html/jsoup/nodes/CommonMarkEntities.java index 1bf8dca5..353f6d9b 100644 --- a/markwon-html/src/main/java/io/noties/markwon/html/jsoup/nodes/CommonMarkEntities.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/jsoup/nodes/CommonMarkEntities.java @@ -1,6 +1,6 @@ package io.noties.markwon.html.jsoup.nodes; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import org.commonmark.internal.util.Html5Entities; diff --git a/markwon-html/src/main/java/io/noties/markwon/html/jsoup/parser/Token.java b/markwon-html/src/main/java/io/noties/markwon/html/jsoup/parser/Token.java index 428186b5..d78c0b56 100644 --- a/markwon-html/src/main/java/io/noties/markwon/html/jsoup/parser/Token.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/jsoup/parser/Token.java @@ -1,6 +1,6 @@ package io.noties.markwon.html.jsoup.parser; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import io.noties.markwon.html.jsoup.helper.Validate; import io.noties.markwon.html.jsoup.nodes.Attributes; @@ -251,7 +251,7 @@ public abstract class Token { } } - public final static class EndTag extends Tag{ + public final static class EndTag extends Tag { EndTag() { super(TokenType.EndTag); } diff --git a/markwon-html/src/main/java/io/noties/markwon/html/span/SubScriptSpan.java b/markwon-html/src/main/java/io/noties/markwon/html/span/SubScriptSpan.java index 8fa840ad..c807e051 100644 --- a/markwon-html/src/main/java/io/noties/markwon/html/span/SubScriptSpan.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/span/SubScriptSpan.java @@ -1,9 +1,10 @@ package io.noties.markwon.html.span; -import android.support.annotation.NonNull; import android.text.TextPaint; import android.text.style.MetricAffectingSpan; +import androidx.annotation.NonNull; + import io.noties.markwon.html.HtmlPlugin; public class SubScriptSpan extends MetricAffectingSpan { diff --git a/markwon-html/src/main/java/io/noties/markwon/html/span/SuperScriptSpan.java b/markwon-html/src/main/java/io/noties/markwon/html/span/SuperScriptSpan.java index 6c4d5247..9e6a657b 100644 --- a/markwon-html/src/main/java/io/noties/markwon/html/span/SuperScriptSpan.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/span/SuperScriptSpan.java @@ -1,9 +1,10 @@ package io.noties.markwon.html.span; -import android.support.annotation.NonNull; import android.text.TextPaint; import android.text.style.MetricAffectingSpan; +import androidx.annotation.NonNull; + import io.noties.markwon.html.HtmlPlugin; public class SuperScriptSpan extends MetricAffectingSpan { diff --git a/markwon-html/src/main/java/io/noties/markwon/html/tag/BlockquoteHandler.java b/markwon-html/src/main/java/io/noties/markwon/html/tag/BlockquoteHandler.java index ee8373c7..e579a7d3 100644 --- a/markwon-html/src/main/java/io/noties/markwon/html/tag/BlockquoteHandler.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/tag/BlockquoteHandler.java @@ -1,19 +1,19 @@ package io.noties.markwon.html.tag; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import org.commonmark.node.BlockQuote; import java.util.Collection; import java.util.Collections; -import io.noties.markwon.html.HtmlTag; -import io.noties.markwon.html.MarkwonHtmlRenderer; -import io.noties.markwon.html.TagHandler; import io.noties.markwon.MarkwonConfiguration; import io.noties.markwon.MarkwonVisitor; import io.noties.markwon.SpanFactory; import io.noties.markwon.SpannableBuilder; +import io.noties.markwon.html.HtmlTag; +import io.noties.markwon.html.MarkwonHtmlRenderer; +import io.noties.markwon.html.TagHandler; public class BlockquoteHandler extends TagHandler { diff --git a/markwon-html/src/main/java/io/noties/markwon/html/tag/EmphasisHandler.java b/markwon-html/src/main/java/io/noties/markwon/html/tag/EmphasisHandler.java index ff7c4e5e..d1f7fdd8 100644 --- a/markwon-html/src/main/java/io/noties/markwon/html/tag/EmphasisHandler.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/tag/EmphasisHandler.java @@ -1,17 +1,17 @@ package io.noties.markwon.html.tag; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import org.commonmark.node.Emphasis; import java.util.Arrays; import java.util.Collection; -import io.noties.markwon.html.HtmlTag; import io.noties.markwon.MarkwonConfiguration; import io.noties.markwon.RenderProps; import io.noties.markwon.SpanFactory; +import io.noties.markwon.html.HtmlTag; public class EmphasisHandler extends SimpleTagHandler { @Nullable diff --git a/markwon-html/src/main/java/io/noties/markwon/html/tag/HeadingHandler.java b/markwon-html/src/main/java/io/noties/markwon/html/tag/HeadingHandler.java index 155a46fa..7c694e2d 100644 --- a/markwon-html/src/main/java/io/noties/markwon/html/tag/HeadingHandler.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/tag/HeadingHandler.java @@ -1,18 +1,18 @@ package io.noties.markwon.html.tag; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import org.commonmark.node.Heading; import java.util.Arrays; import java.util.Collection; -import io.noties.markwon.core.CoreProps; -import io.noties.markwon.html.HtmlTag; import io.noties.markwon.MarkwonConfiguration; import io.noties.markwon.RenderProps; import io.noties.markwon.SpanFactory; +import io.noties.markwon.core.CoreProps; +import io.noties.markwon.html.HtmlTag; public class HeadingHandler extends SimpleTagHandler { diff --git a/markwon-html/src/main/java/io/noties/markwon/html/tag/ImageHandler.java b/markwon-html/src/main/java/io/noties/markwon/html/tag/ImageHandler.java index e93c42cb..ad170b0e 100644 --- a/markwon-html/src/main/java/io/noties/markwon/html/tag/ImageHandler.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/tag/ImageHandler.java @@ -1,22 +1,23 @@ package io.noties.markwon.html.tag; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.text.TextUtils; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import org.commonmark.node.Image; import java.util.Collection; import java.util.Collections; import java.util.Map; -import io.noties.markwon.image.ImageSize; import io.noties.markwon.MarkwonConfiguration; import io.noties.markwon.RenderProps; import io.noties.markwon.SpanFactory; import io.noties.markwon.html.CssInlineStyleParser; import io.noties.markwon.html.HtmlTag; import io.noties.markwon.image.ImageProps; +import io.noties.markwon.image.ImageSize; public class ImageHandler extends SimpleTagHandler { diff --git a/markwon-html/src/main/java/io/noties/markwon/html/tag/ImageSizeParserImpl.java b/markwon-html/src/main/java/io/noties/markwon/html/tag/ImageSizeParserImpl.java index 69eb0412..97e2e61f 100644 --- a/markwon-html/src/main/java/io/noties/markwon/html/tag/ImageSizeParserImpl.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/tag/ImageSizeParserImpl.java @@ -1,10 +1,11 @@ package io.noties.markwon.html.tag; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.VisibleForTesting; import android.text.TextUtils; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; + import java.util.Map; import io.noties.markwon.html.CssInlineStyleParser; diff --git a/markwon-html/src/main/java/io/noties/markwon/html/tag/LinkHandler.java b/markwon-html/src/main/java/io/noties/markwon/html/tag/LinkHandler.java index a3cd6084..fdd830cc 100644 --- a/markwon-html/src/main/java/io/noties/markwon/html/tag/LinkHandler.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/tag/LinkHandler.java @@ -1,19 +1,20 @@ package io.noties.markwon.html.tag; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.text.TextUtils; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import org.commonmark.node.Link; import java.util.Collection; import java.util.Collections; -import io.noties.markwon.core.CoreProps; -import io.noties.markwon.html.HtmlTag; import io.noties.markwon.MarkwonConfiguration; import io.noties.markwon.RenderProps; import io.noties.markwon.SpanFactory; +import io.noties.markwon.core.CoreProps; +import io.noties.markwon.html.HtmlTag; public class LinkHandler extends SimpleTagHandler { @Nullable diff --git a/markwon-html/src/main/java/io/noties/markwon/html/tag/ListHandler.java b/markwon-html/src/main/java/io/noties/markwon/html/tag/ListHandler.java index d214aaca..33499b6c 100644 --- a/markwon-html/src/main/java/io/noties/markwon/html/tag/ListHandler.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/tag/ListHandler.java @@ -1,21 +1,21 @@ package io.noties.markwon.html.tag; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import org.commonmark.node.ListItem; import java.util.Arrays; import java.util.Collection; -import io.noties.markwon.core.CoreProps; -import io.noties.markwon.html.HtmlTag; -import io.noties.markwon.html.MarkwonHtmlRenderer; -import io.noties.markwon.html.TagHandler; import io.noties.markwon.MarkwonConfiguration; import io.noties.markwon.MarkwonVisitor; import io.noties.markwon.RenderProps; import io.noties.markwon.SpanFactory; import io.noties.markwon.SpannableBuilder; +import io.noties.markwon.core.CoreProps; +import io.noties.markwon.html.HtmlTag; +import io.noties.markwon.html.MarkwonHtmlRenderer; +import io.noties.markwon.html.TagHandler; public class ListHandler extends TagHandler { diff --git a/markwon-html/src/main/java/io/noties/markwon/html/tag/SimpleTagHandler.java b/markwon-html/src/main/java/io/noties/markwon/html/tag/SimpleTagHandler.java index bf0f141c..337ac748 100644 --- a/markwon-html/src/main/java/io/noties/markwon/html/tag/SimpleTagHandler.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/tag/SimpleTagHandler.java @@ -1,17 +1,17 @@ package io.noties.markwon.html.tag; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import java.util.Collection; -import io.noties.markwon.html.HtmlTag; -import io.noties.markwon.html.MarkwonHtmlRenderer; -import io.noties.markwon.html.TagHandler; import io.noties.markwon.MarkwonConfiguration; import io.noties.markwon.MarkwonVisitor; import io.noties.markwon.RenderProps; import io.noties.markwon.SpannableBuilder; +import io.noties.markwon.html.HtmlTag; +import io.noties.markwon.html.MarkwonHtmlRenderer; +import io.noties.markwon.html.TagHandler; public abstract class SimpleTagHandler extends TagHandler { diff --git a/markwon-html/src/main/java/io/noties/markwon/html/tag/StrikeHandler.java b/markwon-html/src/main/java/io/noties/markwon/html/tag/StrikeHandler.java index 2715a8f5..6c01e31f 100644 --- a/markwon-html/src/main/java/io/noties/markwon/html/tag/StrikeHandler.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/tag/StrikeHandler.java @@ -1,19 +1,20 @@ package io.noties.markwon.html.tag; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.text.style.StrikethroughSpan; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import java.util.Arrays; import java.util.Collection; -import io.noties.markwon.html.HtmlTag; -import io.noties.markwon.html.MarkwonHtmlRenderer; -import io.noties.markwon.html.TagHandler; import io.noties.markwon.MarkwonConfiguration; import io.noties.markwon.MarkwonVisitor; import io.noties.markwon.SpanFactory; import io.noties.markwon.SpannableBuilder; +import io.noties.markwon.html.HtmlTag; +import io.noties.markwon.html.MarkwonHtmlRenderer; +import io.noties.markwon.html.TagHandler; public class StrikeHandler extends TagHandler { diff --git a/markwon-html/src/main/java/io/noties/markwon/html/tag/StrongEmphasisHandler.java b/markwon-html/src/main/java/io/noties/markwon/html/tag/StrongEmphasisHandler.java index 2a28ec7c..a698ae44 100644 --- a/markwon-html/src/main/java/io/noties/markwon/html/tag/StrongEmphasisHandler.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/tag/StrongEmphasisHandler.java @@ -1,17 +1,17 @@ package io.noties.markwon.html.tag; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import org.commonmark.node.StrongEmphasis; import java.util.Arrays; import java.util.Collection; -import io.noties.markwon.html.HtmlTag; import io.noties.markwon.MarkwonConfiguration; import io.noties.markwon.RenderProps; import io.noties.markwon.SpanFactory; +import io.noties.markwon.html.HtmlTag; public class StrongEmphasisHandler extends SimpleTagHandler { @Nullable diff --git a/markwon-html/src/main/java/io/noties/markwon/html/tag/SubScriptHandler.java b/markwon-html/src/main/java/io/noties/markwon/html/tag/SubScriptHandler.java index cfcf77c5..679eed7c 100644 --- a/markwon-html/src/main/java/io/noties/markwon/html/tag/SubScriptHandler.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/tag/SubScriptHandler.java @@ -1,14 +1,14 @@ package io.noties.markwon.html.tag; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import java.util.Collection; import java.util.Collections; -import io.noties.markwon.html.HtmlTag; import io.noties.markwon.MarkwonConfiguration; import io.noties.markwon.RenderProps; +import io.noties.markwon.html.HtmlTag; import io.noties.markwon.html.span.SubScriptSpan; public class SubScriptHandler extends SimpleTagHandler { diff --git a/markwon-html/src/main/java/io/noties/markwon/html/tag/SuperScriptHandler.java b/markwon-html/src/main/java/io/noties/markwon/html/tag/SuperScriptHandler.java index 199350aa..e0b94201 100644 --- a/markwon-html/src/main/java/io/noties/markwon/html/tag/SuperScriptHandler.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/tag/SuperScriptHandler.java @@ -1,14 +1,14 @@ package io.noties.markwon.html.tag; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import java.util.Collection; import java.util.Collections; -import io.noties.markwon.html.HtmlTag; import io.noties.markwon.MarkwonConfiguration; import io.noties.markwon.RenderProps; +import io.noties.markwon.html.HtmlTag; import io.noties.markwon.html.span.SuperScriptSpan; public class SuperScriptHandler extends SimpleTagHandler { diff --git a/markwon-html/src/main/java/io/noties/markwon/html/tag/UnderlineHandler.java b/markwon-html/src/main/java/io/noties/markwon/html/tag/UnderlineHandler.java index 300cc69c..09ed2fa5 100644 --- a/markwon-html/src/main/java/io/noties/markwon/html/tag/UnderlineHandler.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/tag/UnderlineHandler.java @@ -1,16 +1,17 @@ package io.noties.markwon.html.tag; -import android.support.annotation.NonNull; import android.text.style.UnderlineSpan; +import androidx.annotation.NonNull; + import java.util.Arrays; import java.util.Collection; +import io.noties.markwon.MarkwonVisitor; +import io.noties.markwon.SpannableBuilder; import io.noties.markwon.html.HtmlTag; import io.noties.markwon.html.MarkwonHtmlRenderer; import io.noties.markwon.html.TagHandler; -import io.noties.markwon.MarkwonVisitor; -import io.noties.markwon.SpannableBuilder; public class UnderlineHandler extends TagHandler { diff --git a/markwon-html/src/test/java/io/noties/markwon/html/CssInlineStyleParserTest.java b/markwon-html/src/test/java/io/noties/markwon/html/CssInlineStyleParserTest.java index 88a45f14..1c0c0235 100644 --- a/markwon-html/src/test/java/io/noties/markwon/html/CssInlineStyleParserTest.java +++ b/markwon-html/src/test/java/io/noties/markwon/html/CssInlineStyleParserTest.java @@ -1,6 +1,6 @@ package io.noties.markwon.html; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import org.junit.Before; import org.junit.Test; diff --git a/markwon-html/src/test/java/io/noties/markwon/html/MarkwonHtmlParserImplTest.java b/markwon-html/src/test/java/io/noties/markwon/html/MarkwonHtmlParserImplTest.java index a2e0e7bd..2930e28b 100644 --- a/markwon-html/src/test/java/io/noties/markwon/html/MarkwonHtmlParserImplTest.java +++ b/markwon-html/src/test/java/io/noties/markwon/html/MarkwonHtmlParserImplTest.java @@ -1,7 +1,7 @@ package io.noties.markwon.html; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/markwon-html/src/test/java/io/noties/markwon/html/tag/ImageSizeParserImplTest.java b/markwon-html/src/test/java/io/noties/markwon/html/tag/ImageSizeParserImplTest.java index daa5491e..c31ab3e1 100644 --- a/markwon-html/src/test/java/io/noties/markwon/html/tag/ImageSizeParserImplTest.java +++ b/markwon-html/src/test/java/io/noties/markwon/html/tag/ImageSizeParserImplTest.java @@ -1,7 +1,7 @@ package io.noties.markwon.html.tag; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import org.junit.Assert; import org.junit.Before; diff --git a/markwon-image-gif/src/main/java/ru/noties/markwon/image/gif/GifMediaDecoder.java b/markwon-image-gif/src/main/java/ru/noties/markwon/image/gif/GifMediaDecoder.java index 72dd572c..7c06e13a 100644 --- a/markwon-image-gif/src/main/java/ru/noties/markwon/image/gif/GifMediaDecoder.java +++ b/markwon-image-gif/src/main/java/ru/noties/markwon/image/gif/GifMediaDecoder.java @@ -1,8 +1,8 @@ package ru.noties.markwon.image.gif; import android.graphics.drawable.Drawable; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import java.io.ByteArrayOutputStream; import java.io.IOException; diff --git a/markwon-image-gif/src/main/java/ru/noties/markwon/image/gif/GifPlugin.java b/markwon-image-gif/src/main/java/ru/noties/markwon/image/gif/GifPlugin.java index 6cceffdf..754f91ae 100644 --- a/markwon-image-gif/src/main/java/ru/noties/markwon/image/gif/GifPlugin.java +++ b/markwon-image-gif/src/main/java/ru/noties/markwon/image/gif/GifPlugin.java @@ -1,6 +1,6 @@ package ru.noties.markwon.image.gif; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import ru.noties.markwon.AbstractMarkwonPlugin; import ru.noties.markwon.image.AsyncDrawableLoader; diff --git a/markwon-image-glide/src/main/java/io/noties/markwon/image/glide/GlideImagesPlugin.java b/markwon-image-glide/src/main/java/io/noties/markwon/image/glide/GlideImagesPlugin.java index 21d2bc55..ae15afa4 100644 --- a/markwon-image-glide/src/main/java/io/noties/markwon/image/glide/GlideImagesPlugin.java +++ b/markwon-image-glide/src/main/java/io/noties/markwon/image/glide/GlideImagesPlugin.java @@ -2,11 +2,12 @@ package io.noties.markwon.image.glide; import android.content.Context; import android.graphics.drawable.Drawable; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.text.Spanned; import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import com.bumptech.glide.Glide; import com.bumptech.glide.RequestBuilder; import com.bumptech.glide.RequestManager; @@ -19,12 +20,12 @@ import org.commonmark.node.Image; import java.util.HashMap; import java.util.Map; -import io.noties.markwon.image.AsyncDrawable; -import io.noties.markwon.image.AsyncDrawableScheduler; import io.noties.markwon.AbstractMarkwonPlugin; import io.noties.markwon.MarkwonConfiguration; import io.noties.markwon.MarkwonSpansFactory; +import io.noties.markwon.image.AsyncDrawable; import io.noties.markwon.image.AsyncDrawableLoader; +import io.noties.markwon.image.AsyncDrawableScheduler; import io.noties.markwon.image.DrawableUtils; import io.noties.markwon.image.ImageSpanFactory; diff --git a/markwon-image-okhttp/src/main/java/ru/noties/markwon/image/okhttp/OkHttpImagesPlugin.java b/markwon-image-okhttp/src/main/java/ru/noties/markwon/image/okhttp/OkHttpImagesPlugin.java index 36cc79fb..6a72136a 100644 --- a/markwon-image-okhttp/src/main/java/ru/noties/markwon/image/okhttp/OkHttpImagesPlugin.java +++ b/markwon-image-okhttp/src/main/java/ru/noties/markwon/image/okhttp/OkHttpImagesPlugin.java @@ -1,6 +1,6 @@ package ru.noties.markwon.image.okhttp; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import java.util.Arrays; diff --git a/markwon-image-okhttp/src/main/java/ru/noties/markwon/image/okhttp/OkHttpSchemeHandler.java b/markwon-image-okhttp/src/main/java/ru/noties/markwon/image/okhttp/OkHttpSchemeHandler.java index 32527bdf..e1ce930b 100644 --- a/markwon-image-okhttp/src/main/java/ru/noties/markwon/image/okhttp/OkHttpSchemeHandler.java +++ b/markwon-image-okhttp/src/main/java/ru/noties/markwon/image/okhttp/OkHttpSchemeHandler.java @@ -1,8 +1,8 @@ package ru.noties.markwon.image.okhttp; import android.net.Uri; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import java.io.IOException; import java.io.InputStream; diff --git a/markwon-image-picasso/src/main/java/io/noties/markwon/image/picasso/PicassoImagesPlugin.java b/markwon-image-picasso/src/main/java/io/noties/markwon/image/picasso/PicassoImagesPlugin.java index 5d3fc7b5..4e92fced 100644 --- a/markwon-image-picasso/src/main/java/io/noties/markwon/image/picasso/PicassoImagesPlugin.java +++ b/markwon-image-picasso/src/main/java/io/noties/markwon/image/picasso/PicassoImagesPlugin.java @@ -5,11 +5,12 @@ import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.text.Spanned; import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import com.squareup.picasso.Picasso; import com.squareup.picasso.RequestCreator; import com.squareup.picasso.Target; diff --git a/markwon-image-svg/src/main/java/ru/noties/markwon/image/svg/SvgMediaDecoder.java b/markwon-image-svg/src/main/java/ru/noties/markwon/image/svg/SvgMediaDecoder.java index 8c8b9dcc..8b2a9527 100644 --- a/markwon-image-svg/src/main/java/ru/noties/markwon/image/svg/SvgMediaDecoder.java +++ b/markwon-image-svg/src/main/java/ru/noties/markwon/image/svg/SvgMediaDecoder.java @@ -5,8 +5,8 @@ import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.caverock.androidsvg.SVG; import com.caverock.androidsvg.SVGParseException; diff --git a/markwon-image-svg/src/main/java/ru/noties/markwon/image/svg/SvgPlugin.java b/markwon-image-svg/src/main/java/ru/noties/markwon/image/svg/SvgPlugin.java index c4486fc6..34573c9f 100644 --- a/markwon-image-svg/src/main/java/ru/noties/markwon/image/svg/SvgPlugin.java +++ b/markwon-image-svg/src/main/java/ru/noties/markwon/image/svg/SvgPlugin.java @@ -1,7 +1,7 @@ package ru.noties.markwon.image.svg; import android.content.res.Resources; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import ru.noties.markwon.AbstractMarkwonPlugin; import ru.noties.markwon.image.AsyncDrawableLoader; diff --git a/markwon-image/build.gradle b/markwon-image/build.gradle index 16c70814..2e0c86dd 100644 --- a/markwon-image/build.gradle +++ b/markwon-image/build.gradle @@ -17,11 +17,10 @@ dependencies { api project(':markwon-core') - // todo: note that it includes these implicitly deps.with { - api it['android-gif'] - api it['android-svg'] - api it['okhttp'] + compileOnly it['android-gif'] + compileOnly it['android-svg'] + compileOnly it['okhttp'] } deps['test'].with { diff --git a/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderBuilder.java b/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderBuilder.java index 7ee1116e..731aa449 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderBuilder.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderBuilder.java @@ -1,7 +1,7 @@ package io.noties.markwon.image; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import java.util.HashMap; import java.util.Map; diff --git a/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderImpl.java b/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderImpl.java index 54e6c1b2..4428177c 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderImpl.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderImpl.java @@ -5,11 +5,12 @@ import android.net.Uri; import android.os.Handler; import android.os.Looper; import android.os.SystemClock; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.VisibleForTesting; import android.util.Log; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; + import java.util.HashMap; import java.util.Map; import java.util.concurrent.ExecutorService; diff --git a/markwon-image/src/main/java/io/noties/markwon/image/DefaultImageMediaDecoder.java b/markwon-image/src/main/java/io/noties/markwon/image/DefaultImageMediaDecoder.java index 3aec554a..e820ff45 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/DefaultImageMediaDecoder.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/DefaultImageMediaDecoder.java @@ -5,8 +5,9 @@ import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import java.io.InputStream; import java.util.Collection; diff --git a/markwon-image/src/main/java/io/noties/markwon/image/ImageItem.java b/markwon-image/src/main/java/io/noties/markwon/image/ImageItem.java index 8e62e010..191e3e10 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/ImageItem.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/ImageItem.java @@ -1,8 +1,9 @@ package io.noties.markwon.image; import android.graphics.drawable.Drawable; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import java.io.InputStream; diff --git a/markwon-image/src/main/java/io/noties/markwon/image/ImagesPlugin.java b/markwon-image/src/main/java/io/noties/markwon/image/ImagesPlugin.java index 7a9a8df8..8c02695e 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/ImagesPlugin.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/ImagesPlugin.java @@ -1,12 +1,13 @@ package io.noties.markwon.image; import android.graphics.drawable.Drawable; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.VisibleForTesting; import android.text.Spanned; import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; + import org.commonmark.node.Image; import java.util.concurrent.ExecutorService; diff --git a/markwon-image/src/main/java/io/noties/markwon/image/MediaDecoder.java b/markwon-image/src/main/java/io/noties/markwon/image/MediaDecoder.java index 6f05bb20..6b69ba03 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/MediaDecoder.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/MediaDecoder.java @@ -1,8 +1,9 @@ package io.noties.markwon.image; import android.graphics.drawable.Drawable; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import java.io.InputStream; import java.util.Collection; diff --git a/markwon-image/src/main/java/io/noties/markwon/image/SchemeHandler.java b/markwon-image/src/main/java/io/noties/markwon/image/SchemeHandler.java index d16ffc0e..6a8ccbf1 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/SchemeHandler.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/SchemeHandler.java @@ -1,7 +1,8 @@ package io.noties.markwon.image; import android.net.Uri; -import android.support.annotation.NonNull; + +import androidx.annotation.NonNull; import java.util.Collection; diff --git a/markwon-image/src/main/java/io/noties/markwon/image/data/DataUri.java b/markwon-image/src/main/java/io/noties/markwon/image/data/DataUri.java index 0d14bad9..cca96861 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/data/DataUri.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/data/DataUri.java @@ -1,6 +1,6 @@ package io.noties.markwon.image.data; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; public class DataUri { diff --git a/markwon-image/src/main/java/io/noties/markwon/image/data/DataUriDecoder.java b/markwon-image/src/main/java/io/noties/markwon/image/data/DataUriDecoder.java index e802cad2..ce311d57 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/data/DataUriDecoder.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/data/DataUriDecoder.java @@ -1,7 +1,7 @@ package io.noties.markwon.image.data; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import android.text.TextUtils; import android.util.Base64; diff --git a/markwon-image/src/main/java/io/noties/markwon/image/data/DataUriParser.java b/markwon-image/src/main/java/io/noties/markwon/image/data/DataUriParser.java index ad3311b2..5dc8f1ec 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/data/DataUriParser.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/data/DataUriParser.java @@ -1,7 +1,7 @@ package io.noties.markwon.image.data; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; public abstract class DataUriParser { diff --git a/markwon-image/src/main/java/io/noties/markwon/image/data/DataUriSchemeHandler.java b/markwon-image/src/main/java/io/noties/markwon/image/data/DataUriSchemeHandler.java index 6ba1cb33..3a68c54e 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/data/DataUriSchemeHandler.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/data/DataUriSchemeHandler.java @@ -1,7 +1,7 @@ package io.noties.markwon.image.data; import android.net.Uri; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import java.io.ByteArrayInputStream; import java.util.Collection; diff --git a/markwon-image/src/main/java/io/noties/markwon/image/file/FileSchemeHandler.java b/markwon-image/src/main/java/io/noties/markwon/image/file/FileSchemeHandler.java index 257fcfe8..43a969f5 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/file/FileSchemeHandler.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/file/FileSchemeHandler.java @@ -3,8 +3,8 @@ package io.noties.markwon.image.file; import android.content.Context; import android.content.res.AssetManager; import android.net.Uri; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import android.text.TextUtils; import android.webkit.MimeTypeMap; diff --git a/markwon-image/src/main/java/io/noties/markwon/image/gif/GifMediaDecoder.java b/markwon-image/src/main/java/io/noties/markwon/image/gif/GifMediaDecoder.java index 508c6667..335cbb71 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/gif/GifMediaDecoder.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/gif/GifMediaDecoder.java @@ -1,8 +1,8 @@ package io.noties.markwon.image.gif; import android.graphics.drawable.Drawable; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -112,7 +112,7 @@ public class GifMediaDecoder extends MediaDecoder { static { boolean result = true; try { - GifDrawable.class.getName(); + pl.droidsonroids.gif.GifDrawable.class.getName(); } catch (Throwable t) { result = false; t.printStackTrace(); diff --git a/markwon-image/src/main/java/io/noties/markwon/image/network/NetworkSchemeHandler.java b/markwon-image/src/main/java/io/noties/markwon/image/network/NetworkSchemeHandler.java index 03c015e3..9eaff883 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/network/NetworkSchemeHandler.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/network/NetworkSchemeHandler.java @@ -1,8 +1,8 @@ package io.noties.markwon.image.network; import android.net.Uri; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import java.io.BufferedInputStream; import java.io.IOException; diff --git a/markwon-image/src/main/java/io/noties/markwon/image/network/OkHttpNetworkSchemeHandler.java b/markwon-image/src/main/java/io/noties/markwon/image/network/OkHttpNetworkSchemeHandler.java index 5203d23a..3d7bea00 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/network/OkHttpNetworkSchemeHandler.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/network/OkHttpNetworkSchemeHandler.java @@ -1,7 +1,7 @@ package io.noties.markwon.image.network; import android.net.Uri; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import java.io.InputStream; import java.util.Arrays; diff --git a/markwon-image/src/main/java/io/noties/markwon/image/svg/SvgMediaDecoder.java b/markwon-image/src/main/java/io/noties/markwon/image/svg/SvgMediaDecoder.java index 7482262e..9e58d1e7 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/svg/SvgMediaDecoder.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/svg/SvgMediaDecoder.java @@ -5,8 +5,8 @@ import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.caverock.androidsvg.SVG; import com.caverock.androidsvg.SVGParseException; @@ -99,7 +99,7 @@ public class SvgMediaDecoder extends MediaDecoder { static { boolean result = true; try { - SVG.class.getName(); + com.caverock.androidsvg.SVG.class.getName(); } catch (Throwable t) { result = false; t.printStackTrace(); diff --git a/markwon-image/src/test/java/io/noties/markwon/image/AsyncDrawableLoaderImplTest.java b/markwon-image/src/test/java/io/noties/markwon/image/AsyncDrawableLoaderImplTest.java index c2e65dcd..f3beff49 100644 --- a/markwon-image/src/test/java/io/noties/markwon/image/AsyncDrawableLoaderImplTest.java +++ b/markwon-image/src/test/java/io/noties/markwon/image/AsyncDrawableLoaderImplTest.java @@ -3,8 +3,8 @@ package io.noties.markwon.image; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Handler; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import org.junit.Before; import org.junit.Test; diff --git a/markwon-image/src/test/java/io/noties/markwon/image/ImagesPluginTest.java b/markwon-image/src/test/java/io/noties/markwon/image/ImagesPluginTest.java index f19b1563..faf25ebb 100644 --- a/markwon-image/src/test/java/io/noties/markwon/image/ImagesPluginTest.java +++ b/markwon-image/src/test/java/io/noties/markwon/image/ImagesPluginTest.java @@ -1,6 +1,6 @@ package io.noties.markwon.image; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import android.text.Spanned; import android.widget.TextView; diff --git a/markwon-image/src/test/java/io/noties/markwon/image/data/DataUriSchemeHandlerTest.java b/markwon-image/src/test/java/io/noties/markwon/image/data/DataUriSchemeHandlerTest.java index 58d9ffd2..d523595d 100644 --- a/markwon-image/src/test/java/io/noties/markwon/image/data/DataUriSchemeHandlerTest.java +++ b/markwon-image/src/test/java/io/noties/markwon/image/data/DataUriSchemeHandlerTest.java @@ -1,7 +1,7 @@ package io.noties.markwon.image.data; import android.net.Uri; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import org.junit.Before; import org.junit.Test; diff --git a/markwon-linkify/src/main/java/io/noties/markwon/linkify/LinkifyPlugin.java b/markwon-linkify/src/main/java/io/noties/markwon/linkify/LinkifyPlugin.java index 05098dcf..292884bf 100644 --- a/markwon-linkify/src/main/java/io/noties/markwon/linkify/LinkifyPlugin.java +++ b/markwon-linkify/src/main/java/io/noties/markwon/linkify/LinkifyPlugin.java @@ -1,10 +1,11 @@ package io.noties.markwon.linkify; -import android.support.annotation.IntDef; -import android.support.annotation.NonNull; import android.text.SpannableStringBuilder; import android.text.util.Linkify; +import androidx.annotation.IntDef; +import androidx.annotation.NonNull; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/markwon-recycler-table/src/main/java/io/noties/markwon/recycler/table/TableBorderDrawable.java b/markwon-recycler-table/src/main/java/io/noties/markwon/recycler/table/TableBorderDrawable.java index e78dbd84..8202ab84 100644 --- a/markwon-recycler-table/src/main/java/io/noties/markwon/recycler/table/TableBorderDrawable.java +++ b/markwon-recycler-table/src/main/java/io/noties/markwon/recycler/table/TableBorderDrawable.java @@ -5,10 +5,11 @@ import android.graphics.ColorFilter; import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.drawable.Drawable; -import android.support.annotation.ColorInt; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.Px; + +import androidx.annotation.ColorInt; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.Px; class TableBorderDrawable extends Drawable { diff --git a/markwon-recycler-table/src/main/java/io/noties/markwon/recycler/table/TableEntry.java b/markwon-recycler-table/src/main/java/io/noties/markwon/recycler/table/TableEntry.java index 01190f29..2784221f 100644 --- a/markwon-recycler-table/src/main/java/io/noties/markwon/recycler/table/TableEntry.java +++ b/markwon-recycler-table/src/main/java/io/noties/markwon/recycler/table/TableEntry.java @@ -4,12 +4,6 @@ import android.annotation.SuppressLint; import android.content.Context; import android.content.res.Resources; import android.graphics.drawable.Drawable; -import android.support.annotation.ColorInt; -import android.support.annotation.IdRes; -import android.support.annotation.LayoutRes; -import android.support.annotation.NonNull; -import android.support.annotation.Px; -import android.support.annotation.VisibleForTesting; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; @@ -18,16 +12,23 @@ import android.widget.TableLayout; import android.widget.TableRow; import android.widget.TextView; +import androidx.annotation.ColorInt; +import androidx.annotation.IdRes; +import androidx.annotation.LayoutRes; +import androidx.annotation.NonNull; +import androidx.annotation.Px; +import androidx.annotation.VisibleForTesting; + import org.commonmark.ext.gfm.tables.TableBlock; import java.util.HashMap; import java.util.List; import java.util.Map; -import io.noties.markwon.recycler.MarkwonAdapter; -import io.noties.markwon.utils.NoCopySpannableFactory; import io.noties.markwon.Markwon; import io.noties.markwon.ext.tables.Table; +import io.noties.markwon.recycler.MarkwonAdapter; +import io.noties.markwon.utils.NoCopySpannableFactory; /** * @since 3.0.0 diff --git a/markwon-recycler-table/src/main/java/io/noties/markwon/recycler/table/TableEntryPlugin.java b/markwon-recycler-table/src/main/java/io/noties/markwon/recycler/table/TableEntryPlugin.java index 0a339c3a..b917bb19 100644 --- a/markwon-recycler-table/src/main/java/io/noties/markwon/recycler/table/TableEntryPlugin.java +++ b/markwon-recycler-table/src/main/java/io/noties/markwon/recycler/table/TableEntryPlugin.java @@ -1,7 +1,8 @@ package io.noties.markwon.recycler.table; import android.content.Context; -import android.support.annotation.NonNull; + +import androidx.annotation.NonNull; import org.commonmark.ext.gfm.tables.TablesExtension; import org.commonmark.parser.Parser; diff --git a/markwon-recycler-table/src/main/java/io/noties/markwon/recycler/table/TableEntryTheme.java b/markwon-recycler-table/src/main/java/io/noties/markwon/recycler/table/TableEntryTheme.java index 9164bd12..987499c6 100644 --- a/markwon-recycler-table/src/main/java/io/noties/markwon/recycler/table/TableEntryTheme.java +++ b/markwon-recycler-table/src/main/java/io/noties/markwon/recycler/table/TableEntryTheme.java @@ -1,12 +1,13 @@ package io.noties.markwon.recycler.table; import android.graphics.Paint; -import android.support.annotation.ColorInt; -import android.support.annotation.NonNull; -import android.support.annotation.Px; -import io.noties.markwon.utils.ColorUtils; +import androidx.annotation.ColorInt; +import androidx.annotation.NonNull; +import androidx.annotation.Px; + import io.noties.markwon.ext.tables.TableTheme; +import io.noties.markwon.utils.ColorUtils; /** * Mimics TableTheme to allow uniform table customization diff --git a/markwon-recycler/build.gradle b/markwon-recycler/build.gradle index a5a16087..63c7742e 100644 --- a/markwon-recycler/build.gradle +++ b/markwon-recycler/build.gradle @@ -18,7 +18,7 @@ dependencies { api project(':markwon-core') deps.with { - api it['support-recycler-view'] + api it['x-recycler-view'] } } diff --git a/markwon-recycler/src/main/java/io/noties/markwon/recycler/MarkwonAdapter.java b/markwon-recycler/src/main/java/io/noties/markwon/recycler/MarkwonAdapter.java index 99894ddd..265c9273 100644 --- a/markwon-recycler/src/main/java/io/noties/markwon/recycler/MarkwonAdapter.java +++ b/markwon-recycler/src/main/java/io/noties/markwon/recycler/MarkwonAdapter.java @@ -1,14 +1,15 @@ package io.noties.markwon.recycler; -import android.support.annotation.IdRes; -import android.support.annotation.LayoutRes; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import androidx.annotation.IdRes; +import androidx.annotation.LayoutRes; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.RecyclerView; + import org.commonmark.node.Node; import java.util.List; diff --git a/markwon-recycler/src/main/java/io/noties/markwon/recycler/MarkwonAdapterImpl.java b/markwon-recycler/src/main/java/io/noties/markwon/recycler/MarkwonAdapterImpl.java index ea7c34d2..d773edcc 100644 --- a/markwon-recycler/src/main/java/io/noties/markwon/recycler/MarkwonAdapterImpl.java +++ b/markwon-recycler/src/main/java/io/noties/markwon/recycler/MarkwonAdapterImpl.java @@ -1,10 +1,11 @@ package io.noties.markwon.recycler; -import android.support.annotation.NonNull; import android.util.SparseArray; import android.view.LayoutInflater; import android.view.ViewGroup; +import androidx.annotation.NonNull; + import org.commonmark.node.Node; import java.util.Collections; diff --git a/markwon-recycler/src/main/java/io/noties/markwon/recycler/SimpleEntry.java b/markwon-recycler/src/main/java/io/noties/markwon/recycler/SimpleEntry.java index a876597a..b55be1fb 100644 --- a/markwon-recycler/src/main/java/io/noties/markwon/recycler/SimpleEntry.java +++ b/markwon-recycler/src/main/java/io/noties/markwon/recycler/SimpleEntry.java @@ -1,14 +1,15 @@ package io.noties.markwon.recycler; -import android.support.annotation.IdRes; -import android.support.annotation.LayoutRes; -import android.support.annotation.NonNull; import android.text.Spanned; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; +import androidx.annotation.IdRes; +import androidx.annotation.LayoutRes; +import androidx.annotation.NonNull; + import org.commonmark.node.Node; import java.util.HashMap; diff --git a/markwon-syntax-highlight/build.gradle b/markwon-syntax-highlight/build.gradle index 6d9353ff..4c6586ed 100644 --- a/markwon-syntax-highlight/build.gradle +++ b/markwon-syntax-highlight/build.gradle @@ -18,7 +18,6 @@ dependencies { api project(':markwon-core') deps.with { - api it['support-annotations'] api it['prism4j'] } } diff --git a/markwon-syntax-highlight/src/main/java/io/noties/markwon/syntax/Prism4jSyntaxHighlight.java b/markwon-syntax-highlight/src/main/java/io/noties/markwon/syntax/Prism4jSyntaxHighlight.java index a36a0170..cc78c401 100644 --- a/markwon-syntax-highlight/src/main/java/io/noties/markwon/syntax/Prism4jSyntaxHighlight.java +++ b/markwon-syntax-highlight/src/main/java/io/noties/markwon/syntax/Prism4jSyntaxHighlight.java @@ -1,11 +1,12 @@ package io.noties.markwon.syntax; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.text.SpannableStringBuilder; import android.text.TextUtils; -import ru.noties.prism4j.Prism4j; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import io.noties.prism4j.Prism4j; public class Prism4jSyntaxHighlight implements SyntaxHighlight { diff --git a/markwon-syntax-highlight/src/main/java/io/noties/markwon/syntax/Prism4jSyntaxVisitor.java b/markwon-syntax-highlight/src/main/java/io/noties/markwon/syntax/Prism4jSyntaxVisitor.java index 9fd14435..41056d9f 100644 --- a/markwon-syntax-highlight/src/main/java/io/noties/markwon/syntax/Prism4jSyntaxVisitor.java +++ b/markwon-syntax-highlight/src/main/java/io/noties/markwon/syntax/Prism4jSyntaxVisitor.java @@ -1,10 +1,11 @@ package io.noties.markwon.syntax; -import android.support.annotation.NonNull; import android.text.SpannableStringBuilder; -import ru.noties.prism4j.AbsVisitor; -import ru.noties.prism4j.Prism4j; +import androidx.annotation.NonNull; + +import io.noties.prism4j.AbsVisitor; +import io.noties.prism4j.Prism4j; class Prism4jSyntaxVisitor extends AbsVisitor { diff --git a/markwon-syntax-highlight/src/main/java/io/noties/markwon/syntax/Prism4jTheme.java b/markwon-syntax-highlight/src/main/java/io/noties/markwon/syntax/Prism4jTheme.java index 6f15c6ed..dff31736 100644 --- a/markwon-syntax-highlight/src/main/java/io/noties/markwon/syntax/Prism4jTheme.java +++ b/markwon-syntax-highlight/src/main/java/io/noties/markwon/syntax/Prism4jTheme.java @@ -1,10 +1,11 @@ package io.noties.markwon.syntax; -import android.support.annotation.ColorInt; -import android.support.annotation.NonNull; import android.text.SpannableStringBuilder; -import ru.noties.prism4j.Prism4j; +import androidx.annotation.ColorInt; +import androidx.annotation.NonNull; + +import io.noties.prism4j.Prism4j; public interface Prism4jTheme { diff --git a/markwon-syntax-highlight/src/main/java/io/noties/markwon/syntax/Prism4jThemeBase.java b/markwon-syntax-highlight/src/main/java/io/noties/markwon/syntax/Prism4jThemeBase.java index 16110cf0..abf71299 100644 --- a/markwon-syntax-highlight/src/main/java/io/noties/markwon/syntax/Prism4jThemeBase.java +++ b/markwon-syntax-highlight/src/main/java/io/noties/markwon/syntax/Prism4jThemeBase.java @@ -1,17 +1,18 @@ package io.noties.markwon.syntax; -import android.support.annotation.ColorInt; -import android.support.annotation.FloatRange; -import android.support.annotation.IntRange; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.style.ForegroundColorSpan; +import androidx.annotation.ColorInt; +import androidx.annotation.FloatRange; +import androidx.annotation.IntRange; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import java.util.HashMap; -import ru.noties.prism4j.Prism4j; +import io.noties.prism4j.Prism4j; public abstract class Prism4jThemeBase implements Prism4jTheme { diff --git a/markwon-syntax-highlight/src/main/java/io/noties/markwon/syntax/Prism4jThemeDarkula.java b/markwon-syntax-highlight/src/main/java/io/noties/markwon/syntax/Prism4jThemeDarkula.java index df586fd0..5c9dcde3 100644 --- a/markwon-syntax-highlight/src/main/java/io/noties/markwon/syntax/Prism4jThemeDarkula.java +++ b/markwon-syntax-highlight/src/main/java/io/noties/markwon/syntax/Prism4jThemeDarkula.java @@ -1,13 +1,14 @@ package io.noties.markwon.syntax; -import android.support.annotation.ColorInt; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.text.SpannableStringBuilder; import android.text.Spanned; -import io.noties.markwon.core.spans.StrongEmphasisSpan; +import androidx.annotation.ColorInt; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import io.noties.markwon.core.spans.EmphasisSpan; +import io.noties.markwon.core.spans.StrongEmphasisSpan; public class Prism4jThemeDarkula extends Prism4jThemeBase { diff --git a/markwon-syntax-highlight/src/main/java/io/noties/markwon/syntax/Prism4jThemeDefault.java b/markwon-syntax-highlight/src/main/java/io/noties/markwon/syntax/Prism4jThemeDefault.java index b44e46e7..86ecca7b 100644 --- a/markwon-syntax-highlight/src/main/java/io/noties/markwon/syntax/Prism4jThemeDefault.java +++ b/markwon-syntax-highlight/src/main/java/io/noties/markwon/syntax/Prism4jThemeDefault.java @@ -1,12 +1,13 @@ package io.noties.markwon.syntax; -import android.support.annotation.ColorInt; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.style.BackgroundColorSpan; +import androidx.annotation.ColorInt; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import io.noties.markwon.core.spans.EmphasisSpan; import io.noties.markwon.core.spans.StrongEmphasisSpan; diff --git a/markwon-syntax-highlight/src/main/java/io/noties/markwon/syntax/SyntaxHighlightPlugin.java b/markwon-syntax-highlight/src/main/java/io/noties/markwon/syntax/SyntaxHighlightPlugin.java index 9bcefc38..f815fee4 100644 --- a/markwon-syntax-highlight/src/main/java/io/noties/markwon/syntax/SyntaxHighlightPlugin.java +++ b/markwon-syntax-highlight/src/main/java/io/noties/markwon/syntax/SyntaxHighlightPlugin.java @@ -1,12 +1,12 @@ package io.noties.markwon.syntax; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import io.noties.markwon.AbstractMarkwonPlugin; import io.noties.markwon.MarkwonConfiguration; import io.noties.markwon.core.MarkwonTheme; -import ru.noties.prism4j.Prism4j; +import io.noties.prism4j.Prism4j; public class SyntaxHighlightPlugin extends AbstractMarkwonPlugin { diff --git a/markwon-test-span/build.gradle b/markwon-test-span/build.gradle index cba39010..0e519e25 100644 --- a/markwon-test-span/build.gradle +++ b/markwon-test-span/build.gradle @@ -15,7 +15,7 @@ android { dependencies { - api deps['support-annotations'] + api deps['x-annotations'] deps['test'].with { api it['junit'] diff --git a/markwon-test-span/src/main/java/io/noties/markwon/test/TestSpan.java b/markwon-test-span/src/main/java/io/noties/markwon/test/TestSpan.java index fe41dd2a..595391bd 100644 --- a/markwon-test-span/src/main/java/io/noties/markwon/test/TestSpan.java +++ b/markwon-test-span/src/main/java/io/noties/markwon/test/TestSpan.java @@ -1,6 +1,6 @@ package io.noties.markwon.test; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import java.util.ArrayList; import java.util.Collections; diff --git a/markwon-test-span/src/main/java/io/noties/markwon/test/TestSpanDocument.java b/markwon-test-span/src/main/java/io/noties/markwon/test/TestSpanDocument.java index 91b479db..ae94c89d 100644 --- a/markwon-test-span/src/main/java/io/noties/markwon/test/TestSpanDocument.java +++ b/markwon-test-span/src/main/java/io/noties/markwon/test/TestSpanDocument.java @@ -1,6 +1,6 @@ package io.noties.markwon.test; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import java.util.List; diff --git a/markwon-test-span/src/main/java/io/noties/markwon/test/TestSpanEnumerator.java b/markwon-test-span/src/main/java/io/noties/markwon/test/TestSpanEnumerator.java index 7e75f149..807656a2 100644 --- a/markwon-test-span/src/main/java/io/noties/markwon/test/TestSpanEnumerator.java +++ b/markwon-test-span/src/main/java/io/noties/markwon/test/TestSpanEnumerator.java @@ -1,6 +1,6 @@ package io.noties.markwon.test; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; public class TestSpanEnumerator { diff --git a/markwon-test-span/src/main/java/io/noties/markwon/test/TestSpanMatcher.java b/markwon-test-span/src/main/java/io/noties/markwon/test/TestSpanMatcher.java index a3cf1b57..372a4f7a 100644 --- a/markwon-test-span/src/main/java/io/noties/markwon/test/TestSpanMatcher.java +++ b/markwon-test-span/src/main/java/io/noties/markwon/test/TestSpanMatcher.java @@ -1,8 +1,8 @@ package io.noties.markwon.test; -import android.support.annotation.NonNull; import android.text.Spanned; +import androidx.annotation.NonNull; import org.junit.Assert; import org.junit.ComparisonFailure; diff --git a/markwon-test-span/src/main/java/io/noties/markwon/test/TestSpanSpan.java b/markwon-test-span/src/main/java/io/noties/markwon/test/TestSpanSpan.java index f51a32ba..b7e41f5d 100644 --- a/markwon-test-span/src/main/java/io/noties/markwon/test/TestSpanSpan.java +++ b/markwon-test-span/src/main/java/io/noties/markwon/test/TestSpanSpan.java @@ -1,6 +1,6 @@ package io.noties.markwon.test; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import java.util.List; import java.util.Map; diff --git a/markwon-test-span/src/main/java/io/noties/markwon/test/TestSpanText.java b/markwon-test-span/src/main/java/io/noties/markwon/test/TestSpanText.java index 995d3541..64895af9 100644 --- a/markwon-test-span/src/main/java/io/noties/markwon/test/TestSpanText.java +++ b/markwon-test-span/src/main/java/io/noties/markwon/test/TestSpanText.java @@ -1,6 +1,6 @@ package io.noties.markwon.test; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import java.util.Collections; import java.util.List; diff --git a/sample/build.gradle b/sample/build.gradle index df6695e4..f624824b 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -44,15 +44,10 @@ dependencies { implementation project(':markwon-recycler') implementation project(':markwon-recycler-table') - // these are for glide - implementation 'com.android.support:animated-vector-drawable:28.0.0' - implementation 'com.android.support:support-fragment:28.0.0' - - implementation project(':markwon-image-glide') implementation project(':markwon-image-picasso') deps.with { - implementation it['support-recycler-view'] + implementation it['x-recycler-view'] implementation it['okhttp'] implementation it['prism4j'] implementation it['debug'] diff --git a/sample/src/main/java/io/noties/markwon/sample/MainActivity.java b/sample/src/main/java/io/noties/markwon/sample/MainActivity.java index 4d9bee65..a7805f52 100644 --- a/sample/src/main/java/io/noties/markwon/sample/MainActivity.java +++ b/sample/src/main/java/io/noties/markwon/sample/MainActivity.java @@ -4,10 +4,11 @@ import android.app.Activity; import android.content.Context; import android.content.Intent; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.VisibleForTesting; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; + +import androidx.annotation.NonNull; +import androidx.annotation.VisibleForTesting; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; import java.util.ArrayList; import java.util.List; diff --git a/sample/src/main/java/io/noties/markwon/sample/Sample.java b/sample/src/main/java/io/noties/markwon/sample/Sample.java index 8e20c80d..459ef4c8 100644 --- a/sample/src/main/java/io/noties/markwon/sample/Sample.java +++ b/sample/src/main/java/io/noties/markwon/sample/Sample.java @@ -1,6 +1,6 @@ package io.noties.markwon.sample; -import android.support.annotation.StringRes; +import androidx.annotation.StringRes; public enum Sample { diff --git a/sample/src/main/java/io/noties/markwon/sample/SampleItem.java b/sample/src/main/java/io/noties/markwon/sample/SampleItem.java index 57266e49..aa71551b 100644 --- a/sample/src/main/java/io/noties/markwon/sample/SampleItem.java +++ b/sample/src/main/java/io/noties/markwon/sample/SampleItem.java @@ -1,12 +1,13 @@ package io.noties.markwon.sample; -import android.support.annotation.NonNull; import android.text.Spanned; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; +import androidx.annotation.NonNull; + import io.noties.adapt.Item; import io.noties.markwon.Markwon; import io.noties.markwon.utils.NoCopySpannableFactory; diff --git a/sample/src/main/java/io/noties/markwon/sample/SampleItemDecoration.java b/sample/src/main/java/io/noties/markwon/sample/SampleItemDecoration.java index 16a04286..3a3ad1d5 100644 --- a/sample/src/main/java/io/noties/markwon/sample/SampleItemDecoration.java +++ b/sample/src/main/java/io/noties/markwon/sample/SampleItemDecoration.java @@ -3,11 +3,12 @@ package io.noties.markwon.sample; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Rect; -import android.support.annotation.ColorInt; -import android.support.annotation.Px; -import android.support.v7.widget.RecyclerView; import android.view.View; +import androidx.annotation.ColorInt; +import androidx.annotation.Px; +import androidx.recyclerview.widget.RecyclerView; + class SampleItemDecoration extends RecyclerView.ItemDecoration { private final Rect rect = new Rect(); diff --git a/sample/src/main/java/io/noties/markwon/sample/basicplugins/BasicPluginsActivity.java b/sample/src/main/java/io/noties/markwon/sample/basicplugins/BasicPluginsActivity.java index 8e6c2500..df22cf06 100644 --- a/sample/src/main/java/io/noties/markwon/sample/basicplugins/BasicPluginsActivity.java +++ b/sample/src/main/java/io/noties/markwon/sample/basicplugins/BasicPluginsActivity.java @@ -4,27 +4,21 @@ import android.app.Activity; import android.graphics.Color; import android.net.Uri; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.text.Layout; import android.text.TextUtils; import android.text.style.AlignmentSpan; import android.text.style.ForegroundColorSpan; import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import org.commonmark.node.Heading; import org.commonmark.node.Paragraph; import java.util.Collection; import java.util.Collections; -import io.noties.markwon.core.MarkwonTheme; -import io.noties.markwon.html.HtmlTag; -import io.noties.markwon.image.ImageItem; -import io.noties.markwon.image.ImagesPlugin; -import io.noties.markwon.image.SchemeHandler; -import io.noties.markwon.image.network.NetworkSchemeHandler; -import io.noties.markwon.movement.MovementMethodPlugin; import io.noties.markwon.AbstractMarkwonPlugin; import io.noties.markwon.Markwon; import io.noties.markwon.MarkwonConfiguration; @@ -32,8 +26,15 @@ import io.noties.markwon.MarkwonPlugin; import io.noties.markwon.MarkwonSpansFactory; import io.noties.markwon.MarkwonVisitor; import io.noties.markwon.RenderProps; +import io.noties.markwon.core.MarkwonTheme; import io.noties.markwon.html.HtmlPlugin; +import io.noties.markwon.html.HtmlTag; import io.noties.markwon.html.tag.SimpleTagHandler; +import io.noties.markwon.image.ImageItem; +import io.noties.markwon.image.ImagesPlugin; +import io.noties.markwon.image.SchemeHandler; +import io.noties.markwon.image.network.NetworkSchemeHandler; +import io.noties.markwon.movement.MovementMethodPlugin; public class BasicPluginsActivity extends Activity { diff --git a/sample/src/main/java/io/noties/markwon/sample/core/CoreActivity.java b/sample/src/main/java/io/noties/markwon/sample/core/CoreActivity.java index f208fa07..f1a67f50 100644 --- a/sample/src/main/java/io/noties/markwon/sample/core/CoreActivity.java +++ b/sample/src/main/java/io/noties/markwon/sample/core/CoreActivity.java @@ -2,15 +2,16 @@ package io.noties.markwon.sample.core; import android.app.Activity; import android.os.Bundle; -import android.support.annotation.Nullable; import android.text.Spanned; import android.widget.TextView; import android.widget.Toast; +import androidx.annotation.Nullable; + import org.commonmark.node.Node; -import io.noties.markwon.core.CorePlugin; import io.noties.markwon.Markwon; +import io.noties.markwon.core.CorePlugin; public class CoreActivity extends Activity { diff --git a/sample/src/main/java/io/noties/markwon/sample/customextension/CustomExtensionActivity.java b/sample/src/main/java/io/noties/markwon/sample/customextension/CustomExtensionActivity.java index c8615331..99bd6d4c 100644 --- a/sample/src/main/java/io/noties/markwon/sample/customextension/CustomExtensionActivity.java +++ b/sample/src/main/java/io/noties/markwon/sample/customextension/CustomExtensionActivity.java @@ -2,9 +2,10 @@ package io.noties.markwon.sample.customextension; import android.app.Activity; import android.os.Bundle; -import android.support.annotation.Nullable; import android.widget.TextView; +import androidx.annotation.Nullable; + import io.noties.markwon.Markwon; import io.noties.markwon.sample.R; diff --git a/sample/src/main/java/io/noties/markwon/sample/customextension/IconNode.java b/sample/src/main/java/io/noties/markwon/sample/customextension/IconNode.java index c0a2f75b..92447920 100644 --- a/sample/src/main/java/io/noties/markwon/sample/customextension/IconNode.java +++ b/sample/src/main/java/io/noties/markwon/sample/customextension/IconNode.java @@ -1,6 +1,6 @@ package io.noties.markwon.sample.customextension; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import org.commonmark.node.CustomNode; import org.commonmark.node.Delimited; diff --git a/sample/src/main/java/io/noties/markwon/sample/customextension/IconPlugin.java b/sample/src/main/java/io/noties/markwon/sample/customextension/IconPlugin.java index bf39834c..e8459dd3 100644 --- a/sample/src/main/java/io/noties/markwon/sample/customextension/IconPlugin.java +++ b/sample/src/main/java/io/noties/markwon/sample/customextension/IconPlugin.java @@ -1,8 +1,9 @@ package io.noties.markwon.sample.customextension; -import android.support.annotation.NonNull; import android.text.TextUtils; +import androidx.annotation.NonNull; + import org.commonmark.parser.Parser; import io.noties.markwon.AbstractMarkwonPlugin; diff --git a/sample/src/main/java/io/noties/markwon/sample/customextension/IconProcessor.java b/sample/src/main/java/io/noties/markwon/sample/customextension/IconProcessor.java index 0fa1797b..484575fb 100644 --- a/sample/src/main/java/io/noties/markwon/sample/customextension/IconProcessor.java +++ b/sample/src/main/java/io/noties/markwon/sample/customextension/IconProcessor.java @@ -1,8 +1,9 @@ package io.noties.markwon.sample.customextension; -import android.support.annotation.NonNull; import android.text.TextUtils; +import androidx.annotation.NonNull; + import org.commonmark.node.Node; import org.commonmark.node.Text; import org.commonmark.parser.delimiter.DelimiterProcessor; diff --git a/sample/src/main/java/io/noties/markwon/sample/customextension/IconSpan.java b/sample/src/main/java/io/noties/markwon/sample/customextension/IconSpan.java index b055233d..acc2096f 100644 --- a/sample/src/main/java/io/noties/markwon/sample/customextension/IconSpan.java +++ b/sample/src/main/java/io/noties/markwon/sample/customextension/IconSpan.java @@ -4,11 +4,12 @@ import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.drawable.Drawable; -import android.support.annotation.IntDef; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.text.style.ReplacementSpan; +import androidx.annotation.IntDef; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/sample/src/main/java/io/noties/markwon/sample/customextension/IconSpanProvider.java b/sample/src/main/java/io/noties/markwon/sample/customextension/IconSpanProvider.java index a324ae35..24f542e8 100644 --- a/sample/src/main/java/io/noties/markwon/sample/customextension/IconSpanProvider.java +++ b/sample/src/main/java/io/noties/markwon/sample/customextension/IconSpanProvider.java @@ -4,8 +4,9 @@ import android.content.Context; import android.content.res.Resources; import android.graphics.drawable.Drawable; import android.os.Build; -import android.support.annotation.DrawableRes; -import android.support.annotation.NonNull; + +import androidx.annotation.DrawableRes; +import androidx.annotation.NonNull; @SuppressWarnings("WeakerAccess") public abstract class IconSpanProvider { diff --git a/sample/src/main/java/io/noties/markwon/sample/latex/LatexActivity.java b/sample/src/main/java/io/noties/markwon/sample/latex/LatexActivity.java index 6c94afa9..2eea4fed 100644 --- a/sample/src/main/java/io/noties/markwon/sample/latex/LatexActivity.java +++ b/sample/src/main/java/io/noties/markwon/sample/latex/LatexActivity.java @@ -2,11 +2,12 @@ package io.noties.markwon.sample.latex; import android.app.Activity; import android.os.Bundle; -import android.support.annotation.Nullable; import android.widget.TextView; -import io.noties.markwon.ext.latex.JLatexMathPlugin; +import androidx.annotation.Nullable; + import io.noties.markwon.Markwon; +import io.noties.markwon.ext.latex.JLatexMathPlugin; import io.noties.markwon.sample.R; public class LatexActivity extends Activity { diff --git a/sample/src/main/java/io/noties/markwon/sample/recycler/RecyclerActivity.java b/sample/src/main/java/io/noties/markwon/sample/recycler/RecyclerActivity.java index 077bf967..bbd6f890 100644 --- a/sample/src/main/java/io/noties/markwon/sample/recycler/RecyclerActivity.java +++ b/sample/src/main/java/io/noties/markwon/sample/recycler/RecyclerActivity.java @@ -4,12 +4,13 @@ import android.app.Activity; import android.content.Context; import android.net.Uri; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; import android.text.TextUtils; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + import org.commonmark.ext.gfm.tables.TableBlock; import org.commonmark.node.FencedCodeBlock; @@ -18,6 +19,8 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import io.noties.debug.AndroidLogDebugOutput; +import io.noties.debug.Debug; import io.noties.markwon.AbstractMarkwonPlugin; import io.noties.markwon.Markwon; import io.noties.markwon.MarkwonConfiguration; @@ -32,8 +35,6 @@ import io.noties.markwon.recycler.table.TableEntryPlugin; import io.noties.markwon.sample.R; import io.noties.markwon.urlprocessor.UrlProcessor; import io.noties.markwon.urlprocessor.UrlProcessorRelativeToAbsolute; -import io.noties.debug.AndroidLogDebugOutput; -import io.noties.debug.Debug; public class RecyclerActivity extends Activity { diff --git a/sample/src/main/java/io/noties/markwon/sample/theme/ThemeActivity.java b/sample/src/main/java/io/noties/markwon/sample/theme/ThemeActivity.java index bec1afa6..bddaef52 100644 --- a/sample/src/main/java/io/noties/markwon/sample/theme/ThemeActivity.java +++ b/sample/src/main/java/io/noties/markwon/sample/theme/ThemeActivity.java @@ -2,7 +2,8 @@ package io.noties.markwon.sample.theme; import android.app.Activity; import android.os.Bundle; -import android.support.annotation.Nullable; + +import androidx.annotation.Nullable; import io.noties.markwon.sample.R; diff --git a/sample/src/main/res/layout/activity_main.xml b/sample/src/main/res/layout/activity_main.xml index 26bc9906..f0dfd7fd 100644 --- a/sample/src/main/res/layout/activity_main.xml +++ b/sample/src/main/res/layout/activity_main.xml @@ -3,7 +3,7 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - - \ No newline at end of file From 512814ac4cab4c577526d0b5abe82207def90462 Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Tue, 11 Jun 2019 18:53:31 +0300 Subject: [PATCH 21/42] SVG and GIF dependencies check --- .../image/AsyncDrawableLoaderBuilder.java | 6 ++- .../markwon/image/gif/GifMediaDecoder.java | 38 ++++--------------- .../noties/markwon/image/gif/GifSupport.java | 28 ++++++++++++++ .../markwon/image/svg/SvgMediaDecoder.java | 36 +++--------------- .../noties/markwon/image/svg/SvgSupport.java | 28 ++++++++++++++ 5 files changed, 73 insertions(+), 63 deletions(-) create mode 100644 markwon-image/src/main/java/io/noties/markwon/image/gif/GifSupport.java create mode 100644 markwon-image/src/main/java/io/noties/markwon/image/svg/SvgSupport.java diff --git a/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderBuilder.java b/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderBuilder.java index 731aa449..704ebffb 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderBuilder.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderBuilder.java @@ -10,8 +10,10 @@ import java.util.concurrent.Executors; import io.noties.markwon.image.data.DataUriSchemeHandler; import io.noties.markwon.image.gif.GifMediaDecoder; +import io.noties.markwon.image.gif.GifSupport; import io.noties.markwon.image.network.NetworkSchemeHandler; import io.noties.markwon.image.svg.SvgMediaDecoder; +import io.noties.markwon.image.svg.SvgSupport; class AsyncDrawableLoaderBuilder { @@ -33,11 +35,11 @@ class AsyncDrawableLoaderBuilder { addSchemeHandler(NetworkSchemeHandler.create()); // add SVG and GIF, but only if they are present in the class-path - if (SvgMediaDecoder.available()) { + if (SvgSupport.hasSvgSupport()) { addMediaDecoder(SvgMediaDecoder.create()); } - if (GifMediaDecoder.available()) { + if (GifSupport.hasGifSupport()) { addMediaDecoder(GifMediaDecoder.create()); } diff --git a/markwon-image/src/main/java/io/noties/markwon/image/gif/GifMediaDecoder.java b/markwon-image/src/main/java/io/noties/markwon/image/gif/GifMediaDecoder.java index 335cbb71..923fc113 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/gif/GifMediaDecoder.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/gif/GifMediaDecoder.java @@ -1,6 +1,7 @@ package io.noties.markwon.image.gif; import android.graphics.drawable.Drawable; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -37,21 +38,13 @@ public class GifMediaDecoder extends MediaDecoder { return new GifMediaDecoder(autoPlayGif); } - /** - * @return boolean indicating if GIF dependency is satisfied - * @since 4.0.0-SNAPSHOT - */ - public static boolean available() { - return Holder.HAS_GIF; - } - private final boolean autoPlayGif; protected GifMediaDecoder(boolean autoPlayGif) { this.autoPlayGif = autoPlayGif; // @since 4.0.0-SNAPSHOT - Holder.validate(); + validate(); } @NonNull @@ -104,28 +97,11 @@ public class GifMediaDecoder extends MediaDecoder { return outputStream.toByteArray(); } - // @since 4.0.0-SNAPSHOT - private static class Holder { - - private static final boolean HAS_GIF; - - static { - boolean result = true; - try { - pl.droidsonroids.gif.GifDrawable.class.getName(); - } catch (Throwable t) { - result = false; - t.printStackTrace(); - } - HAS_GIF = result; - } - - static void validate() { - if (!HAS_GIF) { - throw new IllegalStateException("`pl.droidsonroids.gif:android-gif-drawable:*` " + - "dependency is missing, please add to your project explicitly if you " + - "wish to use GIF media decoder"); - } + private static void validate() { + if (!GifSupport.hasGifSupport()) { + throw new IllegalStateException("`pl.droidsonroids.gif:android-gif-drawable:*` " + + "dependency is missing, please add to your project explicitly if you " + + "wish to use GIF media decoder"); } } } diff --git a/markwon-image/src/main/java/io/noties/markwon/image/gif/GifSupport.java b/markwon-image/src/main/java/io/noties/markwon/image/gif/GifSupport.java new file mode 100644 index 00000000..3e996d45 --- /dev/null +++ b/markwon-image/src/main/java/io/noties/markwon/image/gif/GifSupport.java @@ -0,0 +1,28 @@ +package io.noties.markwon.image.gif; + +/** + * @since 4.0.0-SNAPSHOT + */ +public abstract class GifSupport { + + private static boolean HAS_GIF; + + static { + boolean result; + try { + pl.droidsonroids.gif.GifDrawable.class.getName(); + result = true; + } catch (Throwable t) { + t.printStackTrace(); + result = false; + } + HAS_GIF = result; + } + + public static boolean hasGifSupport() { + return HAS_GIF; + } + + private GifSupport() { + } +} diff --git a/markwon-image/src/main/java/io/noties/markwon/image/svg/SvgMediaDecoder.java b/markwon-image/src/main/java/io/noties/markwon/image/svg/SvgMediaDecoder.java index 9e58d1e7..eb4cb74c 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/svg/SvgMediaDecoder.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/svg/SvgMediaDecoder.java @@ -5,6 +5,7 @@ import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -39,14 +40,6 @@ public class SvgMediaDecoder extends MediaDecoder { return new SvgMediaDecoder(resources); } - /** - * @return boolean indicating if SVG dependency is satisfied - * @since 4.0.0-SNAPSHOT - */ - public static boolean available() { - return Holder.HAS_SVG; - } - private final Resources resources; @SuppressWarnings("WeakerAccess") @@ -54,7 +47,7 @@ public class SvgMediaDecoder extends MediaDecoder { this.resources = resources; // @since 4.0.0-SNAPSHOT - Holder.validate(); + validate(); } @NonNull @@ -91,27 +84,10 @@ public class SvgMediaDecoder extends MediaDecoder { return Collections.singleton(CONTENT_TYPE); } - // @since 4.0.0-SNAPSHOT - private static class Holder { - - private static final boolean HAS_SVG; - - static { - boolean result = true; - try { - com.caverock.androidsvg.SVG.class.getName(); - } catch (Throwable t) { - result = false; - t.printStackTrace(); - } - HAS_SVG = result; - } - - static void validate() { - if (!HAS_SVG) { - throw new IllegalStateException("`com.caverock:androidsvg:*` dependency is missing, " + - "please add to your project explicitly if you wish to use SVG media decoder"); - } + private static void validate() { + if (!SvgSupport.hasSvgSupport()) { + throw new IllegalStateException("`com.caverock:androidsvg:*` dependency is missing, " + + "please add to your project explicitly if you wish to use SVG media decoder"); } } } diff --git a/markwon-image/src/main/java/io/noties/markwon/image/svg/SvgSupport.java b/markwon-image/src/main/java/io/noties/markwon/image/svg/SvgSupport.java new file mode 100644 index 00000000..7ed0ce46 --- /dev/null +++ b/markwon-image/src/main/java/io/noties/markwon/image/svg/SvgSupport.java @@ -0,0 +1,28 @@ +package io.noties.markwon.image.svg; + +/** + * @since 4.0.0-SNAPSHOT + */ +public abstract class SvgSupport { + + private static final boolean HAS_SVG; + + static { + boolean result; + try { + com.caverock.androidsvg.SVG.class.getName(); + result = true; + } catch (Throwable t) { + t.printStackTrace(); + result = false; + } + HAS_SVG = result; + } + + public static boolean hasSvgSupport() { + return HAS_SVG; + } + + private SvgSupport() { + } +} From 14591508b5dc794360ac2968a6a9ccb33e39df3a Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Wed, 12 Jun 2019 16:51:48 +0300 Subject: [PATCH 22/42] Update awesome section for documentation --- build.gradle | 2 +- docs/.vuepress/components/AwesomeGroup.vue | 57 ++++++++++++++++++++++ docs/README.md | 3 ++ 3 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 docs/.vuepress/components/AwesomeGroup.vue diff --git a/build.gradle b/build.gradle index 157757aa..8c49f472 100644 --- a/build.gradle +++ b/build.gradle @@ -62,7 +62,7 @@ ext { 'commonmark' : "com.atlassian.commonmark:commonmark:$commonMarkVersion", 'commonmark-strikethrough': "com.atlassian.commonmark:commonmark-ext-gfm-strikethrough:$commonMarkVersion", 'commonmark-table' : "com.atlassian.commonmark:commonmark-ext-gfm-tables:$commonMarkVersion", - 'android-svg' : 'com.caverock:androidsvg:1.2.1', + 'android-svg' : 'com.caverock:androidsvg:1.4', 'android-gif' : 'pl.droidsonroids.gif:android-gif-drawable:1.2.14', 'jlatexmath-android' : 'ru.noties:jlatexmath-android:0.1.0', 'okhttp' : 'com.squareup.okhttp3:okhttp:3.9.0', diff --git a/docs/.vuepress/components/AwesomeGroup.vue b/docs/.vuepress/components/AwesomeGroup.vue new file mode 100644 index 00000000..1399ffaf --- /dev/null +++ b/docs/.vuepress/components/AwesomeGroup.vue @@ -0,0 +1,57 @@ + + + + + + + diff --git a/docs/README.md b/docs/README.md index 2f6d8e5a..d1acc437 100644 --- a/docs/README.md +++ b/docs/README.md @@ -82,6 +82,9 @@ and 2 themes included: Light & Dark. It can be downloaded from [releases](ht * [FairNote](https://play.google.com/store/apps/details?id=com.rgiskard.fairnote) - simple and intuitive notepad app. It gives you speed and efficiency when you write notes, to-do lists, e-mails, or jot down quick ideas. * [Boxcryptor](https://www.boxcryptor.com) - A software that adds AES-256 and RSA encryption to Dropbox, Google Drive, OneDrive and many other clouds. + Extension/plugins: From 8b0edc32c3de247f3a6a6eaa8b1261bc4035c68c Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Wed, 12 Jun 2019 18:45:28 +0300 Subject: [PATCH 23/42] Started with v4 documentation --- README.md | 9 - _CHANGES.md | 3 +- docs/.vuepress/.artifacts.js | 2 +- docs/.vuepress/.artifacts.v3.js | 4 + docs/.vuepress/components/ArtifactPicker.vue | 2 +- docs/.vuepress/components/ArtifactPicker4.vue | 105 +++++ docs/.vuepress/config.js | 23 +- docs/docs/v4/core/configuration.md | 173 +++++++++ docs/docs/v4/core/core-plugin.md | 141 +++++++ docs/docs/v4/core/getting-started.md | 52 +++ docs/docs/v4/core/movement-method-plugin.md | 17 + docs/docs/v4/core/plugins.md | 361 ++++++++++++++++++ docs/docs/v4/core/registry.md | 97 +++++ docs/docs/v4/core/render-props.md | 75 ++++ docs/docs/v4/core/spans-factory.md | 103 +++++ docs/docs/v4/core/theme.md | 187 +++++++++ docs/docs/v4/core/visitor.md | 73 ++++ docs/docs/v4/install.md | 34 ++ docs/docs/v4/migration-3-4.md | 3 + docs/docs/v4/recipes.md | 3 + markwon-image-gif/build.gradle | 25 -- markwon-image-gif/gradle.properties | 4 - .../src/main/AndroidManifest.xml | 1 - .../markwon/image/gif/GifMediaDecoder.java | 81 ---- .../noties/markwon/image/gif/GifPlugin.java | 37 -- markwon-image-okhttp/build.gradle | 25 -- markwon-image-okhttp/gradle.properties | 4 - .../src/main/AndroidManifest.xml | 1 - .../image/okhttp/OkHttpImagesPlugin.java | 51 --- .../image/okhttp/OkHttpSchemeHandler.java | 55 --- markwon-image-svg/build.gradle | 25 -- markwon-image-svg/gradle.properties | 4 - .../src/main/AndroidManifest.xml | 1 - .../markwon/image/svg/SvgMediaDecoder.java | 72 ---- .../noties/markwon/image/svg/SvgPlugin.java | 33 -- 35 files changed, 1454 insertions(+), 432 deletions(-) create mode 100644 docs/.vuepress/.artifacts.v3.js create mode 100644 docs/.vuepress/components/ArtifactPicker4.vue create mode 100644 docs/docs/v4/core/configuration.md create mode 100644 docs/docs/v4/core/core-plugin.md create mode 100644 docs/docs/v4/core/getting-started.md create mode 100644 docs/docs/v4/core/movement-method-plugin.md create mode 100644 docs/docs/v4/core/plugins.md create mode 100644 docs/docs/v4/core/registry.md create mode 100644 docs/docs/v4/core/render-props.md create mode 100644 docs/docs/v4/core/spans-factory.md create mode 100644 docs/docs/v4/core/theme.md create mode 100644 docs/docs/v4/core/visitor.md create mode 100644 docs/docs/v4/install.md create mode 100644 docs/docs/v4/migration-3-4.md create mode 100644 docs/docs/v4/recipes.md delete mode 100644 markwon-image-gif/build.gradle delete mode 100644 markwon-image-gif/gradle.properties delete mode 100644 markwon-image-gif/src/main/AndroidManifest.xml delete mode 100644 markwon-image-gif/src/main/java/ru/noties/markwon/image/gif/GifMediaDecoder.java delete mode 100644 markwon-image-gif/src/main/java/ru/noties/markwon/image/gif/GifPlugin.java delete mode 100644 markwon-image-okhttp/build.gradle delete mode 100644 markwon-image-okhttp/gradle.properties delete mode 100644 markwon-image-okhttp/src/main/AndroidManifest.xml delete mode 100644 markwon-image-okhttp/src/main/java/ru/noties/markwon/image/okhttp/OkHttpImagesPlugin.java delete mode 100644 markwon-image-okhttp/src/main/java/ru/noties/markwon/image/okhttp/OkHttpSchemeHandler.java delete mode 100644 markwon-image-svg/build.gradle delete mode 100644 markwon-image-svg/gradle.properties delete mode 100644 markwon-image-svg/src/main/AndroidManifest.xml delete mode 100644 markwon-image-svg/src/main/java/ru/noties/markwon/image/svg/SvgMediaDecoder.java delete mode 100644 markwon-image-svg/src/main/java/ru/noties/markwon/image/svg/SvgPlugin.java diff --git a/README.md b/README.md index 075186b0..ddfd65dd 100644 --- a/README.md +++ b/README.md @@ -97,15 +97,6 @@ Please visit [documentation] web-site for reference [documentation]: https://noties.github.io/Markwon ---- - -## Applications using Markwon - -* [Partiko](https://partiko.app) -* [FairNote Notepad](https://play.google.com/store/apps/details?id=com.rgiskard.fairnote) -* [Boxcryptor](https://www.boxcryptor.com) - - --- # Demo diff --git a/_CHANGES.md b/_CHANGES.md index 0c8ea7de..e20c7985 100644 --- a/_CHANGES.md +++ b/_CHANGES.md @@ -9,4 +9,5 @@ * images-plugin moved to standalone again * removed MarkwonPlugin#configureHtmlRenderer -> now part of HtmlPlugin * TagHandler now has `supportedTags()` method -* html is moved completely to html-plugin \ No newline at end of file +* html is moved completely to html-plugin +* OnTextAddedListener \ No newline at end of file diff --git a/docs/.vuepress/.artifacts.js b/docs/.vuepress/.artifacts.js index 2a1c3f43..2f41fc13 100644 --- a/docs/.vuepress/.artifacts.js +++ b/docs/.vuepress/.artifacts.js @@ -1,4 +1,4 @@ // this is a generated file, do not modify. To update it run 'collectArtifacts.js' script -const artifacts = [{"id":"core","name":"Core","group":"ru.noties.markwon","description":"Core Markwon artifact that includes basic markdown parsing and rendering"},{"id":"ext-latex","name":"LaTeX","group":"ru.noties.markwon","description":"Extension to add LaTeX formulas to Markwon markdown"},{"id":"ext-strikethrough","name":"Strikethrough","group":"ru.noties.markwon","description":"Extension to add strikethrough markup to Markwon markdown"},{"id":"ext-tables","name":"Tables","group":"ru.noties.markwon","description":"Extension to add tables markup (GFM) to Markwon markdown"},{"id":"ext-tasklist","name":"Task List","group":"ru.noties.markwon","description":"Extension to add task lists (GFM) to Markwon markdown"},{"id":"html","name":"HTML","group":"ru.noties.markwon","description":"Provides HTML parsing functionality"},{"id":"image-gif","name":"Image GIF","group":"ru.noties.markwon","description":"Adds GIF media support to Markwon markdown"},{"id":"image-okhttp","name":"Image OkHttp","group":"ru.noties.markwon","description":"Adds OkHttp client to retrieve images data from network"},{"id":"image-svg","name":"Image SVG","group":"ru.noties.markwon","description":"Adds SVG media support to Markwon markdown"},{"id":"recycler","name":"Recycler","group":"ru.noties.markwon","description":"Provides RecyclerView.Adapter to display Markwon markdown"},{"id":"recycler-table","name":"Recycler Table","group":"ru.noties.markwon","description":"Provides MarkwonAdapter.Entry to render TableBlocks inside Android-native TableLayout widget"},{"id":"syntax-highlight","name":"Syntax Highlight","group":"ru.noties.markwon","description":"Add syntax highlight to Markwon markdown via Prism4j library"}]; +const artifacts = [{"id":"core","name":"Core","group":"io.noties.markwon","description":"Core Markwon artifact that includes basic markdown parsing and rendering"},{"id":"ext-latex","name":"LaTeX","group":"io.noties.markwon","description":"Extension to add LaTeX formulas to Markwon markdown"},{"id":"ext-strikethrough","name":"Strikethrough","group":"io.noties.markwon","description":"Extension to add strikethrough markup to Markwon markdown"},{"id":"ext-tables","name":"Tables","group":"io.noties.markwon","description":"Extension to add tables markup (GFM) to Markwon markdown"},{"id":"ext-tasklist","name":"Task List","group":"io.noties.markwon","description":"Extension to add task lists (GFM) to Markwon markdown"},{"id":"html","name":"HTML","group":"io.noties.markwon","description":"Provides HTML parsing functionality"},{"id":"image","name":"Image","group":"io.noties.markwon","description":"Markwon image loading module (with optional GIF and SVG support)"},{"id":"image-gif","name":"Image GIF","group":"io.noties.markwon","description":"Adds GIF media support to Markwon markdown"},{"id":"image-glide","name":"Image Glide","group":"io.noties.markwon","description":"Markwon image loading module (based on Glide library)"},{"id":"image-okhttp","name":"Image OkHttp","group":"io.noties.markwon","description":"Adds OkHttp client to retrieve images data from network"},{"id":"image-picasso","name":"Image Picasso","group":"io.noties.markwon","description":"Markwon image loading module (based on Picasso library)"},{"id":"image-svg","name":"Image SVG","group":"io.noties.markwon","description":"Adds SVG media support to Markwon markdown"},{"id":"linkify","name":"Linkify","group":"io.noties.markwon","description":"Markwon plugin to linkify text (based on Android Linkify)"},{"id":"recycler","name":"Recycler","group":"io.noties.markwon","description":"Provides RecyclerView.Adapter to display Markwon markdown"},{"id":"recycler-table","name":"Recycler Table","group":"io.noties.markwon","description":"Provides MarkwonAdapter.Entry to render TableBlocks inside Android-native TableLayout widget"},{"id":"syntax-highlight","name":"Syntax Highlight","group":"io.noties.markwon","description":"Add syntax highlight to Markwon markdown via Prism4j library"}]; export { artifacts }; diff --git a/docs/.vuepress/.artifacts.v3.js b/docs/.vuepress/.artifacts.v3.js new file mode 100644 index 00000000..2a1c3f43 --- /dev/null +++ b/docs/.vuepress/.artifacts.v3.js @@ -0,0 +1,4 @@ + +// this is a generated file, do not modify. To update it run 'collectArtifacts.js' script +const artifacts = [{"id":"core","name":"Core","group":"ru.noties.markwon","description":"Core Markwon artifact that includes basic markdown parsing and rendering"},{"id":"ext-latex","name":"LaTeX","group":"ru.noties.markwon","description":"Extension to add LaTeX formulas to Markwon markdown"},{"id":"ext-strikethrough","name":"Strikethrough","group":"ru.noties.markwon","description":"Extension to add strikethrough markup to Markwon markdown"},{"id":"ext-tables","name":"Tables","group":"ru.noties.markwon","description":"Extension to add tables markup (GFM) to Markwon markdown"},{"id":"ext-tasklist","name":"Task List","group":"ru.noties.markwon","description":"Extension to add task lists (GFM) to Markwon markdown"},{"id":"html","name":"HTML","group":"ru.noties.markwon","description":"Provides HTML parsing functionality"},{"id":"image-gif","name":"Image GIF","group":"ru.noties.markwon","description":"Adds GIF media support to Markwon markdown"},{"id":"image-okhttp","name":"Image OkHttp","group":"ru.noties.markwon","description":"Adds OkHttp client to retrieve images data from network"},{"id":"image-svg","name":"Image SVG","group":"ru.noties.markwon","description":"Adds SVG media support to Markwon markdown"},{"id":"recycler","name":"Recycler","group":"ru.noties.markwon","description":"Provides RecyclerView.Adapter to display Markwon markdown"},{"id":"recycler-table","name":"Recycler Table","group":"ru.noties.markwon","description":"Provides MarkwonAdapter.Entry to render TableBlocks inside Android-native TableLayout widget"},{"id":"syntax-highlight","name":"Syntax Highlight","group":"ru.noties.markwon","description":"Add syntax highlight to Markwon markdown via Prism4j library"}]; +export { artifacts }; diff --git a/docs/.vuepress/components/ArtifactPicker.vue b/docs/.vuepress/components/ArtifactPicker.vue index 453b1cd2..1c5a9ca8 100644 --- a/docs/.vuepress/components/ArtifactPicker.vue +++ b/docs/.vuepress/components/ArtifactPicker.vue @@ -29,7 +29,7 @@ + + \ No newline at end of file diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index 8de47eef..91f11d14 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -18,10 +18,10 @@ module.exports = { text: 'API Version', items: [ { text: 'Current (3.x.x)', link: '/' }, + { text: 'Beta (4.x.x)', link: '/docs/v4/install.md' }, { text: 'Legacy (2.x.x)', link: '/docs/v2/' } ] }, - { text: 'Sandbox', link: '/sandbox.md' }, { text: 'Github', link: 'https://github.com/noties/Markwon' } ], sidebar: { @@ -36,6 +36,27 @@ module.exports = { '/docs/v2/html.md', '/docs/v2/view.md' ], + '/docs/v4': [ + '/docs/v4/install.md', + { + title: 'Core', + collapsable: false, + children: [ + '/docs/v4/core/getting-started.md', + '/docs/v4/core/plugins.md', + '/docs/v4/core/registry.md', + '/docs/v4/core/theme.md', + '/docs/v4/core/configuration.md', + '/docs/v4/core/visitor.md', + '/docs/v4/core/spans-factory.md', + '/docs/v4/core/core-plugin.md', + '/docs/v4/core/movement-method-plugin.md', + '/docs/v4/core/render-props.md' + ] + }, + '/docs/v4/recipes.md', + '/docs/v4/migration-3-4.md' + ], '/': [ '', { diff --git a/docs/docs/v4/core/configuration.md b/docs/docs/v4/core/configuration.md new file mode 100644 index 00000000..4c4ad645 --- /dev/null +++ b/docs/docs/v4/core/configuration.md @@ -0,0 +1,173 @@ +# Configuration + +`MarkwonConfiguration` class holds common Markwon functionality. +These are _configurable_ properties: +* `AsyncDrawableLoader` (back here since ) +* `SyntaxHighlight` +* `LinkSpan.Resolver` +* `UrlProcessor` +* `ImageSizeResolver` + +:::tip +Additionally `MarkwonConfiguration` holds: +* `MarkwonTheme` +* `MarkwonSpansFactory` + +Please note that these values can be retrieved from `MarkwonConfiguration` +instance, but their _configuration_ must be done by a `Plugin` by overriding +one of the methods: +* `Plugin#configureTheme` +* `Plugin#configureSpansFactory` +::: + +## AsyncDrawableLoader + +Allows loading and displaying of images in markdown. Please note that if one is not specified +directly (or via plugin) no images will be displayed. + +```java +final Markwon markwon = Markwon.builder(context) + .usePlugin(new AbstractMarkwonPlugin() { + @Override + public void configureConfiguration(@NonNull MarkwonConfiguration.Builder builder) { + builder.asyncDrawableLoader(AsyncDrawableLoader.noOp()); + } + }) + .build(); +``` + +Currently `Markwon` provides 3 implementations for loading images: +* [own implementation](/docs/v4/image.md) with SVG, GIF, data uri and android_assets support +* [based on Picasso](/docs/v4/image-picasso.md) +* [based on Glide](/docs/v4/image-glide.md) + +## SyntaxHighlight + +```java +final Markwon markwon = Markwon.builder(this) + .usePlugin(new AbstractMarkwonPlugin() { + @Override + public void configureConfiguration(@NonNull MarkwonConfiguration.Builder builder) { + builder.syntaxHighlight(new SyntaxHighlightNoOp()); + } + }) + .build(); +``` + +:::tip +Use [syntax-highlight](/docs/v4/syntax-highlight/) to add syntax highlighting +to your application +::: + +## LinkSpan.Resolver + +React to a link click event. By default `LinkResolverDef` is used, +which tries to start an Activity given the `link` argument. If no +Activity can handle `link` `LinkResolverDef` silently ignores click event + +```java +final Markwon markwon = Markwon.builder(this) + .usePlugin(new AbstractMarkwonPlugin() { + @Override + public void configureConfiguration(@NonNull MarkwonConfiguration.Builder builder) { + builder.linkResolver(new LinkSpan.Resolver() { + @Override + public void resolve(View view, @NonNull String link) { + // react to link click here + } + }); + } + }) + .build(); +``` + +:::tip +Please note that `Markwon` will apply `LinkMovementMethod` to a resulting TextView +if there is none registered. if you wish to register own instance of a `MovementMethod` +apply it directly to a TextView or use [MovementMethodPlugin](/docs/v4/core/movement-method-plugin.md) +::: + +## UrlProcessor + +Process URLs in your markdown (for links and images). If not provided explicitly, +default **no-op** implementation will be used, which does not modify URLs (keeping them as-is). + +`Markwon` provides 2 implementations of `UrlProcessor`: +* `UrlProcessorRelativeToAbsolute` +* `UrlProcessorAndroidAssets` + +### UrlProcessorRelativeToAbsolute + +`UrlProcessorRelativeToAbsolute` can be used to make relative URL absolute. For example if an image is +defined like this: `![img](./art/image.JPG)` and `UrlProcessorRelativeToAbsolute` +is created with `https://github.com/noties/Markwon/raw/master/` as the base: +`new UrlProcessorRelativeToAbsolute("https://github.com/noties/Markwon/raw/master/")`, +then final image will have `https://github.com/noties/Markwon/raw/master/art/image.JPG` +as the destination. + +### UrlProcessorAndroidAssets + +`UrlProcessorAndroidAssets` can be used to make processed links to point to Android assets folder. +So an image: `![img](./art/image.JPG)` will have `file:///android_asset/art/image.JPG` as the +destination. + +:::tip +Please note that `UrlProcessorAndroidAssets` will process only URLs that have no `scheme` information, +so a `./art/image.png` will become `file:///android_asset/art/image.JPG` whilst `https://so.me/where.png` +will be kept as-is. +::: + +## ImageSizeResolver + +`ImageSizeResolver` controls the size of an image to be displayed. Currently it +handles only HTML images (specified via `img` tag). + +```java +final Markwon markwon = Markwon.builder(this) + .usePlugin(new AbstractMarkwonPlugin() { + @Override + public void configureConfiguration(@NonNull MarkwonConfiguration.Builder builder) { + builder.imageSizeResolver(new ImageSizeResolver() { + @NonNull + @Override + public Rect resolveImageSize( + @Nullable ImageSize imageSize, + @NonNull Rect imageBounds, + int canvasWidth, + float textSize) { + return null; + } + }); + } + }) + .build(); +``` + +If not provided explicitly, default `ImageSizeResolverDef` implementation will be used. +It handles 3 dimension units: +* `%` (percent, relative to Canvas width) +* `em` (relative to text size) +* `px` (absolute size, every dimension that is not `%` or `em` is considered to be _absolute_) + +```html + + + +``` + +`ImageSizeResolverDef` keeps the ratio of original image if one of the dimensions is missing. + +:::warning Height% +There is no support for `%` units for `height` dimension. This is due to the fact that +height of an TextView in which markdown is displayed is non-stable and changes with time +(for example when image is loaded and applied to a TextView it will _increase_ TextView's height), +so we will have no point-of-reference from which to _calculate_ image height. +::: + +:::tip +`ImageSizeResolverDef` also takes care for an image to **not** exceed +canvas width. If an image has greater width than a TextView Canvas, then +image will be _scaled-down_ to fit the canvas. Please note that this rule +applies only if image has no absolute sizes (for example width is specified +in pixels). +::: \ No newline at end of file diff --git a/docs/docs/v4/core/core-plugin.md b/docs/docs/v4/core/core-plugin.md new file mode 100644 index 00000000..750e3c59 --- /dev/null +++ b/docs/docs/v4/core/core-plugin.md @@ -0,0 +1,141 @@ +# Core plugin + +Since with introduction of _plugins_, Markwon +**core** functionality was moved to a dedicated plugin. + +```java +CorePlugin.create(); +``` + +## Node visitors + +`CorePlugin` registers these `commonmark-java` node visitors: +* `Text` +* `StrongEmphasis` +* `Emphasis` +* `BlockQuote` +* `Code` +* `Image` +* `FencedCodeBlock` +* `IndentedCodeBlock` +* `BulletList` +* `OrderedList` +* `ListItem` +* `ThematicBreak` +* `Heading` +* `SoftLineBreak` +* `HardLineBreak` +* `Paragraph` +* `Link` + +## Span factories + +`CorePlugin` adds these `SpanFactory`s: +* `StrongEmphasis` +* `Emphasis` +* `BlockQuote` +* `Code` +* `FencedCodeBlock` +* `IndentedCodeBlock` +* `ListItem` +* `Heading` +* `Link` +* `ThematicBreak` + + +:::tip +By default `CorePlugin` does not register a `Paragraph` `SpanFactory` but +this can be done in your custom plugin: + +```java +Markwon.builder(context) + .usePlugin(new AbstractMarkwonPlugin() { + @Override + public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) { + builder.setFactory(Paragraph.class, (configuration, props) -> + new ForegroundColorSpan(Color.RED)); + } + }) +``` +::: + +## Props +These props are exported by `CorePlugin` and can be found in `CoreProps`: +* `Prop LIST_ITEM_TYPE` (BULLET | ORDERED) +* `Prop BULLET_LIST_ITEM_LEVEL` +* `Prop ORDERED_LIST_ITEM_NUMBER` +* `Prop HEADING_LEVEL` +* `Prop LINK_DESTINATION` +* `Prop PARAGRAPH_IS_IN_TIGHT_LIST` + +:::warning List item type +Before `Markwon` had 2 distinct lists (bullet and ordered). +Since a single `SpanFactory` is used, which internally checks +for `Prop LIST_ITEM_TYPE`. +Beware of this if you would like to override only one of the list types. This is +done to correspond to `commonmark-java` implementation. +::: + +More information about props can be found [here](/docs/v4/core/render-props.md) + +--- + +:::tip Soft line break +Since Markwon core does not give an option to +insert a new line when there is a soft line break in markdown. Instead a +custom plugin can be used: + +```java +final Markwon markwon = Markwon.builder(this) + .usePlugin(new AbstractMarkwonPlugin() { + @Override + public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) { + builder.on(SoftLineBreak.class, (visitor, softLineBreak) -> + visitor.forceNewLine()); + } + }) + .build(); +``` +::: + +:::warning +Please note that `CorePlugin` will implicitly set a `LinkMovementMethod` on a TextView +if one is not present. If you wish to customize a MovementMethod that is used, apply +one manually to a TextView (before applying markdown) or use the [MovementMethodPlugin](/docs/v4/core/movement-method-plugin.md) +which accepts a MovementMethod as an argument. +::: + +## OnTextAddedListener + +Since `4.0.0` `CorePlugin` provides ability to receive text-added event. This can +be useful in order to process raw text (for example to [linkify](/docs/v4/linkify.md) it): + +```java +final Markwon markwon = Markwon.builder(context) + .usePlugin(new AbstractMarkwonPlugin() { + @Override + public void configure(@NonNull Registry registry) { + registry.require(CorePlugin.class, new Action() { + @Override + public void apply(@NonNull CorePlugin corePlugin) { + corePlugin.addOnTextAddedListener(new CorePlugin.OnTextAddedListener() { + @Override + public void onTextAdded(@NonNull MarkwonVisitor visitor, @NonNull String text, int start) { + + // NB text is already added and you are __strongly__ adviced not to + // modify visitor here, but only add spans + // + // this will make all text BLUE + visitor.builder().setSpan( + new ForegroundColorSpan(Color.BLUE), + start, + visitor.length() + ); + } + }); + } + }); + } + }) + .build(); +``` \ No newline at end of file diff --git a/docs/docs/v4/core/getting-started.md b/docs/docs/v4/core/getting-started.md new file mode 100644 index 00000000..91848f71 --- /dev/null +++ b/docs/docs/v4/core/getting-started.md @@ -0,0 +1,52 @@ +# Getting started + +:::tip Installation +Please follow [installation](/docs/v4/install.md) instructions +to learn how to add `Markwon` to your project +::: + +## Quick one + +This is the most simple way to set markdown to a `TextView` or any of its siblings: + +```java +// obtain an instance of Markwon +final Markwon markwon = Markwon.create(context); + +// set markdown +markwon.setMarkdown(textView, "**Hello there!**"); +``` + +The most simple way to obtain markdown to be applied _somewhere_ else: + +```java +// obtain an instance of Markwon +final Markwon markwon = Markwon.create(context); + +// parse markdown and create styled text +final Spanned markdown = markwon.toMarkdown("**Hello there!**"); + +// use it +Toast.makeText(context, markdown, Toast.LENGTH_LONG).show(); +``` + +## Longer one + +With explicit `parse` and `render` methods: + +```java +// obtain an instance of Markwon +final Markwon markwon = Markwon.create(context); + +// parse markdown to commonmark-java Node +final Node node = markwon.parse("Are **you** still there?"); + +// create styled text from parsed Node +final Spanned markdown = markwon.render(node); + +// use it on a TextView +markwon.setParsedMarkdown(textView, markdown); + +// or a Toast +Toast.makeText(context, markdown, Toast.LENGTH_LONG).show(); +``` diff --git a/docs/docs/v4/core/movement-method-plugin.md b/docs/docs/v4/core/movement-method-plugin.md new file mode 100644 index 00000000..6bb50c87 --- /dev/null +++ b/docs/docs/v4/core/movement-method-plugin.md @@ -0,0 +1,17 @@ +# Movement method plugin + +`MovementMethodPlugin` can be used to apply a `MovementMethod` to a TextView +(important if you have links inside your markdown). By default `CorePlugin` +will set a `LinkMovementMethod` on a TextView if one is missing. If you have +specific needs for a `MovementMethod` and `LinkMovementMethod` doesn't answer +your needs use `MovementMethodPlugin`: + +```java +Markwon.builder(context) + .usePlugin(MovementMethodPlugin.create(ScrollingMovementMethod.getInstance())) +``` + +:::tip +If you are having trouble with system `LinkMovementMethod` as an alternative +[BetterLinkMovementMethod](https://github.com/saket/Better-Link-Movement-Method) library can be used. +::: diff --git a/docs/docs/v4/core/plugins.md b/docs/docs/v4/core/plugins.md new file mode 100644 index 00000000..c44954b3 --- /dev/null +++ b/docs/docs/v4/core/plugins.md @@ -0,0 +1,361 @@ +# Plugins + +Since `MarkwonPlugin` takes the key role in +processing and rendering markdown. Even **core** functionaly is abstracted +into a `CorePlugin`. So it's still possible to use `Markwon` with a completely +own set of plugins. + +To register a plugin `Markwon.Builder` must be used: + +```java +Markwon.builder(context) + // @since 4.0.0 there is no need to register CorePlugin, as it's registered automatically +// .usePlugin(CorePlugin.create()) + .usePlugin(MyPlugin.create()) + .build(); +``` + +All the process of transforming _raw_ markdown into a styled text (Spanned) +will go through plugins. A plugin can: + +* [configure plugin registry](#registry) +* [configure commonmark-java `Parser`](#parser) +* [configure `MarkwonTheme`](#markwontheme) +* [configure `AsyncDrawableLoader` (used to display images in markdown)](#images) +* [configure `MarkwonConfiguration`](#configuration) +* [configure `MarkwonVisitor` (extensible commonmark-java Node visitor)](#visitor) +* [configure `MarkwonSpansFactory` (factory to hold spans information for each Node)](#spans-factory) + +--- + +* [process raw input markdown before parsing it](#process-markdown) +* [inspect/modify commonmark-java Node after it's been parsed, but before rendering](#inspect-modify-node) +* [inspect commonmark-java Node after it's been rendered](#inspect-node-after-render) +* [prepare TextView to display markdown _before_ markdown is applied to a TextView](#prepare-textview) +* [post-process TextView _after_ markdown was applied](#textview-after-markdown-applied) + +:::tip +if you need to override only few methods of `MarkwonPlugin` (since it is an interface), +`AbstractMarkwonPlugin` can be used. +::: + +## Registry + +Registry is a special step to pre-configure all registered plugins. It is also +used to determine the order of plugins inside `Markwon` instance. + +```java +final Markwon markwon = Markwon.builder(context) + .usePlugin(new AbstractMarkwonPlugin() { + @Override + public void configure(@NonNull Registry registry) { + + final CorePlugin corePlugin = registry.require(CorePlugin.class); + + // or + registry.require(CorePlugin.class, new Action() { + @Override + public void apply(@NonNull CorePlugin corePlugin) { + + } + }); + } + }) + .build(); +``` + +More information about registry can be found [here](/docs/v4/core/registry.md) + +## Parser + +For example, let's register a new commonmark-java Parser extension: + +```java +final Markwon markwon = Markwon.builder(context) + .usePlugin(new AbstractMarkwonPlugin() { + @Override + public void configureParser(@NonNull Parser.Builder builder) { + // no need to call `super.configureParser(builder)` + builder.extensions(Collections.singleton(StrikethroughExtension.create())); + } + }) + .build(); +``` + +There are no limitations on what to do with commonmark-java Parser. For more info +_what_ can be done please refer to . + +## MarkwonTheme + +Starting `MarkwonTheme` represents _core_ theme. Aka theme for +things core module knows of. For example it doesn't know anything about `strikethrough` +or `tables` (as they belong to different modules). + +```java +final Markwon markwon = Markwon.builder(context) + .usePlugin(new AbstractMarkwonPlugin() { + @Override + public void configureTheme(@NonNull MarkwonTheme.Builder builder) { + builder + .codeTextColor(Color.BLACK) + .codeBackgroundColor(Color.GREEN); + } + }) + .build(); +``` + +:::tip +`CorePlugin` has special handling - it will be added automatically +when `Markwon.builder(Context)` method is used. If you wish to create +Markwon instance _without_ CorePlugin registered - +use `Markwon.builderNoCore(Context)` method instead +::: + +More information about `MarkwonTheme` can be found [here](/docs/v4/core/theme.md). + + +## Configuration + +`MarkwonConfiguration` is a set of common tools that are used by different parts +of `Markwon`. It allows configurations of these: + +* `AsyncDrawableLoader` (image loading) +* `SyntaxHighlight` (highlighting code blocks) +* `LinkResolver` (opens links in markdown) +* `UrlProcessor` (process URLs in markdown for both links and images) +* `ImageSizeResolver` (resolve image sizes, like `fit-to-canvas`, etc) + +```java +final Markwon markwon = Markwon.builder(context) + .usePlugin(new AbstractMarkwonPlugin() { + @Override + public void configureConfiguration(@NonNull MarkwonConfiguration.Builder builder) { + builder.linkResolver(new LinkResolverDef()); + } + }) + .build(); +``` + +More information about `MarkwonConfiguration` can be found [here](/docs/v4/core/configuration.md) + + +## Visitor + +`MarkwonVisitor` is commonmark-java Visitor that allows +configuration of how each Node is visited. There is no longer need to create +own subclass of Visitor and override required methods (like in `2.x.x` versions). +`MarkwonVisitor` also allows registration of Nodes, that `core` module knows +nothing about (instead of relying on `visit(CustomNode)` method)). + +For example, let's add `strikethrough` Node visitor: + +```java +final Markwon markwon = Markwon.builder(context) + .usePlugin(new AbstractMarkwonPlugin() { + @Override + public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) { + // please note that strike-through parser extension must be registered + // in order to receive such callback + builder + .on(Strikethrough.class, new MarkwonVisitor.NodeVisitor() { + @Override + public void visit(@NonNull MarkwonVisitor visitor, @NonNull Strikethrough strikethrough) { + final int length = visitor.length(); + visitor.visitChildren(strikethrough); + visitor.setSpansForNodeOptional(strikethrough, length); + } + }); + } + }) + .build(); +``` + +:::tip +`MarkwonVisitor` also allows _overriding_ already registered nodes. For example, +you can disable `Heading` Node rendering: + +```java +builder.on(Heading.class, null); +``` +::: + +More information about `MarkwonVisitor` can be found [here](/docs/v4/core/visitor.md) + + +## Spans Factory + +`MarkwonSpansFactory` is an abstract factory (factory that produces other factories) +for spans that `Markwon` uses. It controls what spans to use for certain Nodes. + +```java +final Markwon markwon = Markwon.builder(context) + .usePlugin(new AbstractMarkwonPlugin() { + @Override + public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) { + // override emphasis factory to make all emphasis nodes underlined + builder.setFactory(Emphasis.class, new SpanFactory() { + @Override + public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) { + return new UnderlineSpan(); + } + }); + } + }) + .build(); +``` + +:::tip +`SpanFactory` allows to return an _array_ of spans to apply multiple spans +for a Node: + +```java +@Override +public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) { + // make underlined and set text color to red + return new Object[]{ + new UnderlineSpan(), + new ForegroundColorSpan(Color.RED) + }; +} +``` +::: + +More information about spans factory can be found [here](/docs/v4/core/spans-factory.md) + + +## Process markdown + +A plugin can be used to _pre-process_ input markdown (this will be called before _parsing_): + +```java +final Markwon markwon = Markwon.builder(context) + .usePlugin(new AbstractMarkwonPlugin() { + @NonNull + @Override + public String processMarkdown(@NonNull String markdown) { + return markdown.replaceAll("foo", "bar"); + } + }) + .build(); +``` + +## Inspect/modify Node + +A plugin can inspect/modify commonmark-java Node _before_ it's being rendered. + +```java +final Markwon markwon = Markwon.builder(context) + .usePlugin(new AbstractMarkwonPlugin() { + @Override + public void beforeRender(@NonNull Node node) { + + // for example inspect it with custom visitor + node.accept(new MyVisitor()); + + // or modify (you know what you are doing, right?) + node.appendChild(new Text("Appended")); + } + }) + .build(); +``` + +## Inspect Node after render + +A plugin can inspect commonmark-java Node after it's been rendered. +Modifying Node at this point makes not much sense (it's already been +rendered and all modifications won't change anything). But this method can be used, +for example, to clean-up some internal state (after rendering). Generally +speaking, a plugin must be stateless, but if it cannot, then this method is +the best place to clean-up. + +```java +final Markwon markwon = Markwon.builder(context) + .usePlugin(new AbstractMarkwonPlugin() { + @Override + public void afterRender(@NonNull Node node, @NonNull MarkwonVisitor visitor) { + cleanUp(); + } + }) + .build(); +``` + +## Prepare TextView + +A plugin can _prepare_ a TextView before markdown is applied. For example `images` +unschedules all previously scheduled `AsyncDrawableSpans` (if any) here. This way +when new markdown (and set of Spannables) arrives, previous set won't be kept in +memory and could be garbage-collected. + +```java +final Markwon markwon = Markwon.builder(context) + .usePlugin(new AbstractMarkwonPlugin() { + @Override + public void beforeSetText(@NonNull TextView textView, @NonNull Spanned markdown) { + // clean-up previous + AsyncDrawableScheduler.unschedule(textView); + } + }) + .build(); +``` + +## TextView after markdown applied + +A plugin will receive a callback _after_ markdown is applied to a TextView. +For example `images` uses this callback to schedule new set of Spannables. + +```java +final Markwon markwon = Markwon.builder(context) + .usePlugin(new AbstractMarkwonPlugin() { + @Override + public void afterSetText(@NonNull TextView textView) { + AsyncDrawableScheduler.schedule(textView); + } + }) + .build(); +``` + +:::tip +Please note that unlike `#beforeSetText`, `#afterSetText` won't receive +`Spanned` markdown. This happens because at this point spans must be +queried directly from a TextView. +::: + +## What happens underneath + +Here is what happens inside `Markwon` when `setMarkdown` method is called: + +```java +final Markwon markwon = Markwon.create(context); + +// warning: pseudo-code + +// 0. each plugin will be called to _pre-process_ raw input markdown +rawInput = plugins.reduce(rawInput, (input, plugin) -> plugin.processMarkdown(input)); + +// 1. after input is processed it's being parsed to a Node +node = parser.parse(rawInput); + +// 2. each plugin will be able to inspect or manipulate resulting Node +// before rendering +plugins.forEach(plugin -> plugin.beforeRender(node)); + +// 3. node is being visited by a visitor +node.accept(visitor); + +// 4. each plugin will be called after node is being visited (aka rendered) +plugins.forEach(plugin -> plugin.afterRender(node, visitor)); + +// 5. styled markdown ready at this point +final Spanned markdown = visitor.markdown(); + +// NB, points 6-8 are applied **only** if markdown is set to a TextView + +// 6. each plugin will be called before styled markdown is applied to a TextView +plugins.forEach(plugin -> plugin.beforeSetText(textView, markdown)); + +// 7. markdown is applied to a TextView +textView.setText(markdown); + +// 8. each plugin will be called after markdown is applied to a TextView +plugins.forEach(plugin -> plugin.afterSetText(textView)); +``` \ No newline at end of file diff --git a/docs/docs/v4/core/registry.md b/docs/docs/v4/core/registry.md new file mode 100644 index 00000000..1161600c --- /dev/null +++ b/docs/docs/v4/core/registry.md @@ -0,0 +1,97 @@ +# Registry + +`Registry` allows to pre-configure other plugins and/or declare a dependency on a plugin, +which also will modify internal order of plugins inside a `Markwon` instance. + +For example, you have a configurable plugin: + +```java +public class MyPlugin extends AbstractMarkwonPlugin { + + private boolean enabled; + + public boolean enabled() { + return enabled; + } + + @NonNull + public MyPlugin enabled(boolean enabled) { + this.enabled = enabled; + return this; + } + + {...} +} +``` + +and other plugin that needs to access `MyPlugin` or modify/configure it: + +```java +public class MyOtherPlugin extends AbstractMarkwonPlugin { + @Override + public void configure(@NonNull Registry registry) { + registry.require(MyPlugin.class, new Action() { + @Override + public void apply(@NonNull MyPlugin myPlugin) { + myPlugin.enabled(false); + } + }); + } +} +``` + +```java +final Markwon markwon = Markwon.builder(context) + .usePlugin(new MyOtherPlugin()) + .usePlugin(new MyPlugin()) + .build(); +``` + +_Internal_ plugins order (in this case) will be: +* `CorePlugin` (added automatically and always the first one) +* `MyPlugin` (was required by `MyOtherPlugin`) +* `MyOtherPlugin` + +:::tip +There is no need to _require_ `CorePlugin` as it will be the first one inside +`Markwon` instance. +::: + +The order matters if you want to _override_ some plugin. For example, `CoolPlugin` +adds a `SpanFactory` for a `Cool` markdown node. Other `NotCoolPlugin` wants to +use a different `SpanFactory`, then: + +```java +final Markwon markwon = Markwon.builder(context) + .usePlugin(CoolPlugin.create()) + .usePlugin(new NotCoolPlugin() { + + @Override + public void configure(@NonNull MarkwonPlugin.Registry registry) { + registry.require(CoolPlugin.class); + } + + @Override + public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) { + builder.setFactory(Cool.class, new NotCoolSpanFactory()); + } + }) + .build(); +``` + +--- + +All `require` calls to the `Registry` will also validate at runtime that +_required_ plugins are registered. + +```java +final Markwon markwon = Markwon.builder(context) + .usePlugin(new AbstractMarkwonPlugin() { + @Override + public void configure(@NonNull Registry registry) { + // will throw an exception if `NotPresentPlugin` is not present + registry.require(NotPresentPlugin.class); + } + }) + .build(); +``` \ No newline at end of file diff --git a/docs/docs/v4/core/render-props.md b/docs/docs/v4/core/render-props.md new file mode 100644 index 00000000..9dd18004 --- /dev/null +++ b/docs/docs/v4/core/render-props.md @@ -0,0 +1,75 @@ +# RenderProps + +`RenderProps` encapsulates passing arguments from a node visitor to a node renderer. +Without hardcoding arguments into an API method calls. + +`RenderProps` is the state collection for `Props` that are set by a node visitor and +retrieved by a node renderer. + +```java +public class Prop { + + @NonNull + public static Prop of(@NonNull String name) { + return new Prop<>(name); + } + + /* ... */ +} +``` + +For example `CorePlugin` defines a _Heading level_ prop (inside `CoreProps` class): + +```java +public static final Prop HEADING_LEVEL = Prop.of("heading-level"); +``` + +Then CorePlugin registers a `Heading` node visitor and applies heading value: + +```java +@Override +public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) { + builder.on(Heading.class, new MarkwonVisitor.NodeVisitor() { + @Override + public void visit(@NonNull MarkwonVisitor visitor, @NonNull Heading heading) { + + /* Heading node handling logic */ + + // set heading level + CoreProps.HEADING_LEVEL.set(visitor.renderProps(), heading.getLevel()); + + // a helper method to apply span(s) for a node + // (internally obtains a SpanFactory for Heading or silently ignores + // this call if no factory for a Heading is registered) + visitor.setSpansForNodeOptional(heading, start); + + /* Heading node handling logic */ + } + }); +} +``` + +And finally `HeadingSpanFactory` (which is also registered by `CorePlugin`): + +```java +public class HeadingSpanFactory implements SpanFactory { + @Nullable + @Override + public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) { + return new HeadingSpan( + configuration.theme(), + CoreProps.HEADING_LEVEL.require(props) + ); + } +} +``` + +--- + +`Prop` has these methods: + +* `@Nullable T get(RenderProps)` - returns value stored in RenderProps or `null` if none is present +* `@NonNull T get(RenderProps, @NonNull T defValue)` - returns value stored in RenderProps or default value (this method always return non-null value) +* `@NonNull T require(RenderProps)` - returns value stored in RenderProps or _throws an exception_ if none is present +* `void set(RenderProps, @Nullable T value)` - updates value stored in RenderProps, passing `null` as value is the same as calling `clear` +* `void clear(RenderProps)` - clears value stored in RenderProps diff --git a/docs/docs/v4/core/spans-factory.md b/docs/docs/v4/core/spans-factory.md new file mode 100644 index 00000000..9567a788 --- /dev/null +++ b/docs/docs/v4/core/spans-factory.md @@ -0,0 +1,103 @@ +# Spans Factory + +Starting with `MarkwonSpansFactory` controls what spans are displayed +for markdown nodes. + +```java +Markwon.builder(context) + .usePlugin(new AbstractMarkwonPlugin() { + @Override + public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) { + // passing null as second argument will remove previously added + // factory for the Link node + builder.setFactory(Link.class, null); + } + }); +``` + +## SpanFactory + +In order to create a _generic_ interface for all possible Nodes, a `SpanFactory` +was added: + +```java +builder.setFactory(Link.class, new SpanFactory() { + @Nullable + @Override + public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) { + return null; + } +}); +``` + +All possible arguments are passed via [RenderProps](/docs/v4/core/render-props.md): + +```java +builder.setFactory(Link.class, new SpanFactory() { + @Override + public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) { + final String href = CoreProps.LINK_DESTINATION.require(props); + return new LinkSpan(configuration.theme(), href, configuration.linkResolver()); + } +}); +``` + +`SpanFactory` allows returning `null` for a certain span (no span will be applied). +Or an array of spans (you _can_ go deeper): + +```java +builder.setFactory(Link.class, new SpanFactory() { + @Override + public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) { + return new Object[]{ + new LinkSpan( + configuration.theme(), + CoreProps.LINK_DESTINATION.require(props), + configuration.linkResolver()), + new ForegroundColorSpan(Color.RED) + }; + } +}); +``` + +--- + +Since you can _add_ multiple `SpanFactory` for a single node: + +```java +final Markwon markwon = Markwon.builder(context) + .usePlugin(new AbstractMarkwonPlugin() { + @Override + public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) { + // this factory will be used _along_ with all other factories for specified node + builder.addFactory(Code.class, new SpanFactory() { + @Override + public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) { + return new ForegroundColorSpan(Color.GREEN); + } + }); + } + }) + .build(); +``` + +--- + +If you wish to inspect existing factory you can use: +* `builder#getFactory()` -> returns registered factory or `null` +* `builder#requireFactory()` -> returns registered factory or throws + +```java +final Markwon markwon = Markwon.builder(context) + .usePlugin(new AbstractMarkwonPlugin() { + @Override + public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) { + final SpanFactory codeFactory = builder.requireFactory(Code.class); + final SpanFactory linkFactory = builder.getFactory(Link.class); + if (linkFactory != null) { + {...} + } + } + }) + .build(); +``` \ No newline at end of file diff --git a/docs/docs/v4/core/theme.md b/docs/docs/v4/core/theme.md new file mode 100644 index 00000000..672babc6 --- /dev/null +++ b/docs/docs/v4/core/theme.md @@ -0,0 +1,187 @@ +# Theme + +Here is the list of properties that can be configured via `MarkwonTheme.Builder` class. + +:::tip +Starting with there is no need to manually construct a `MarkwonTheme`. +Instead a `Plugin` should be used: +```java +final Markwon markwon = Markwon.builder(context) + .usePlugin(new AbstractMarkwonPlugin() { + @Override + public void configureTheme(@NonNull MarkwonTheme.Builder builder) { + builder + .codeTextColor(Color.BLACK) + .codeBackgroundColor(Color.GREEN); + } + }) + .build(); +``` +::: + +## Link color + +Controls the color of a [link](#) + + + +* `TextPaint#linkColor` will be used to determine linkColor of a context + +## Block margin + +Starting margin before text content for the: +* lists +* blockquotes +* task lists + + + +## Block quote + +Customizations for the `blockquote` stripe + +> Quote + +### Stripe width + +Width of a blockquote stripe + + + +### Stripe color + +Color of a blockquote stripe + + + +## List + +### List item color + +Controls the color of a list item. For ordered list: leading number, +for unordered list: bullet. + +* UL +1. OL + + + +### Bullet item stroke width + +Border width of a bullet list item (level 2) + +* First +* * Second +* * * Third + + + +### Bullet width + +The width of the bullet item + +* First + * Second + * Third + + + +## Code + +### Inline code text color + +The color of the `code` content + + + +### Inline code background color + +The color of `background` of a code content + + + +### Block code text color + +``` +The color of code block text +``` + + + +### Block code background color + +``` +The color of background of code block text +``` + + + +### Block code leading margin + +Leading margin for the block code content + + + +### Code typeface + +Typeface of code content + + + +### Block code typeface + +Typeface of block code content + + + +### Code text size + +Text size of code content + + + +### Block code text size + +Text size of block code content + + + +## Heading + +### Break height + +The height of a brake under H1 & H2 + + + +### Break color + +The color of a brake under H1 & H2 + + + +### Typeface + +The typeface of heading elements + + + +### Text size + +Array of heading text sizes _ratio_ that is applied to text size + + + +## Thematic break + +### Color + +Color of a thematic break + + + +### Height + +Height of a thematic break + + diff --git a/docs/docs/v4/core/visitor.md b/docs/docs/v4/core/visitor.md new file mode 100644 index 00000000..d03ff848 --- /dev/null +++ b/docs/docs/v4/core/visitor.md @@ -0,0 +1,73 @@ +# Visitor + +Starting with _visiting_ of parsed markdown +nodes does not require creating own instance of commonmark-java `Visitor`, +instead a composable/configurable `MarkwonVisitor` is used. + +## Visitor.Builder +There is no need to create own instance of `MarkwonVisitor.Builder` as +it is done by `Markwon` itself. One still can configure it as one wishes: + +```java +final Markwon markwon = Markwon.builder(contex) + .usePlugin(new AbstractMarkwonPlugin() { + @Override + public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) { + builder.on(SoftLineBreak.class, new MarkwonVisitor.NodeVisitor() { + @Override + public void visit(@NonNull MarkwonVisitor visitor, @NonNull SoftLineBreak softLineBreak) { + visitor.forceNewLine(); + } + }); + } + }); +``` + +--- + +`MarkwonVisitor` encapsulates most of the functionality of rendering parsed markdown. + +It holds rendering configuration: +* `MarkwonVisitor#configuration` - getter for current [MarkwonConfiguration](/docs/v4/core/configuration.md) +* `MarkwonVisitor#renderProps` - getter for current [RenderProps](/docs/v4/core/render-props.md) +* `MarkwonVisitor#builder` - getter for current `SpannableBuilder` + +It contains also a number of utility functions: +* `visitChildren(Node)` - will visit all children of supplied Node +* `hasNext(Node)` - utility function to check if supplied Node has a Node after it (useful for white-space management, so there should be no blank new line after last BlockNode) +* `ensureNewLine` - will insert a new line at current `SpannableBuilder` position only if current (last) character is not a new-line +* `forceNewLine` - will insert a new line character without any condition checking +* `length` - helper function to call `visitor.builder().length()`, returns current length of `SpannableBuilder` +* `clear` - will clear state for `RenderProps` and `SpannableBuilder`, this is done by `Markwon` automatically after each render call + +And some utility functions to control the spans: +* `setSpans(int start, Object spans)` - will apply supplied `spans` on `SpannableBuilder` starting at `start` position and ending at `SpannableBuilder#length`. `spans` can be `null` (no spans will be applied) or an array of spans (each span of this array will be applied) +* `setSpansForNodeOptional(N node, int start)` - helper method to set spans for specified `node` (internally obtains `SpanFactory` for that node and uses it to apply spans) +* `setSpansForNode(N node, int start)` - almost the same as `setSpansForNodeOptional` but instead of silently ignoring call if none `SpanFactory` is registered, this method will throw an exception. + +```java +@Override +public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) { + builder.on(Heading.class, new MarkwonVisitor.NodeVisitor() { + @Override + public void visit(@NonNull MarkwonVisitor visitor, @NonNull Heading heading) { + + // or just `visitor.length()` + final int start = visitor.builder().length(); + + visitor.visitChildren(heading); + + // or just `visitor.setSpansForNodeOptional(heading, start)` + final SpanFactory factory = visitor.configuration().spansFactory().get(heading.getClass()); + if (factory != null) { + visitor.setSpans(start, factory.getSpans(visitor.configuration(), visitor.renderProps())); + } + + if (visitor.hasNext(heading)) { + visitor.ensureNewLine(); + visitor.forceNewLine(); + } + } + }); +} +``` \ No newline at end of file diff --git a/docs/docs/v4/install.md b/docs/docs/v4/install.md new file mode 100644 index 00000000..c6de0e5a --- /dev/null +++ b/docs/docs/v4/install.md @@ -0,0 +1,34 @@ +--- +prev: false +next: /docs/v4/core/getting-started.md +--- + +# Installation + +![stable](https://img.shields.io/maven-central/v/io.noties.markwon/core.svg?label=stable) +![snapshot](https://img.shields.io/nexus/s/https/oss.sonatype.org/io.noties.markwon/core.svg?label=snapshot) + + + +## Snapshot + +In order to use latest `SNAPSHOT` version add snapshot repository +to your root project's `build.gradle` file: + +```groovy +allprojects { + repositories { + jcenter() + google() + // this one 👇 + maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' } // 👈 this one + // this one 👆 + } +} +``` + +:::tip Info +All official artifacts share the same version number and all +are uploaded to **release** and **snapshot** repositories +::: + diff --git a/docs/docs/v4/migration-3-4.md b/docs/docs/v4/migration-3-4.md new file mode 100644 index 00000000..5537e1e2 --- /dev/null +++ b/docs/docs/v4/migration-3-4.md @@ -0,0 +1,3 @@ +# Migration 3.x.x -> 4.x.x + +todo \ No newline at end of file diff --git a/docs/docs/v4/recipes.md b/docs/docs/v4/recipes.md new file mode 100644 index 00000000..7fc70175 --- /dev/null +++ b/docs/docs/v4/recipes.md @@ -0,0 +1,3 @@ +# Recipes + +todo \ No newline at end of file diff --git a/markwon-image-gif/build.gradle b/markwon-image-gif/build.gradle deleted file mode 100644 index bcb3fa77..00000000 --- a/markwon-image-gif/build.gradle +++ /dev/null @@ -1,25 +0,0 @@ -apply plugin: 'com.android.library' - -android { - - compileSdkVersion config['compile-sdk'] - buildToolsVersion config['build-tools'] - - defaultConfig { - minSdkVersion config['min-sdk'] - targetSdkVersion config['target-sdk'] - versionCode 1 - versionName version - } -} - -dependencies { - - api project(':markwon-core') - - deps.with { - api it['android-gif'] - } -} - -registerArtifact(this) \ No newline at end of file diff --git a/markwon-image-gif/gradle.properties b/markwon-image-gif/gradle.properties deleted file mode 100644 index 2630a2f3..00000000 --- a/markwon-image-gif/gradle.properties +++ /dev/null @@ -1,4 +0,0 @@ -POM_NAME=Image GIF -POM_ARTIFACT_ID=image-gif -POM_DESCRIPTION=Adds GIF media support to Markwon markdown -POM_PACKAGING=aar \ No newline at end of file diff --git a/markwon-image-gif/src/main/AndroidManifest.xml b/markwon-image-gif/src/main/AndroidManifest.xml deleted file mode 100644 index 649a9a70..00000000 --- a/markwon-image-gif/src/main/AndroidManifest.xml +++ /dev/null @@ -1 +0,0 @@ - diff --git a/markwon-image-gif/src/main/java/ru/noties/markwon/image/gif/GifMediaDecoder.java b/markwon-image-gif/src/main/java/ru/noties/markwon/image/gif/GifMediaDecoder.java deleted file mode 100644 index 7c06e13a..00000000 --- a/markwon-image-gif/src/main/java/ru/noties/markwon/image/gif/GifMediaDecoder.java +++ /dev/null @@ -1,81 +0,0 @@ -package ru.noties.markwon.image.gif; - -import android.graphics.drawable.Drawable; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; - -import pl.droidsonroids.gif.GifDrawable; -import ru.noties.markwon.image.DrawableUtils; - -/** - * @since 1.1.0 - */ -@SuppressWarnings("WeakerAccess") -public class GifMediaDecoder extends MediaDecoder { - - public static final String CONTENT_TYPE = "image/gif"; - - @NonNull - public static GifMediaDecoder create(boolean autoPlayGif) { - return new GifMediaDecoder(autoPlayGif); - } - - private final boolean autoPlayGif; - - protected GifMediaDecoder(boolean autoPlayGif) { - this.autoPlayGif = autoPlayGif; - } - - @Nullable - @Override - public Drawable decode(@NonNull InputStream inputStream) { - - Drawable out = null; - - final byte[] bytes = readBytes(inputStream); - if (bytes != null) { - try { - out = newGifDrawable(bytes); - DrawableUtils.applyIntrinsicBounds(out); - - if (!autoPlayGif) { - ((GifDrawable) out).pause(); - } - } catch (IOException e) { - e.printStackTrace(); - } - } - - return out; - } - - @NonNull - protected Drawable newGifDrawable(@NonNull byte[] bytes) throws IOException { - return new GifDrawable(bytes); - } - - @Nullable - protected static byte[] readBytes(@NonNull InputStream stream) { - - byte[] out = null; - - try { - final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - final int length = 1024 * 8; - final byte[] buffer = new byte[length]; - int read; - while ((read = stream.read(buffer, 0, length)) != -1) { - outputStream.write(buffer, 0, read); - } - out = outputStream.toByteArray(); - } catch (IOException e) { - e.printStackTrace(); - } - - return out; - } -} diff --git a/markwon-image-gif/src/main/java/ru/noties/markwon/image/gif/GifPlugin.java b/markwon-image-gif/src/main/java/ru/noties/markwon/image/gif/GifPlugin.java deleted file mode 100644 index 754f91ae..00000000 --- a/markwon-image-gif/src/main/java/ru/noties/markwon/image/gif/GifPlugin.java +++ /dev/null @@ -1,37 +0,0 @@ -package ru.noties.markwon.image.gif; - -import androidx.annotation.NonNull; - -import ru.noties.markwon.AbstractMarkwonPlugin; -import ru.noties.markwon.image.AsyncDrawableLoader; -import ru.noties.markwon.priority.Priority; - -public class GifPlugin extends AbstractMarkwonPlugin { - - @NonNull - public static GifPlugin create() { - return create(true); - } - - @NonNull - public static GifPlugin create(boolean autoPlay) { - return new GifPlugin(autoPlay); - } - - private final boolean autoPlay; - - public GifPlugin(boolean autoPlay) { - this.autoPlay = autoPlay; - } - - @Override - public void configureImages(@NonNull AsyncDrawableLoader.Builder builder) { - builder.addMediaDecoder(GifMediaDecoder.CONTENT_TYPE, GifMediaDecoder.create(autoPlay)); - } - - @NonNull - @Override - public Priority priority() { - return Priority.after(ImagesPlugin.class); - } -} diff --git a/markwon-image-okhttp/build.gradle b/markwon-image-okhttp/build.gradle deleted file mode 100644 index 3f570553..00000000 --- a/markwon-image-okhttp/build.gradle +++ /dev/null @@ -1,25 +0,0 @@ -apply plugin: 'com.android.library' - -android { - - compileSdkVersion config['compile-sdk'] - buildToolsVersion config['build-tools'] - - defaultConfig { - minSdkVersion config['min-sdk'] - targetSdkVersion config['target-sdk'] - versionCode 1 - versionName version - } -} - -dependencies { - - api project(':markwon-core') - - deps.with { - api it['okhttp'] - } -} - -registerArtifact(this) \ No newline at end of file diff --git a/markwon-image-okhttp/gradle.properties b/markwon-image-okhttp/gradle.properties deleted file mode 100644 index 8722d5cf..00000000 --- a/markwon-image-okhttp/gradle.properties +++ /dev/null @@ -1,4 +0,0 @@ -POM_NAME=Image OkHttp -POM_ARTIFACT_ID=image-okhttp -POM_DESCRIPTION=Adds OkHttp client to retrieve images data from network -POM_PACKAGING=aar \ No newline at end of file diff --git a/markwon-image-okhttp/src/main/AndroidManifest.xml b/markwon-image-okhttp/src/main/AndroidManifest.xml deleted file mode 100644 index 32240579..00000000 --- a/markwon-image-okhttp/src/main/AndroidManifest.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/markwon-image-okhttp/src/main/java/ru/noties/markwon/image/okhttp/OkHttpImagesPlugin.java b/markwon-image-okhttp/src/main/java/ru/noties/markwon/image/okhttp/OkHttpImagesPlugin.java deleted file mode 100644 index 6a72136a..00000000 --- a/markwon-image-okhttp/src/main/java/ru/noties/markwon/image/okhttp/OkHttpImagesPlugin.java +++ /dev/null @@ -1,51 +0,0 @@ -package ru.noties.markwon.image.okhttp; - -import androidx.annotation.NonNull; - -import java.util.Arrays; - -import okhttp3.OkHttpClient; -import ru.noties.markwon.AbstractMarkwonPlugin; -import ru.noties.markwon.image.AsyncDrawableLoader; -import ru.noties.markwon.priority.Priority; - -/** - * Plugin to use OkHttpClient to obtain images from network (http and https schemes) - * - * @see #create() - * @see #create(OkHttpClient) - * @since 3.0.0 - */ -@SuppressWarnings("WeakerAccess") -public class OkHttpImagesPlugin extends AbstractMarkwonPlugin { - - @NonNull - public static OkHttpImagesPlugin create() { - return new OkHttpImagesPlugin(new OkHttpClient()); - } - - @NonNull - public static OkHttpImagesPlugin create(@NonNull OkHttpClient okHttpClient) { - return new OkHttpImagesPlugin(okHttpClient); - } - - private final OkHttpClient client; - - OkHttpImagesPlugin(@NonNull OkHttpClient client) { - this.client = client; - } - - @Override - public void configureImages(@NonNull AsyncDrawableLoader.Builder builder) { - builder.addSchemeHandler( - Arrays.asList(NetworkSchemeHandler.SCHEME_HTTP, NetworkSchemeHandler.SCHEME_HTTPS), - new OkHttpSchemeHandler(client) - ); - } - - @NonNull - @Override - public Priority priority() { - return Priority.after(ImagesPlugin.class); - } -} diff --git a/markwon-image-okhttp/src/main/java/ru/noties/markwon/image/okhttp/OkHttpSchemeHandler.java b/markwon-image-okhttp/src/main/java/ru/noties/markwon/image/okhttp/OkHttpSchemeHandler.java deleted file mode 100644 index e1ce930b..00000000 --- a/markwon-image-okhttp/src/main/java/ru/noties/markwon/image/okhttp/OkHttpSchemeHandler.java +++ /dev/null @@ -1,55 +0,0 @@ -package ru.noties.markwon.image.okhttp; - -import android.net.Uri; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.io.IOException; -import java.io.InputStream; - -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; -import okhttp3.ResponseBody; - -class OkHttpSchemeHandler extends SchemeHandler { - - private static final String HEADER_CONTENT_TYPE = "Content-Type"; - - private final OkHttpClient client; - - OkHttpSchemeHandler(@NonNull OkHttpClient client) { - this.client = client; - } - - @Nullable - @Override - public ImageItem handle(@NonNull String raw, @NonNull Uri uri) { - ImageItem out = null; - - final Request request = new Request.Builder() - .url(raw) - .tag(raw) - .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 contentType = response.header(HEADER_CONTENT_TYPE); - out = new ImageItem(contentType, inputStream); - } - } - } - - return out; - } -} diff --git a/markwon-image-svg/build.gradle b/markwon-image-svg/build.gradle deleted file mode 100644 index cfe7bcd1..00000000 --- a/markwon-image-svg/build.gradle +++ /dev/null @@ -1,25 +0,0 @@ -apply plugin: 'com.android.library' - -android { - - compileSdkVersion config['compile-sdk'] - buildToolsVersion config['build-tools'] - - defaultConfig { - minSdkVersion config['min-sdk'] - targetSdkVersion config['target-sdk'] - versionCode 1 - versionName version - } -} - -dependencies { - - api project(':markwon-core') - - deps.with { - api it['android-svg'] - } -} - -registerArtifact(this) \ No newline at end of file diff --git a/markwon-image-svg/gradle.properties b/markwon-image-svg/gradle.properties deleted file mode 100644 index 26dce9a4..00000000 --- a/markwon-image-svg/gradle.properties +++ /dev/null @@ -1,4 +0,0 @@ -POM_NAME=Image SVG -POM_ARTIFACT_ID=image-svg -POM_DESCRIPTION=Adds SVG media support to Markwon markdown -POM_PACKAGING=aar \ No newline at end of file diff --git a/markwon-image-svg/src/main/AndroidManifest.xml b/markwon-image-svg/src/main/AndroidManifest.xml deleted file mode 100644 index 10432a1d..00000000 --- a/markwon-image-svg/src/main/AndroidManifest.xml +++ /dev/null @@ -1 +0,0 @@ - diff --git a/markwon-image-svg/src/main/java/ru/noties/markwon/image/svg/SvgMediaDecoder.java b/markwon-image-svg/src/main/java/ru/noties/markwon/image/svg/SvgMediaDecoder.java deleted file mode 100644 index 8b2a9527..00000000 --- a/markwon-image-svg/src/main/java/ru/noties/markwon/image/svg/SvgMediaDecoder.java +++ /dev/null @@ -1,72 +0,0 @@ -package ru.noties.markwon.image.svg; - -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.caverock.androidsvg.SVG; -import com.caverock.androidsvg.SVGParseException; - -import java.io.InputStream; - -import ru.noties.markwon.image.DrawableUtils; - -/** - * @since 1.1.0 - */ -public class SvgMediaDecoder extends MediaDecoder { - - public static final String CONTENT_TYPE = "image/svg+xml"; - - @NonNull - public static SvgMediaDecoder create(@NonNull Resources resources) { - return new SvgMediaDecoder(resources); - } - - private final Resources resources; - - @SuppressWarnings("WeakerAccess") - SvgMediaDecoder(Resources resources) { - this.resources = resources; - } - - @Nullable - @Override - public Drawable decode(@NonNull InputStream inputStream) { - - final Drawable out; - - SVG svg = null; - try { - svg = SVG.getFromInputStream(inputStream); - } catch (SVGParseException e) { - e.printStackTrace(); - } - - if (svg == null) { - out = null; - } else { - - final float w = svg.getDocumentWidth(); - final float h = svg.getDocumentHeight(); - final float density = resources.getDisplayMetrics().density; - - final int width = (int) (w * density + .5F); - final int height = (int) (h * density + .5F); - - final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_4444); - final Canvas canvas = new Canvas(bitmap); - canvas.scale(density, density); - svg.renderToCanvas(canvas); - - out = new BitmapDrawable(resources, bitmap); - DrawableUtils.applyIntrinsicBounds(out); - } - - return out; - } -} diff --git a/markwon-image-svg/src/main/java/ru/noties/markwon/image/svg/SvgPlugin.java b/markwon-image-svg/src/main/java/ru/noties/markwon/image/svg/SvgPlugin.java deleted file mode 100644 index 34573c9f..00000000 --- a/markwon-image-svg/src/main/java/ru/noties/markwon/image/svg/SvgPlugin.java +++ /dev/null @@ -1,33 +0,0 @@ -package ru.noties.markwon.image.svg; - -import android.content.res.Resources; -import androidx.annotation.NonNull; - -import ru.noties.markwon.AbstractMarkwonPlugin; -import ru.noties.markwon.image.AsyncDrawableLoader; -import ru.noties.markwon.priority.Priority; - -public class SvgPlugin extends AbstractMarkwonPlugin { - - @NonNull - public static SvgPlugin create(@NonNull Resources resources) { - return new SvgPlugin(resources); - } - - private final Resources resources; - - public SvgPlugin(@NonNull Resources resources) { - this.resources = resources; - } - - @Override - public void configureImages(@NonNull AsyncDrawableLoader.Builder builder) { - builder.addMediaDecoder(SvgMediaDecoder.CONTENT_TYPE, SvgMediaDecoder.create(resources)); - } - - @NonNull - @Override - public Priority priority() { - return Priority.after(ImagesPlugin.class); - } -} From 8944f395924aae8d265e246db7f67b46d70c2cb4 Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Mon, 17 Jun 2019 14:08:33 +0300 Subject: [PATCH 24/42] Working with documentation v4 --- .travis.yml | 4 + docs/.vuepress/.artifacts.js | 2 +- docs/.vuepress/components/MavenBadge4.vue | 24 +++ docs/.vuepress/config.js | 11 ++ docs/docs/v2/README.md | 2 + docs/docs/v2/configure.md | 2 + docs/docs/v2/factory.md | 2 + docs/docs/v2/getting-started.md | 2 + docs/docs/v2/html.md | 2 + docs/docs/v2/image-loader.md | 2 + docs/docs/v2/install.md | 2 + docs/docs/v2/syntax-highlight.md | 2 + docs/docs/v2/theme.md | 2 + docs/docs/v2/view.md | 2 + docs/docs/v4/ext-latex/README.md | 49 ++++++ docs/docs/v4/ext-strikethrough/README.md | 29 ++++ docs/docs/v4/ext-tables/README.md | 99 +++++++++++++ docs/docs/v4/ext-tasklist/README.md | 146 ++++++++++++++++++ docs/docs/v4/html/README.md | 107 ++++++++++++++ docs/docs/v4/image-glide/README.md | 3 + docs/docs/v4/image-picasso/README.md | 3 + docs/docs/v4/image/README.md | 172 ++++++++++++++++++++++ docs/docs/v4/recipes.md | 52 ++++++- docs/docs/v4/recycler-table/README.md | 92 ++++++++++++ docs/docs/v4/recycler/README.md | 153 +++++++++++++++++++ docs/docs/v4/syntax-highlight/README.md | 74 ++++++++++ 26 files changed, 1038 insertions(+), 2 deletions(-) create mode 100644 docs/.vuepress/components/MavenBadge4.vue create mode 100644 docs/docs/v4/ext-latex/README.md create mode 100644 docs/docs/v4/ext-strikethrough/README.md create mode 100644 docs/docs/v4/ext-tables/README.md create mode 100644 docs/docs/v4/ext-tasklist/README.md create mode 100644 docs/docs/v4/html/README.md create mode 100644 docs/docs/v4/image-glide/README.md create mode 100644 docs/docs/v4/image-picasso/README.md create mode 100644 docs/docs/v4/image/README.md create mode 100644 docs/docs/v4/recycler-table/README.md create mode 100644 docs/docs/v4/recycler/README.md create mode 100644 docs/docs/v4/syntax-highlight/README.md diff --git a/.travis.yml b/.travis.yml index ec7e3e53..b77bdebc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,9 @@ # https://docs.travis-ci.com/user/languages/android/ + language: android + +# so, out of blue travis requires this now (without it build would not even execute, immediate failure when downloading jdk) +dist: trusty jdk: openjdk8 sudo: false diff --git a/docs/.vuepress/.artifacts.js b/docs/.vuepress/.artifacts.js index 2f41fc13..a0f2a8de 100644 --- a/docs/.vuepress/.artifacts.js +++ b/docs/.vuepress/.artifacts.js @@ -1,4 +1,4 @@ // this is a generated file, do not modify. To update it run 'collectArtifacts.js' script -const artifacts = [{"id":"core","name":"Core","group":"io.noties.markwon","description":"Core Markwon artifact that includes basic markdown parsing and rendering"},{"id":"ext-latex","name":"LaTeX","group":"io.noties.markwon","description":"Extension to add LaTeX formulas to Markwon markdown"},{"id":"ext-strikethrough","name":"Strikethrough","group":"io.noties.markwon","description":"Extension to add strikethrough markup to Markwon markdown"},{"id":"ext-tables","name":"Tables","group":"io.noties.markwon","description":"Extension to add tables markup (GFM) to Markwon markdown"},{"id":"ext-tasklist","name":"Task List","group":"io.noties.markwon","description":"Extension to add task lists (GFM) to Markwon markdown"},{"id":"html","name":"HTML","group":"io.noties.markwon","description":"Provides HTML parsing functionality"},{"id":"image","name":"Image","group":"io.noties.markwon","description":"Markwon image loading module (with optional GIF and SVG support)"},{"id":"image-gif","name":"Image GIF","group":"io.noties.markwon","description":"Adds GIF media support to Markwon markdown"},{"id":"image-glide","name":"Image Glide","group":"io.noties.markwon","description":"Markwon image loading module (based on Glide library)"},{"id":"image-okhttp","name":"Image OkHttp","group":"io.noties.markwon","description":"Adds OkHttp client to retrieve images data from network"},{"id":"image-picasso","name":"Image Picasso","group":"io.noties.markwon","description":"Markwon image loading module (based on Picasso library)"},{"id":"image-svg","name":"Image SVG","group":"io.noties.markwon","description":"Adds SVG media support to Markwon markdown"},{"id":"linkify","name":"Linkify","group":"io.noties.markwon","description":"Markwon plugin to linkify text (based on Android Linkify)"},{"id":"recycler","name":"Recycler","group":"io.noties.markwon","description":"Provides RecyclerView.Adapter to display Markwon markdown"},{"id":"recycler-table","name":"Recycler Table","group":"io.noties.markwon","description":"Provides MarkwonAdapter.Entry to render TableBlocks inside Android-native TableLayout widget"},{"id":"syntax-highlight","name":"Syntax Highlight","group":"io.noties.markwon","description":"Add syntax highlight to Markwon markdown via Prism4j library"}]; +const artifacts = [{"id":"core","name":"Core","group":"io.noties.markwon","description":"Core Markwon artifact that includes basic markdown parsing and rendering"},{"id":"ext-latex","name":"LaTeX","group":"io.noties.markwon","description":"Extension to add LaTeX formulas to Markwon markdown"},{"id":"ext-strikethrough","name":"Strikethrough","group":"io.noties.markwon","description":"Extension to add strikethrough markup to Markwon markdown"},{"id":"ext-tables","name":"Tables","group":"io.noties.markwon","description":"Extension to add tables markup (GFM) to Markwon markdown"},{"id":"ext-tasklist","name":"Task List","group":"io.noties.markwon","description":"Extension to add task lists (GFM) to Markwon markdown"},{"id":"html","name":"HTML","group":"io.noties.markwon","description":"Provides HTML parsing functionality"},{"id":"image","name":"Image","group":"io.noties.markwon","description":"Markwon image loading module (with optional GIF and SVG support)"},{"id":"image-glide","name":"Image Glide","group":"io.noties.markwon","description":"Markwon image loading module (based on Glide library)"},{"id":"image-picasso","name":"Image Picasso","group":"io.noties.markwon","description":"Markwon image loading module (based on Picasso library)"},{"id":"linkify","name":"Linkify","group":"io.noties.markwon","description":"Markwon plugin to linkify text (based on Android Linkify)"},{"id":"recycler","name":"Recycler","group":"io.noties.markwon","description":"Provides RecyclerView.Adapter to display Markwon markdown"},{"id":"recycler-table","name":"Recycler Table","group":"io.noties.markwon","description":"Provides MarkwonAdapter.Entry to render TableBlocks inside Android-native TableLayout widget"},{"id":"syntax-highlight","name":"Syntax Highlight","group":"io.noties.markwon","description":"Add syntax highlight to Markwon markdown via Prism4j library"}]; export { artifacts }; diff --git a/docs/.vuepress/components/MavenBadge4.vue b/docs/.vuepress/components/MavenBadge4.vue new file mode 100644 index 00000000..4a8354cd --- /dev/null +++ b/docs/.vuepress/components/MavenBadge4.vue @@ -0,0 +1,24 @@ + + + + diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index 91f11d14..eaa57168 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -54,6 +54,17 @@ module.exports = { '/docs/v4/core/render-props.md' ] }, + '/docs/v4/ext-latex/', + '/docs/v4/ext-strikethrough/', + '/docs/v4/ext-tables/', + '/docs/v4/ext-tasklist/', + '/docs/v4/html/', + '/docs/v4/image/', + '/docs/v4/image-glide/', + '/docs/v4/image-picasso/', + '/docs/v4/recycler/', + '/docs/v4/recycler-table/', + '/docs/v4/syntax-highlight/', '/docs/v4/recipes.md', '/docs/v4/migration-3-4.md' ], diff --git a/docs/docs/v2/README.md b/docs/docs/v2/README.md index 20275911..d237a0a1 100644 --- a/docs/docs/v2/README.md +++ b/docs/docs/v2/README.md @@ -7,6 +7,8 @@ title: 'Overview'

+ + **Markwon** is a markdown library for Android. It parses markdown following with the help of amazing library and renders result as _Android-native_ Spannables. **No HTML** is involved diff --git a/docs/docs/v2/configure.md b/docs/docs/v2/configure.md index 4ba81749..48a973fc 100644 --- a/docs/docs/v2/configure.md +++ b/docs/docs/v2/configure.md @@ -1,5 +1,7 @@ # Configuration + + `SpannableConfiguration` is the core component that controls how markdown is parsed and rendered. It can be obtained via factory methods: diff --git a/docs/docs/v2/factory.md b/docs/docs/v2/factory.md index edf4a018..3ad083b0 100644 --- a/docs/docs/v2/factory.md +++ b/docs/docs/v2/factory.md @@ -1,5 +1,7 @@ # Factory + + `SpannableFactory` is used to create Span implementations. ```java diff --git a/docs/docs/v2/getting-started.md b/docs/docs/v2/getting-started.md index 3361767a..f77b9ab9 100644 --- a/docs/docs/v2/getting-started.md +++ b/docs/docs/v2/getting-started.md @@ -1,5 +1,7 @@ # Getting started + + ## Quick one This is the most simple way to set markdown to a `TextView` or any of its siblings: diff --git a/docs/docs/v2/html.md b/docs/docs/v2/html.md index 6130db36..8a6fc26d 100644 --- a/docs/docs/v2/html.md +++ b/docs/docs/v2/html.md @@ -1,5 +1,7 @@ # HTML + + Starting with version `2.0.0` `Markwon` brings the whole HTML parsing/rendering stack _on-site_. The main reason for this are _special_ definitions of HTML nodes by . More specifically: diff --git a/docs/docs/v2/image-loader.md b/docs/docs/v2/image-loader.md index 6dca5991..68d1a881 100644 --- a/docs/docs/v2/image-loader.md +++ b/docs/docs/v2/image-loader.md @@ -1,5 +1,7 @@ # Images + + By default `Markwon` doesn't handle images. Although `AsyncDrawable.Loader` is defined in main artifact, it does not provide implementation. diff --git a/docs/docs/v2/install.md b/docs/docs/v2/install.md index efb9ef2a..d2edb82a 100644 --- a/docs/docs/v2/install.md +++ b/docs/docs/v2/install.md @@ -1,5 +1,7 @@ # Installation + + In order to start using `Markwon` add this to your dependencies block diff --git a/docs/docs/v2/syntax-highlight.md b/docs/docs/v2/syntax-highlight.md index 854b82b0..a65e72f7 100644 --- a/docs/docs/v2/syntax-highlight.md +++ b/docs/docs/v2/syntax-highlight.md @@ -1,5 +1,7 @@ # Syntax highlight + + This is a simple module to add **syntax highlight** functionality to your markdown rendered with `Markwon` library. It is based on [Prism4j](https://github.com/noties/Prism4j) so lead there to understand how to configure `Prism4j` instance. diff --git a/docs/docs/v2/theme.md b/docs/docs/v2/theme.md index 292e3e39..07aeb26d 100644 --- a/docs/docs/v2/theme.md +++ b/docs/docs/v2/theme.md @@ -1,5 +1,7 @@ # Theme + + Here is the list of properties that can be configured via `SpannableTheme`. If you wish to control what is out of this list, you can use [SpannableFactory](/docs/v2/factory.md) abstraction which lets you to gather full control of Spans that are used to display markdown. diff --git a/docs/docs/v2/view.md b/docs/docs/v2/view.md index bd610344..c8489d94 100644 --- a/docs/docs/v2/view.md +++ b/docs/docs/v2/view.md @@ -1,5 +1,7 @@ # MarkwonView + + This is simple library containing 2 views that are able to display markdown: diff --git a/docs/docs/v4/ext-latex/README.md b/docs/docs/v4/ext-latex/README.md new file mode 100644 index 00000000..4d57371f --- /dev/null +++ b/docs/docs/v4/ext-latex/README.md @@ -0,0 +1,49 @@ +# LaTeX extension + + + +This is an extension that will help you display LaTeX formulas in your markdown. +Syntax is pretty simple: pre-fix and post-fix your latex with `$$` (double dollar sign). +`$$` should be the first characters in a line. + +```markdown +$$ +\\text{A long division \\longdiv{12345}{13} +$$ +``` + +```markdown +$$\\text{A long division \\longdiv{12345}{13}$$ +``` + +```java +Markwon.builder(context) + .use(JLatexMathPlugin.create(textSize)) + .build(); +``` + +This extension uses [jlatexmath-android](https://github.com/noties/jlatexmath-android) artifact to create LaTeX drawable. + +## Config + +```java +final Markwon markwon = Markwon.builder(context) + .usePlugin(JLatexMathPlugin.create(textSize, new BuilderConfigure() { + @Override + public void configureBuilder(@NonNull Builder builder) { + builder + .background(backgroundDrawable) + .align(JLatexMathDrawable.ALIGN_CENTER) + .fitCanvas(true) + .padding(paddingPx) + // @since 4.0.0 - optional, by default cached-thread-pool will be used + .executorService(Executors.newCachedThreadPool()); + } + })) + .build(); +``` + + +:::tip +Since `JLatexMathPlugin` operates independently of `ImagesPlugin` +::: \ No newline at end of file diff --git a/docs/docs/v4/ext-strikethrough/README.md b/docs/docs/v4/ext-strikethrough/README.md new file mode 100644 index 00000000..516b5b98 --- /dev/null +++ b/docs/docs/v4/ext-strikethrough/README.md @@ -0,0 +1,29 @@ +# Strikethrough extension + + + +This module adds `strikethrough` functionality to `Markwon` via `StrikethroughPlugin`: + +```java +Markwon.builder(context) + .usePlugin(StrikethroughPlugin.create()) +``` + +This plugin registers `SpanFactory` for `Strikethrough` node, so it's possible to customize Strikethrough Span that is used in rendering: + +```java +Markwon.builder(context) + .usePlugin(StrikethroughPlugin.create()) + .usePlugin(new AbstractMarkwonPlugin() { + @Override + public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) { + builder.setFactory(Strikethrough.class, new SpanFactory() { + @Override + public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) { + // will use Underline span instead of Strikethrough + return new UnderlineSpan(); + } + }); + } + }) +``` diff --git a/docs/docs/v4/ext-tables/README.md b/docs/docs/v4/ext-tables/README.md new file mode 100644 index 00000000..04df9c5e --- /dev/null +++ b/docs/docs/v4/ext-tables/README.md @@ -0,0 +1,99 @@ +# Tables extension + + + +This extension adds support for GFM tables. + +```java +final Markwon markwon = Markwon.builder(context) + // create default instance of TablePlugin + .usePlugin(TablePlugin.create(context)) +``` + +```java +final TableTheme tableTheme = TableTheme.builder() + .tableBorderColor(Color.RED) + .tableBorderWidth(0) + .tableCellPadding(0) + .tableHeaderRowBackgroundColor(Color.BLACK) + .tableEvenRowBackgroundColor(Color.GREEN) + .tableOddRowBackgroundColor(Color.YELLOW) + .build(); + +final Markwon markwon = Markwon.builder(context) + .usePlugin(TablePlugin.create(tableTheme)) +``` + +```java +Markwon.builder(context) + .usePlugin(TablePlugin.create(builder -> + builder + .tableBorderColor(Color.RED) + .tableBorderWidth(0) + .tableCellPadding(0) + .tableHeaderRowBackgroundColor(Color.BLACK) + .tableEvenRowBackgroundColor(Color.GREEN) + .tableOddRowBackgroundColor(Color.YELLOW) +)) +``` + +Please note, that _by default_ tables have limitations. For example, there is no support +for images inside table cells. And table contents won't be copied to clipboard if a TextView +has such functionality. Table will always take full width of a TextView in which it is displayed. +All columns will always be of the same width. So, _default_ implementation provides basic +functionality which can answer some needs. These all come from the limited nature of the TextView +to display such content. + +In order to provide full-fledged experience, tables must be displayed in a special widget. +Since version `3.0.0` Markwon provides a special artifact `markwon-recycler` that allows +to render markdown in a set of widgets in a RecyclerView. It also gives ability to change +display widget form TextView to any other. + +```java +final Table table = Table.parse(Markwon, TableBlock); +myTableWidget.setTable(table); +``` + +:::tip +To take advantage of this functionality and render tables without limitations (including +horizontally scrollable layout when its contents exceed screen width), refer to [recycler-table](/docs/v3/recycler-table/) +module documentation that adds support for rendering `TableBlock` markdown node inside Android-native `TableLayout` widget. +::: + +## Theme + +### Cell padding + +Padding inside a table cell + + + +### Border color + +The color of table borders + + + +### Border width + +The width of table borders + + + +### Odd row background + +Background of an odd table row + + + +### Even row background + +Background of an even table row + + + +### Header row background + +Background of header table row + + diff --git a/docs/docs/v4/ext-tasklist/README.md b/docs/docs/v4/ext-tasklist/README.md new file mode 100644 index 00000000..154ec743 --- /dev/null +++ b/docs/docs/v4/ext-tasklist/README.md @@ -0,0 +1,146 @@ +# Task list extension + + + +Adds support for GFM (Github-flavored markdown) task-lists: + +```java +Markwon.builder(context) + .usePlugin(TaskListPlugin.create(context)); +``` + +--- + +Create a default instance of `TaskListPlugin` with `TaskListDrawable` initialized to use +`android.R.attr.textColorLink` as primary color and `android.R.attr.colorBackground` as background +```java +TaskListPlugin.create(context); +``` + +--- + +Create an instance of `TaskListPlugin` with exact color values to use: +```java +// obtain color values +final int checkedFillColor = /* */; +final int normalOutlineColor = /* */; +final int checkMarkColor = /* */; + +TaskListPlugin.create(checkedFillColor, normalOutlineColor, checkMarkColor); +``` + +--- + +Specify own drawable for a task list item: + +```java +// obtain drawable +final Drawable drawable = /* */; + +TaskListPlugin.create(drawable); +``` + +:::warning +Please note that custom drawable for a task list item must correctly handle state +in order to display done/not-done: + +```java +public class MyTaskListDrawable extends Drawable { + + private boolean isChecked; + + @Override + public void draw(@NonNull Canvas canvas) { + // draw accordingly to the isChecked value + } + + /* implementation omitted */ + + @Override + protected boolean onStateChange(int[] state) { + final boolean isChecked = contains(state, android.R.attr.state_checked); + final boolean result = this.isChecked != isChecked; + if (result) { + this.isChecked = isChecked; + } + return result; + } + + private static boolean contains(@Nullable int[] states, int value) { + if (states != null) { + for (int state : states) { + if (state == value) { + // NB return here + return true; + } + } + } + return false; + } +} +``` +::: + +## Task list mutation + +It is possible to mutate task list item state (toggle done/not-done). But note +that `Markwon` won't handle state change internally by any means and this change +is merely a visual one. If you need to persist state of a task list +item change you have to implement it yourself. This should get your started: + +```java +final Markwon markwon = Markwon.builder(context) + .usePlugin(TaskListPlugin.create(context)) + .usePlugin(new AbstractMarkwonPlugin() { + @Override + public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) { + + // obtain original SpanFactory set by TaskListPlugin + final SpanFactory origin = builder.getFactory(TaskListItem.class); + if (origin == null) { + // or throw, as it's a bit weird state and we expect + // this factory to be present + return; + } + + builder.setFactory(TaskListItem.class, new SpanFactory() { + @Override + public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) { + // it's a bit non-secure behavior and we should validate + // the type of returned span first, but for the sake of brevity + // we skip this step + final TaskListSpan span = (TaskListSpan) origin.getSpans(configuration, props); + + if (span == null) { + // or throw + return null; + } + + // return an array of spans + return new Object[]{ + span, + new ClickableSpan() { + @Override + public void onClick(@NonNull View widget) { + // toggle VISUAL state + span.setDone(!span.isDone()); + + // do not forget to invalidate widget + widget.invalidate(); + + // execute your persistence logic + } + + @Override + public void updateDrawState(@NonNull TextPaint ds) { + // no-op, so appearance is not changed (otherwise + // task list item will look like a link) + } + } + }; + } + }); + } + }) + .build(); +``` \ No newline at end of file diff --git a/docs/docs/v4/html/README.md b/docs/docs/v4/html/README.md new file mode 100644 index 00000000..44b95c54 --- /dev/null +++ b/docs/docs/v4/html/README.md @@ -0,0 +1,107 @@ +# HTML + + + +This artifact encapsulates HTML parsing from the core artifact and provides +few predefined `TagHandlers` + +```java +final Markwon markwon = Markwon.builder(context) + .usePlugin(HtmlPlugin.create()) + .build(); +``` + +As this artifact brings modified [jsoup](https://github.com/jhy/jsoup) library +it was moved to a standalone module in order to minimize dependencies and unused code +in applications that does not require HTML render capabilities. + +Before `Markwon` used android `Html` class for parsing and +rendering. Unfortunately, according to markdown specification, markdown can contain +HTML in _unpredictable_ way if rendered _outside_ of browser. For example: + +```markdown{4} + +Hello from italics tag + +bold> +``` + +This snippet could be represented as: +* HtmlBlock (`\nHello from italics tag`) +* HtmlInline (``) +* HtmlInline (``) +* Text (`bold`) +* HtmlInline (``) + +:::tip A bit of background +
+ had brought attention to differences between HTML & commonmark implementations.

+::: + +Unfortunately Android `HTML` class cannot parse a _fragment_ of HTML to later +be included in a bigger set of content. This is why the decision was made to bring +HTML parsing _in-markwon-house_ + +## Predefined TagHandlers +* `` +* `` +* `
` +* `` +* `` +* `, ` +* `, ` +* `, ` +* `
    ,
      ` +* `, , , ` +* `

      ,

      ,

      ,

      ,

      ,
      ` + +:::tip +All predefined tag handlers will use styling spans for native markdown content. +So, if your `Markwon` instance was configured to, for example, render Emphasis +nodes as a red text then HTML tag handler will +use the same span. This includes images, links, UrlResolver, LinkProcessor, etc +::: + +--- + +Staring with you can exclude all default tag handlers: + +```java +.usePlugin(HtmlPlugin.create(new HtmlPlugin.HtmlConfigure() { + @Override + public void configureHtml(@NonNull HtmlPlugin plugin) { + plugin.excludeDefaults(true); + } +})) +``` + +or via plugin: + +```java +.usePlugin(new AbstractMarkwonPlugin() { + @Override + public void configure(@NonNull Registry registry) { + registry.require(HtmlPlugin.class, new Action() { + @Override + public void apply(@NonNull HtmlPlugin htmlPlugin) { + htmlPlugin.excludeDefaults(true); + } + }); + } +}) +``` + +If you wish to exclude some of them `TagHandlerNoOp` can be used: + +```java +.usePlugin(HtmlPlugin.create(new HtmlPlugin.HtmlConfigure() { + @Override + public void configureHtml(@NonNull HtmlPlugin plugin) { + plugin.addHandler(TagHandlerNoOp.create("h4", "h5", "h6", "img")); + } +})) +``` + +## TagHandler + + diff --git a/docs/docs/v4/image-glide/README.md b/docs/docs/v4/image-glide/README.md new file mode 100644 index 00000000..5d733b87 --- /dev/null +++ b/docs/docs/v4/image-glide/README.md @@ -0,0 +1,3 @@ +# Image Glide + + \ No newline at end of file diff --git a/docs/docs/v4/image-picasso/README.md b/docs/docs/v4/image-picasso/README.md new file mode 100644 index 00000000..852ff0e5 --- /dev/null +++ b/docs/docs/v4/image-picasso/README.md @@ -0,0 +1,3 @@ +# Image Picasso + + \ No newline at end of file diff --git a/docs/docs/v4/image/README.md b/docs/docs/v4/image/README.md new file mode 100644 index 00000000..8731af05 --- /dev/null +++ b/docs/docs/v4/image/README.md @@ -0,0 +1,172 @@ +# Image + + + +In order to display images in your markdown `ImagesPlugin` can be used. + +```java +final Markwon markwon = Markwon.builder(context) + .usePlugin(ImagesPlugin.create()) +``` + +:::tip +There are also modules that add image loading capabilities to markdown +based on image-loading libraries: [image-glide](/docs/v4/image-glide/) and +[image-picasso](/docs/v4/image-picasso/) +::: + +`ImagesPlugin` splits the image-loading into 2 parts: scheme-handling and media-decoding. + +## SchemeHandler + +To add a scheme-handler to `ImagesPlugin`: + +```java +final Markwon markwon = Markwon.builder(context) + .usePlugin(ImagesPlugin.create()) + .usePlugin(new AbstractMarkwonPlugin() { + @Override + public void configure(@NonNull Registry registry) { + registry.require(ImagesPlugin.class, new Action() { + @Override + public void apply(@NonNull ImagesPlugin imagesPlugin) { + imagesPlugin.addSchemeHandler(DataUriSchemeHandler.create()); + } + }); + } + }) +``` + +```java +final Markwon markwon = Markwon.builder(context) + .usePlugin(ImagesPlugin.create(new ImagesPlugin.ImagesConfigure() { + @Override + public void configureImages(@NonNull ImagesPlugin plugin) { + plugin.addSchemeHandler(DataUriSchemeHandler.create()); + } + })) +``` + +`ImagesPlugin` comes with a set of predefined scheme-handlers: +* `FileSchemeHandler` - `file://` +* `DataUriSchemeHandler` - `data:` +* `NetworkSchemeHandler` - `http`, `https` +* `OkHttpNetworkSchemeHandler` - `http`, `https` + +### FileSchemeHandler + +Loads images via `file://` scheme. Allows loading images from `assets` folder. + +```java +// default implementation, no assets handling +FileSchemeHandler.create(); + +// assets loading +FileSchemeHandler.createWithAssets(context); +``` + +:::warning +Assets loading will work when your URL will include `android_asset` the the path, +for example: `file:///android_asset/image.png` (mind the 3 slashes `///`). If you wish +to _assume_ all images without proper scheme to point to assets folder, then you can use +[UrlProcessorAndroidAssets](/docs/v4/core/configuration.html#urlprocessorandroidassets) +::: + +By default `ImagesPlugin` includes _plain_ `FileSchemeHandler` (without assets support), +so if you wish to change that you can explicitly specify it: + +```java +final Markwon markwon = Markwon.builder(context) + .usePlugin(ImagesPlugin.create(new ImagesPlugin.ImagesConfigure() { + @Override + public void configureImages(@NonNull ImagesPlugin plugin) { + plugin.addSchemeHandler(FileSchemeHandler.createWithAssets(context)); + } + })) +``` + +### DataUriSchemeHandler +`DataUriSchemeHandler` allows _inlining_ images with `data:` scheme (`data:image/svg+xml;base64,MTIz`). +This scheme-handler is registered by default, so you do not need to add it explicitly. + +### NetworkSchemeHandler +`NetworkSchemeHandler` allows obtaining images from `http://` and `https://` uris +(internally it uses `HttpURLConnection`). This scheme-handler is registered by default + +### OkHttpNetworkSchemeHandler +`OkHttpNetworkSchemeHandler` allows obtaining images from `http://` and `https://` uris +via [okhttp library](https://github.com/square/okhttp). Please note that in order to use +this scheme-handler you must explicitly add `okhttp` library to your project. + +```java +// default instance +OkHttpNetworkSchemeHandler.create(); + +// specify OkHttpClient to use +OkHttpNetworkSchemeHandler.create(new OkHttpClient()); + +// @since 4.0.0 +OkHttpNetworkSchemeHandler.create(Call.Factory); +``` + +### Custom SchemeHandler + +```java +public abstract class SchemeHandler { + + @NonNull + public abstract ImageItem handle(@NonNull String raw, @NonNull Uri uri); + + @NonNull + public abstract Collection supportedSchemes(); +} +``` + +Starting with `SchemeHandler` can return a result (when no +further decoding is required): + +```java +final Markwon markwon = Markwon.builder(context) + .usePlugin(ImagesPlugin.create(new ImagesPlugin.ImagesConfigure() { + @Override + public void configureImages(@NonNull ImagesPlugin plugin) { + // for example to return a drawable resource + plugin.addSchemeHandler(new SchemeHandler() { + @NonNull + @Override + public ImageItem handle(@NonNull String raw, @NonNull Uri uri) { + + final int resourceId = context.getResources().getIdentifier( + raw.substring("resources://".length()), + "drawable", + context.getPackageName()); + + // it's fine if it throws, async-image-loader will catch exception + final Drawable drawable = context.getDrawable(resourceId); + + // it's important to apply bounds to resulting drawable + DrawableUtils.applyIntrinsicBounds(drawable); + + return ImageItem.withResult(drawable); + } + + @NonNull + @Override + public Collection supportedSchemes() { + return Collections.singleton("resources"); + } + }); + } + })) +``` + +:::tip +If you are using [html](/docs/v4/html/) you do not have to additionally setup +images displayed via `` tag, as `HtmlPlugin` automatically uses configured +image loader. But images referenced in HTML come with additional support for +sizes, which is not supported natively by markdown, allowing absolute or relative sizes: + +```html + +``` +::: \ No newline at end of file diff --git a/docs/docs/v4/recipes.md b/docs/docs/v4/recipes.md index 7fc70175..46e9d86c 100644 --- a/docs/docs/v4/recipes.md +++ b/docs/docs/v4/recipes.md @@ -1,3 +1,53 @@ # Recipes -todo \ No newline at end of file + +## SpannableFactory + +Consider using `NoCopySpannableFactory` when a `TextView` will be used to display markdown +multiple times (for example in a `RecyclerView`): + +```java +// call after inflation and before setting markdown +textView.setSpannableFactory(NoCopySpannableFactory.getInstance()); +``` + + +## Autolink + +Do not use `autolink` XML attribute on your `TextView` as it will remove all links except autolinked ones. +Consider using [linkify plugin](/docs/v4/linkify.md) or commonmark-java [autolink extension](https://github.com/atlassian/commonmark-java) + + + +## Custom typeface + +When using a custom typeface on a `TextView` you might find that **bold** and *italic* nodes +are displayed incorrectly. Consider registering own `SpanFactories` for `StrongEmphasis` and `Emphasis` nodes: + +```java +final Markwon markwon = Markwon.builder(context) + .usePlugin(new AbstractMarkwonPlugin() { + @Override + public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) { + builder + .setFactory(StrongEmphasis.class, new SpanFactory() { + @Override + public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) { + return new StyleSpan(Typeface.BOLD); + } + }) + .setFactory(Emphasis.class, new SpanFactory() { + @Override + public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) { + return new StyleSpan(Typeface.ITALIC); + } + }); + } + }) + .build(); +``` + +Please check that `StyleSpan` works for you. If it doesn't consider +using `CustomTypefaceSpan` with your typeface directly. + + diff --git a/docs/docs/v4/recycler-table/README.md b/docs/docs/v4/recycler-table/README.md new file mode 100644 index 00000000..1841e832 --- /dev/null +++ b/docs/docs/v4/recycler-table/README.md @@ -0,0 +1,92 @@ +# Recycler Table + + + +Artifact that provides [MarkwonAdapter.Entry](/docs/v3/recycler/) to render `TableBlock` inside +Android-native `TableLayout` widget. + +screenshot +
      +* It's possible to wrap `TableLayout` inside a `HorizontalScrollView` to include all table content + +--- + +Register instance of `TableEntry` with `MarkwonAdapter` to render TableBlocks: +```java +final MarkwonAdapter adapter = MarkwonAdapter.builder(R.layout.adapter_default_entry, R.id.text) + .include(TableBlock.class, TableEntry.create(builder -> builder + .tableLayout(R.layout.adapter_table_block, R.id.table_layout) + .textLayoutIsRoot(R.layout.view_table_entry_cell))) + .build(); +``` + +`TableEntry` requires at least 2 arguments: +* `tableLayout` - layout with `TableLayout` inside +* `textLayout` - layout with `TextView` inside (represents independent table cell) + +In case when required view is the root of layout specific builder methods can be used: +* `tableLayoutIsRoot(int)` +* `textLayoutIsRoot(int)` + +If your layouts have different structure (for example wrap a `TableView` inside a `HorizontalScrollView`) +then you should use methods that accept ID of required view inside layout: +* `tableLayout(int, int)` +* `textLayout(int, int)` + +--- + +To display `TableBlock` as a `TableLayout` specific `MarkwonPlugin` must be used: `TableEntryPlugin`. + +:::warning +Do not use `TablePlugin` if you wish to display markdown tables via `TableEntry`. Use **TableEntryPlugin** instead +::: + +`TableEntryPlugin` can reuse existing `TablePlugin` to make appearance of tables the same in both contexts: +when rendering _natively_ in a TextView and when rendering in RecyclerView with TableEntry. + +* `TableEntryPlugin.create(Context)` - creates plugin with default `TableTheme` +* `TableEntryPlugin.create(TableTheme)` - creates plugin with provided `TableTheme` +* `TableEntryPlugin.create(TablePlugin.ThemeConfigure)` - creates plugin with theme configured by `ThemeConfigure` +* `TableEntryPlugin.create(TablePlugin)` - creates plugin with `TableTheme` used in provided `TablePlugin` + +```java +final Markwon markwon = Markwon.builder(context) + .usePlugin(TableEntryPlugin.create(context)) + // other plugins + .build(); +``` + +```java +final Markwon markwon = Markwon.builder(context) + .usePlugin(TableEntryPlugin.create(builder -> builder + .tableBorderWidth(0) + .tableHeaderRowBackgroundColor(Color.RED))) + // other plugins + .build(); +``` + +## Table with scrollable content + +To stretch table columns to fit the width of screen or to make table scrollable when content exceeds screen width +this layout can be used: + +```xml + + + + + +``` \ No newline at end of file diff --git a/docs/docs/v4/recycler/README.md b/docs/docs/v4/recycler/README.md new file mode 100644 index 00000000..2273915e --- /dev/null +++ b/docs/docs/v4/recycler/README.md @@ -0,0 +1,153 @@ +# Recycler + + + +This artifact allows displaying markdown in a set of Android widgets +inside a RecyclerView. Can be useful when displaying lengthy markdown +content or **displaying certain markdown blocks inside specific widgets**. + +```java +// create an adapter that will use a TextView for each block of markdown +// `createTextViewIsRoot` accepts a layout in which TextView is the root view +final MarkwonAdapter adapter = + MarkwonAdapter.createTextViewIsRoot(R.layout.adapter_default_entry); +``` + +```java +// `create` method accepts a layout with TextView and ID of a TextView +// which allows wrapping a TextView inside another widget or combine with other widgets +final MarkwonAdapter adapter = + MarkwonAdapter.create(R.layout.adapter_default_entry, R.id.text_view); + +// initialize RecyclerView (LayoutManager, Decorations, etc) +final RecyclerView recyclerView = obtainRecyclerView(); + +// set adapter +recyclerView.setAdapter(adapter); + +// obtain an instance of Markwon (register all required plugins) +final Markwon markwon = obtainMarkwon(); + +// set markdown to be displayed +adapter.setMarkdown(markwon, "# This is markdown!"); + +// NB, adapter does not handle updates on its own, please use +// whatever method appropriate for you. +adapter.notifyDataSetChanged(); +``` + +Initialized adapter above will use a TextView for each markdown block. +In order to tell adapter to render certain blocks differently a `builder` can be used. +For example, let's render `FencedCodeBlock` inside a `HorizontalScrollView`: + +```java +// we still need to have a _default_ entry +final MarkwonAdapter adapter = + MarkwonAdapter.builderTextViewIsRoot(R.layout.adapter_default_entry) + .include(FencedCodeBlock.class, new FencedCodeBlockEntry()) + .build(); +``` + +where `FencedCodeBlockEntry` is: + +```java +public class FencedCodeBlockEntry extends MarkwonAdapter.Entry { + + @NonNull + @Override + public Holder createHolder(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) { + return new Holder(inflater.inflate(R.layout.adapter_fenced_code_block, parent, false)); + } + + @Override + public void bindHolder(@NonNull Markwon markwon, @NonNull Holder holder, @NonNull FencedCodeBlock node) { + markwon.setParsedMarkdown(holder.textView, markwon.render(node)); + } + + public static class Holder extends MarkwonAdapter.Holder { + + final TextView textView; + + public Holder(@NonNull View itemView) { + super(itemView); + + this.textView = requireView(R.id.text_view); + } + } +} +``` + +and its layout (`R.layout.adapter_fenced_code_block`): + +```xml + + + + + + +``` + +As we apply styling to `FencedCodeBlock` _manually_, we no longer need +`Markwon` to apply styling spans for us, so `Markwon` initialization could be: + +```java +final Markwon markwon = Markwon.builder(context) + // your other plugins + .usePlugin(new AbstractMarkwonPlugin() { + @Override + public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) { + builder.on(FencedCodeBlock.class, (visitor, fencedCodeBlock) -> { + // we actually won't be applying code spans here, as our custom view will + // draw background and apply mono typeface + // + // NB the `trim` operation on literal (as code will have a new line at the end) + final CharSequence code = visitor.configuration() + .syntaxHighlight() + .highlight(fencedCodeBlock.getInfo(), fencedCodeBlock.getLiteral().trim()); + visitor.builder().append(code); + }); + } + }) + .build(); +``` + +Previously we have created a `FencedCodeBlockEntry` but all it does is apply markdown to a TextView. +For such a case there is a `SimpleEntry` that could be used instead: + +```java +final MarkwonAdapter adapter = + MarkwonAdapter.builderTextViewIsRoot(R.layout.adapter_default_entry) + .include(FencedCodeBlock.class, SimpleEntry.create(R.layout.adapter_fenced_code_block, R.id.text_view)) + .build(); +``` + +:::tip +`SimpleEntry` also takes care of _caching_ parsed markdown. So each node will be +parsed only once and each subsequent adapter binding call will reuse previously cached markdown. +::: + +:::tip Tables +There is a standalone artifact that adds support for displaying markdown tables +natively via `TableLayout`. Please refer to its [documentation](/docs/v3/recycler-table/) +::: \ No newline at end of file diff --git a/docs/docs/v4/syntax-highlight/README.md b/docs/docs/v4/syntax-highlight/README.md new file mode 100644 index 00000000..e1abcca0 --- /dev/null +++ b/docs/docs/v4/syntax-highlight/README.md @@ -0,0 +1,74 @@ +# Syntax highlight + + + +This is a module to add **syntax highlight** functionality to your markdown rendered with `Markwon` library. It is based on [Prism4j](https://github.com/noties/Prism4j) so lead there to understand how to configure `Prism4j` instance. + +theme-default + + +theme-darkula + +--- + +First, we need to obtain an instance of `Prism4jSyntaxHighlight` which implements Markwon's `SyntaxHighlight`: + +```java +final SyntaxHighlight highlight = + Prism4jSyntaxHighlight.create(Prism4j, Prism4jTheme); +``` + +we also can obtain an instance of `Prism4jSyntaxHighlight` that has a _fallback_ option (if a language is not defined in `Prism4j` instance, fallback language can be used): + +```java +final SyntaxHighlight highlight = + Prism4jSyntaxHighlight.create(Prism4j, Prism4jTheme, String); +``` + +Generally obtaining a `Prism4j` instance is pretty easy: + +```java +final Prism4j prism4j = new Prism4j(new GrammarLocatorDef()); +``` + +Where `GrammarLocatorDef` is a generated grammar locator (if you use `prism4j-bundler` annotation processor) + +`Prism4jTheme` is a specific type that is defined in this module (`prism4j` doesn't know anything about rendering). It has 2 implementations: + +* `Prism4jThemeDefault` +* `Prism4jThemeDarkula` + +Both of them can be obtained via factory method `create`: + +* `Prism4jThemeDefault.create()` +* `Prism4jThemeDarkula.create()` + +But of cause nothing is stopping you from defining your own theme: + +```java +public interface Prism4jTheme { + + @ColorInt + int background(); + + @ColorInt + int textColor(); + + void apply( + @NonNull String language, + @NonNull Prism4j.Syntax syntax, + @NonNull SpannableStringBuilder builder, + int start, + int end + ); +} +``` + +:::tip +You can extend `Prism4jThemeBase` which has some helper methods +::: + +```java +final Markwon markwon = Markwon.builder(context) + .usePlugin(SyntaxHighlightPlugin.create(prism4j, prism4jTheme)) +``` \ No newline at end of file From a3ebae3b8739f03e0c86c3a00fa73b89b75c0e12 Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Mon, 17 Jun 2019 23:01:02 +0300 Subject: [PATCH 25/42] Renamed DefaultImageMediaDecoder to DefaultMediaDecoder --- .../noties/markwon/app/MarkdownRenderer.java | 29 ++++++++++ docs/.vuepress/config.js | 1 + docs/docs/v4/core/core-plugin.md | 2 +- docs/docs/v4/image/README.md | 55 +++++++++++++++++-- docs/docs/v4/linkify/README.md | 3 + .../image/AsyncDrawableLoaderBuilder.java | 2 +- .../image/AsyncDrawableLoaderImpl.java | 2 +- ...aDecoder.java => DefaultMediaDecoder.java} | 12 ++-- .../io/noties/markwon/image/ImagesPlugin.java | 6 +- 9 files changed, 96 insertions(+), 16 deletions(-) create mode 100644 docs/docs/v4/linkify/README.md rename markwon-image/src/main/java/io/noties/markwon/image/{DefaultImageMediaDecoder.java => DefaultMediaDecoder.java} (79%) diff --git a/app/src/main/java/io/noties/markwon/app/MarkdownRenderer.java b/app/src/main/java/io/noties/markwon/app/MarkdownRenderer.java index 9bcb8e0f..67585f85 100644 --- a/app/src/main/java/io/noties/markwon/app/MarkdownRenderer.java +++ b/app/src/main/java/io/noties/markwon/app/MarkdownRenderer.java @@ -1,6 +1,7 @@ package io.noties.markwon.app; import android.content.Context; +import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Handler; import android.os.SystemClock; @@ -9,6 +10,8 @@ import android.text.Spanned; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import java.io.InputStream; +import java.util.Collection; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; @@ -23,7 +26,10 @@ import io.noties.markwon.ext.strikethrough.StrikethroughPlugin; import io.noties.markwon.ext.tables.TablePlugin; import io.noties.markwon.ext.tasklist.TaskListPlugin; import io.noties.markwon.html.HtmlPlugin; +import io.noties.markwon.image.ImageItem; import io.noties.markwon.image.ImagesPlugin; +import io.noties.markwon.image.MediaDecoder; +import io.noties.markwon.image.SchemeHandler; import io.noties.markwon.image.file.FileSchemeHandler; import io.noties.markwon.image.network.OkHttpNetworkSchemeHandler; import io.noties.markwon.syntax.Prism4jTheme; @@ -120,6 +126,29 @@ public class MarkdownRenderer { builder.urlProcessor(urlProcessor); } }) + .usePlugin(new AbstractMarkwonPlugin() { + @Override + public void configure(@NonNull Registry registry) { + registry.require(ImagesPlugin.class, new Action() { + @Override + public void apply(@NonNull ImagesPlugin imagesPlugin) { + imagesPlugin.addMediaDecoder(new MediaDecoder() { + @NonNull + @Override + public Drawable decode(@Nullable String contentType, @NonNull InputStream inputStream) { + return null; + } + + @NonNull + @Override + public Collection supportedTypes() { + return null; + } + }); + } + }); + } + }) .build(); final long start = SystemClock.uptimeMillis(); diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index eaa57168..27a4dd6b 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -62,6 +62,7 @@ module.exports = { '/docs/v4/image/', '/docs/v4/image-glide/', '/docs/v4/image-picasso/', + '/docs/v4/linkify/', '/docs/v4/recycler/', '/docs/v4/recycler-table/', '/docs/v4/syntax-highlight/', diff --git a/docs/docs/v4/core/core-plugin.md b/docs/docs/v4/core/core-plugin.md index 750e3c59..a5002ba8 100644 --- a/docs/docs/v4/core/core-plugin.md +++ b/docs/docs/v4/core/core-plugin.md @@ -108,7 +108,7 @@ which accepts a MovementMethod as an argument. ## OnTextAddedListener Since `4.0.0` `CorePlugin` provides ability to receive text-added event. This can -be useful in order to process raw text (for example to [linkify](/docs/v4/linkify.md) it): +be useful in order to process raw text (for example to [linkify](/docs/v4/linkify/) it): ```java final Markwon markwon = Markwon.builder(context) diff --git a/docs/docs/v4/image/README.md b/docs/docs/v4/image/README.md index 8731af05..b618f999 100644 --- a/docs/docs/v4/image/README.md +++ b/docs/docs/v4/image/README.md @@ -66,7 +66,7 @@ FileSchemeHandler.createWithAssets(context); ``` :::warning -Assets loading will work when your URL will include `android_asset` the the path, +Assets loading will work when your URL will include `android_asset` in the path, for example: `file:///android_asset/image.png` (mind the 3 slashes `///`). If you wish to _assume_ all images without proper scheme to point to assets folder, then you can use [UrlProcessorAndroidAssets](/docs/v4/core/configuration.html#urlprocessorandroidassets) @@ -136,8 +136,9 @@ final Markwon markwon = Markwon.builder(context) @Override public ImageItem handle(@NonNull String raw, @NonNull Uri uri) { + // will handle URLs like `drawable://ic_account_24dp_white` final int resourceId = context.getResources().getIdentifier( - raw.substring("resources://".length()), + raw.substring("drawable://".length()), "drawable", context.getPackageName()); @@ -146,20 +147,66 @@ final Markwon markwon = Markwon.builder(context) // it's important to apply bounds to resulting drawable DrawableUtils.applyIntrinsicBounds(drawable); - + return ImageItem.withResult(drawable); } @NonNull @Override public Collection supportedSchemes() { - return Collections.singleton("resources"); + return Collections.singleton("drawable"); } }); } })) ``` +Otherwise `SchemeHandler` must return an `InputStream` with proper `content-type` information +for further processing by a `MediaDecoder`: + +```java +imagesPlugin.addSchemeHandler(new SchemeHandler() { + @NonNull + @Override + public ImageItem handle(@NonNull String raw, @NonNull Uri uri) { + return ImageItem.withDecodingNeeded("image/png", load(raw)); + } + + @NonNull + private InputStream load(@NonNull String raw) {...} +}); +``` + +## MediaDecoder + +`ImagesPlugin` comes with predefined media-decoders: +* `GifMediaDecoder` adds support for GIF +* `SvgMediaDecoder` adds support for SVG +* `DefaultMediaDecoder` + +:::warning +If you wish to add support for **SVG** or **GIF** you must explicitly add these dependencies +to your project: +* for `SVG`: `com.caverock:androidsvg:1.4` +* for `GIF`: `pl.droidsonroids.gif:android-gif-drawable:1.2.14` + +You can try more recent versions of these libraries, but make sure that they doesn't +introduce any unexpected behavior. +::: + + +### GifMediaDecoder + +### SvgMediaDecoder + +### DefaultMediaDecoder + +## AsyncDrawableScheduler + +## ErrorHandler + +## Placeholder + :::tip If you are using [html](/docs/v4/html/) you do not have to additionally setup images displayed via `` tag, as `HtmlPlugin` automatically uses configured diff --git a/docs/docs/v4/linkify/README.md b/docs/docs/v4/linkify/README.md new file mode 100644 index 00000000..10a96b98 --- /dev/null +++ b/docs/docs/v4/linkify/README.md @@ -0,0 +1,3 @@ +# Linkify + + \ No newline at end of file diff --git a/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderBuilder.java b/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderBuilder.java index 704ebffb..24ce355a 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderBuilder.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderBuilder.java @@ -43,7 +43,7 @@ class AsyncDrawableLoaderBuilder { addMediaDecoder(GifMediaDecoder.create()); } - defaultMediaDecoder = DefaultImageMediaDecoder.create(); + defaultMediaDecoder = DefaultMediaDecoder.create(); } void executorService(@NonNull ExecutorService executorService) { diff --git a/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderImpl.java b/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderImpl.java index 4428177c..52afc7a3 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderImpl.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderImpl.java @@ -77,7 +77,7 @@ class AsyncDrawableLoaderImpl extends AsyncDrawableLoader { @NonNull private Future execute(@NonNull final AsyncDrawable asyncDrawable) { - // todo: more efficient DefaultImageMediaDecoder... BitmapFactory.decodeStream is a bit not optimal + // todo: more efficient DefaultMediaDecoder... BitmapFactory.decodeStream is a bit not optimal // for big images for sure. We _could_ introduce internal Drawable that will check for // image bounds (but we will need to cache inputStream in order to inspect and optimize // input image...) diff --git a/markwon-image/src/main/java/io/noties/markwon/image/DefaultImageMediaDecoder.java b/markwon-image/src/main/java/io/noties/markwon/image/DefaultMediaDecoder.java similarity index 79% rename from markwon-image/src/main/java/io/noties/markwon/image/DefaultImageMediaDecoder.java rename to markwon-image/src/main/java/io/noties/markwon/image/DefaultMediaDecoder.java index e820ff45..bdf81e05 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/DefaultImageMediaDecoder.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/DefaultMediaDecoder.java @@ -19,22 +19,22 @@ import java.util.Collections; * * @since 1.1.0 */ -public class DefaultImageMediaDecoder extends MediaDecoder { +public class DefaultMediaDecoder extends MediaDecoder { @NonNull - public static DefaultImageMediaDecoder create() { - return new DefaultImageMediaDecoder(Resources.getSystem()); + public static DefaultMediaDecoder create() { + return new DefaultMediaDecoder(Resources.getSystem()); } @NonNull - public static DefaultImageMediaDecoder create(@NonNull Resources resources) { - return new DefaultImageMediaDecoder(resources); + public static DefaultMediaDecoder create(@NonNull Resources resources) { + return new DefaultMediaDecoder(resources); } private final Resources resources; @SuppressWarnings("WeakerAccess") - DefaultImageMediaDecoder(Resources resources) { + DefaultMediaDecoder(Resources resources) { this.resources = resources; } diff --git a/markwon-image/src/main/java/io/noties/markwon/image/ImagesPlugin.java b/markwon-image/src/main/java/io/noties/markwon/image/ImagesPlugin.java index 8c02695e..d93ca23d 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/ImagesPlugin.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/ImagesPlugin.java @@ -111,7 +111,7 @@ public class ImagesPlugin extends AbstractMarkwonPlugin { } /** - * @see DefaultImageMediaDecoder + * @see DefaultMediaDecoder * @see SvgMediaDecoder * @see GifMediaDecoder * @since 4.0.0-SNAPSHOT @@ -123,10 +123,10 @@ public class ImagesPlugin extends AbstractMarkwonPlugin { } /** - * Please note that if not specified a {@link DefaultImageMediaDecoder} will be used. So + * Please note that if not specified a {@link DefaultMediaDecoder} will be used. So * if you need to disable default-image-media-decoder specify here own no-op implementation or null. * - * @see DefaultImageMediaDecoder + * @see DefaultMediaDecoder * @since 4.0.0-SNAPSHOT */ @NonNull From 5c78f1d51541f4eeaae2a0d5f20e0e635922213a Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Wed, 19 Jun 2019 00:28:22 +0300 Subject: [PATCH 26/42] Image, apply bounds for result drawable if empty --- .../noties/markwon/app/MarkdownRenderer.java | 29 ------------------- docs/docs/v4/image/README.md | 3 -- docs/docs/v4/migration-3-4.md | 3 ++ docs/docs/v4/recipes.md | 2 +- .../image/AsyncDrawableLoaderImpl.java | 6 ++++ .../markwon/image/DefaultMediaDecoder.java | 4 +-- .../markwon/image/gif/GifMediaDecoder.java | 2 -- .../markwon/image/svg/SvgMediaDecoder.java | 5 +--- 8 files changed, 12 insertions(+), 42 deletions(-) diff --git a/app/src/main/java/io/noties/markwon/app/MarkdownRenderer.java b/app/src/main/java/io/noties/markwon/app/MarkdownRenderer.java index 67585f85..9bcb8e0f 100644 --- a/app/src/main/java/io/noties/markwon/app/MarkdownRenderer.java +++ b/app/src/main/java/io/noties/markwon/app/MarkdownRenderer.java @@ -1,7 +1,6 @@ package io.noties.markwon.app; import android.content.Context; -import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Handler; import android.os.SystemClock; @@ -10,8 +9,6 @@ import android.text.Spanned; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import java.io.InputStream; -import java.util.Collection; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; @@ -26,10 +23,7 @@ import io.noties.markwon.ext.strikethrough.StrikethroughPlugin; import io.noties.markwon.ext.tables.TablePlugin; import io.noties.markwon.ext.tasklist.TaskListPlugin; import io.noties.markwon.html.HtmlPlugin; -import io.noties.markwon.image.ImageItem; import io.noties.markwon.image.ImagesPlugin; -import io.noties.markwon.image.MediaDecoder; -import io.noties.markwon.image.SchemeHandler; import io.noties.markwon.image.file.FileSchemeHandler; import io.noties.markwon.image.network.OkHttpNetworkSchemeHandler; import io.noties.markwon.syntax.Prism4jTheme; @@ -126,29 +120,6 @@ public class MarkdownRenderer { builder.urlProcessor(urlProcessor); } }) - .usePlugin(new AbstractMarkwonPlugin() { - @Override - public void configure(@NonNull Registry registry) { - registry.require(ImagesPlugin.class, new Action() { - @Override - public void apply(@NonNull ImagesPlugin imagesPlugin) { - imagesPlugin.addMediaDecoder(new MediaDecoder() { - @NonNull - @Override - public Drawable decode(@Nullable String contentType, @NonNull InputStream inputStream) { - return null; - } - - @NonNull - @Override - public Collection supportedTypes() { - return null; - } - }); - } - }); - } - }) .build(); final long start = SystemClock.uptimeMillis(); diff --git a/docs/docs/v4/image/README.md b/docs/docs/v4/image/README.md index b618f999..bee67c00 100644 --- a/docs/docs/v4/image/README.md +++ b/docs/docs/v4/image/README.md @@ -145,9 +145,6 @@ final Markwon markwon = Markwon.builder(context) // it's fine if it throws, async-image-loader will catch exception final Drawable drawable = context.getDrawable(resourceId); - // it's important to apply bounds to resulting drawable - DrawableUtils.applyIntrinsicBounds(drawable); - return ImageItem.withResult(drawable); } diff --git a/docs/docs/v4/migration-3-4.md b/docs/docs/v4/migration-3-4.md index 5537e1e2..f36cf75a 100644 --- a/docs/docs/v4/migration-3-4.md +++ b/docs/docs/v4/migration-3-4.md @@ -1,3 +1,6 @@ # Migration 3.x.x -> 4.x.x +* maven group-id is changed: `io.noties.markwon` (was `ru.noties.markwon`) +* root package-name is changed: `io.noties.markwon` (was `ru.noties.markwon`) + todo \ No newline at end of file diff --git a/docs/docs/v4/recipes.md b/docs/docs/v4/recipes.md index 46e9d86c..c9aad1cb 100644 --- a/docs/docs/v4/recipes.md +++ b/docs/docs/v4/recipes.md @@ -15,7 +15,7 @@ textView.setSpannableFactory(NoCopySpannableFactory.getInstance()); ## Autolink Do not use `autolink` XML attribute on your `TextView` as it will remove all links except autolinked ones. -Consider using [linkify plugin](/docs/v4/linkify.md) or commonmark-java [autolink extension](https://github.com/atlassian/commonmark-java) +Consider using [linkify plugin](/docs/v4/linkify/) or commonmark-java [autolink extension](https://github.com/atlassian/commonmark-java) diff --git a/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderImpl.java b/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderImpl.java index 52afc7a3..a88a69e1 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderImpl.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderImpl.java @@ -143,6 +143,12 @@ class AsyncDrawableLoaderImpl extends AsyncDrawableLoader { final Drawable out = drawable; + // @since 4.0.0-SNAPSHOT apply intrinsic bounds (but only if they are empty) + if (out != null + && out.getBounds().isEmpty()) { + DrawableUtils.applyIntrinsicBounds(out); + } + handler.postAtTime(new Runnable() { @Override public void run() { diff --git a/markwon-image/src/main/java/io/noties/markwon/image/DefaultMediaDecoder.java b/markwon-image/src/main/java/io/noties/markwon/image/DefaultMediaDecoder.java index bdf81e05..0fc18824 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/DefaultMediaDecoder.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/DefaultMediaDecoder.java @@ -50,9 +50,7 @@ public class DefaultMediaDecoder extends MediaDecoder { throw new IllegalStateException("Exception decoding input-stream", t); } - final Drawable drawable = new BitmapDrawable(resources, bitmap); - DrawableUtils.applyIntrinsicBounds(drawable); - return drawable; + return new BitmapDrawable(resources, bitmap); } @NonNull diff --git a/markwon-image/src/main/java/io/noties/markwon/image/gif/GifMediaDecoder.java b/markwon-image/src/main/java/io/noties/markwon/image/gif/GifMediaDecoder.java index 923fc113..479815f4 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/gif/GifMediaDecoder.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/gif/GifMediaDecoder.java @@ -65,8 +65,6 @@ public class GifMediaDecoder extends MediaDecoder { throw new IllegalStateException("Exception creating GifDrawable", e); } - DrawableUtils.applyIntrinsicBounds(drawable); - if (!autoPlayGif) { drawable.pause(); } diff --git a/markwon-image/src/main/java/io/noties/markwon/image/svg/SvgMediaDecoder.java b/markwon-image/src/main/java/io/noties/markwon/image/svg/SvgMediaDecoder.java index eb4cb74c..848cc82e 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/svg/SvgMediaDecoder.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/svg/SvgMediaDecoder.java @@ -16,7 +16,6 @@ import java.io.InputStream; import java.util.Collection; import java.util.Collections; -import io.noties.markwon.image.DrawableUtils; import io.noties.markwon.image.MediaDecoder; /** @@ -73,9 +72,7 @@ public class SvgMediaDecoder extends MediaDecoder { canvas.scale(density, density); svg.renderToCanvas(canvas); - final Drawable drawable = new BitmapDrawable(resources, bitmap); - DrawableUtils.applyIntrinsicBounds(drawable); - return drawable; + return new BitmapDrawable(resources, bitmap); } @NonNull From 6ed641fa4780fa7da7e766b426cec3c59d1c8b3b Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Thu, 20 Jun 2019 16:06:57 +0300 Subject: [PATCH 27/42] Fix j-latex-plugin background config --- .../markwon/ext/latex/JLatexMathPlugin.java | 22 ++++++++---- .../markwon/sample/latex/LatexActivity.java | 36 ++++++++++++++++++- 2 files changed, 51 insertions(+), 7 deletions(-) diff --git a/markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathPlugin.java b/markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathPlugin.java index 1eda8358..6c53d3fc 100644 --- a/markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathPlugin.java +++ b/markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathPlugin.java @@ -34,6 +34,14 @@ import ru.noties.jlatexmath.JLatexMathDrawable; */ public class JLatexMathPlugin extends AbstractMarkwonPlugin { + /** + * @since 4.0.0-SNAPSHOT + */ + public interface BackgroundProvider { + @NonNull + Drawable provide(); + } + public interface BuilderConfigure { void configureBuilder(@NonNull Builder builder); } @@ -64,7 +72,8 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin { private final float textSize; - private final Drawable background; + // @since 4.0.0-SNAPSHOT + private final BackgroundProvider backgroundProvider; @JLatexMathDrawable.Align private final int align; @@ -78,7 +87,7 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin { Config(@NonNull Builder builder) { this.textSize = builder.textSize; - this.background = builder.background; + this.backgroundProvider = builder.backgroundProvider; this.align = builder.align; this.fitCanvas = builder.fitCanvas; this.padding = builder.padding; @@ -149,7 +158,8 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin { private final float textSize; - private Drawable background; + // @since 4.0.0-SNAPSHOT + private BackgroundProvider backgroundProvider; @JLatexMathDrawable.Align private int align = JLatexMathDrawable.ALIGN_CENTER; @@ -166,8 +176,8 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin { } @NonNull - public Builder background(@NonNull Drawable background) { - this.background = background; + public Builder backgroundProvider(@NonNull BackgroundProvider backgroundProvider) { + this.backgroundProvider = backgroundProvider; return this; } @@ -236,7 +246,7 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin { final JLatexMathDrawable jLatexMathDrawable = JLatexMathDrawable.builder(drawable.getDestination()) .textSize(config.textSize) - .background(config.background) + .background(config.backgroundProvider.provide()) .align(config.align) .fitCanvas(config.fitCanvas) .padding(config.padding) diff --git a/sample/src/main/java/io/noties/markwon/sample/latex/LatexActivity.java b/sample/src/main/java/io/noties/markwon/sample/latex/LatexActivity.java index 2eea4fed..a3db9610 100644 --- a/sample/src/main/java/io/noties/markwon/sample/latex/LatexActivity.java +++ b/sample/src/main/java/io/noties/markwon/sample/latex/LatexActivity.java @@ -1,9 +1,12 @@ package io.noties.markwon.sample.latex; import android.app.Activity; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; import android.os.Bundle; import android.widget.TextView; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import io.noties.markwon.Markwon; @@ -44,9 +47,40 @@ public class LatexActivity extends Activity { final Markwon markwon = Markwon.builder(this) // .usePlugin(ImagesPlugin.create(this)) - .usePlugin(JLatexMathPlugin.create(textView.getTextSize())) + .usePlugin(JLatexMathPlugin.create(textView.getTextSize(), new JLatexMathPlugin.BuilderConfigure() { + @Override + public void configureBuilder(@NonNull JLatexMathPlugin.Builder builder) { + builder.backgroundProvider(new JLatexMathPlugin.BackgroundProvider() { + @NonNull + @Override + public Drawable provide() { + return new ColorDrawable(0x40ff0000); + } + }); + } + })) .build(); + if (true) { + final String l = "$$\n" + + " P(X=r)=\\frac{\\lambda^r e^{-\\lambda}}{r!}\n" + + "$$\n" + + "\n" + + "$$\n" + + " P(Xr)=1-P(X Date: Thu, 20 Jun 2019 16:19:43 +0300 Subject: [PATCH 28/42] Fix wrong fitCanvas config for JLatexMathPlugin --- .../markwon/ext/latex/JLatexMathPlugin.java | 38 +++++++++++++++++-- .../markwon/sample/latex/LatexActivity.java | 20 ++++++---- 2 files changed, 47 insertions(+), 11 deletions(-) diff --git a/markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathPlugin.java b/markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathPlugin.java index 6c53d3fc..9533f304 100644 --- a/markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathPlugin.java +++ b/markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathPlugin.java @@ -1,5 +1,6 @@ package io.noties.markwon.ext.latex; +import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.os.Handler; import android.os.Looper; @@ -27,6 +28,7 @@ import io.noties.markwon.image.AsyncDrawableLoader; import io.noties.markwon.image.AsyncDrawableScheduler; import io.noties.markwon.image.AsyncDrawableSpan; import io.noties.markwon.image.ImageSize; +import io.noties.markwon.image.ImageSizeResolver; import ru.noties.jlatexmath.JLatexMathDrawable; /** @@ -102,10 +104,12 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin { } private final JLatextAsyncDrawableLoader jLatextAsyncDrawableLoader; + private final JLatexImageSizeResolver jLatexImageSizeResolver; @SuppressWarnings("WeakerAccess") JLatexMathPlugin(@NonNull Config config) { this.jLatextAsyncDrawableLoader = new JLatextAsyncDrawableLoader(config); + this.jLatexImageSizeResolver = new JLatexImageSizeResolver(config.fitCanvas); } @Override @@ -132,10 +136,8 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin { new AsyncDrawable( latex, jLatextAsyncDrawableLoader, - configuration.imageSizeResolver(), - new ImageSize( - new ImageSize.Dimension(100, "%"), - null)), + jLatexImageSizeResolver, + null), AsyncDrawableSpan.ALIGN_BOTTOM, false); @@ -290,4 +292,32 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin { return null; } } + + // we must make drawable fit canvas (if specified), but do not keep the ratio whilst scaling up + // @since 4.0.0-SNAPSHOT + private static class JLatexImageSizeResolver extends ImageSizeResolver { + + private final boolean fitCanvas; + + JLatexImageSizeResolver(boolean fitCanvas) { + this.fitCanvas = fitCanvas; + } + + @NonNull + @Override + public Rect resolveImageSize( + @Nullable ImageSize imageSize, + @NonNull Rect imageBounds, + int canvasWidth, + float textSize) { + + if (fitCanvas + && imageBounds.width() < canvasWidth) { + // we increase only width (keep height as-is) + return new Rect(0, 0, canvasWidth, imageBounds.height()); + } + + return imageBounds; + } + } } diff --git a/sample/src/main/java/io/noties/markwon/sample/latex/LatexActivity.java b/sample/src/main/java/io/noties/markwon/sample/latex/LatexActivity.java index a3db9610..93c21e19 100644 --- a/sample/src/main/java/io/noties/markwon/sample/latex/LatexActivity.java +++ b/sample/src/main/java/io/noties/markwon/sample/latex/LatexActivity.java @@ -12,6 +12,7 @@ import androidx.annotation.Nullable; import io.noties.markwon.Markwon; import io.noties.markwon.ext.latex.JLatexMathPlugin; import io.noties.markwon.sample.R; +import ru.noties.jlatexmath.JLatexMathDrawable; public class LatexActivity extends Activity { @@ -50,13 +51,18 @@ public class LatexActivity extends Activity { .usePlugin(JLatexMathPlugin.create(textView.getTextSize(), new JLatexMathPlugin.BuilderConfigure() { @Override public void configureBuilder(@NonNull JLatexMathPlugin.Builder builder) { - builder.backgroundProvider(new JLatexMathPlugin.BackgroundProvider() { - @NonNull - @Override - public Drawable provide() { - return new ColorDrawable(0x40ff0000); - } - }); + builder + .backgroundProvider(new JLatexMathPlugin.BackgroundProvider() { + @NonNull + @Override + public Drawable provide() { + return new ColorDrawable(0x40ff0000); + } + }) + .fitCanvas(true) + .align(JLatexMathDrawable.ALIGN_LEFT) + .padding(48) + ; } })) .build(); From 4fec46fb4db65cce933210f5ab1a8104e6e8433d Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Fri, 21 Jun 2019 00:56:43 +0300 Subject: [PATCH 29/42] Fix async-drawable tests --- docs/docs/v4/ext-latex/README.md | 3 ++- .../noties/markwon/image/AsyncDrawableLoaderImpl.java | 11 ++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/docs/docs/v4/ext-latex/README.md b/docs/docs/v4/ext-latex/README.md index 4d57371f..bf8a9400 100644 --- a/docs/docs/v4/ext-latex/README.md +++ b/docs/docs/v4/ext-latex/README.md @@ -32,10 +32,11 @@ final Markwon markwon = Markwon.builder(context) @Override public void configureBuilder(@NonNull Builder builder) { builder - .background(backgroundDrawable) .align(JLatexMathDrawable.ALIGN_CENTER) .fitCanvas(true) .padding(paddingPx) + // @since 4.0.0 - change to provider + .backgroundProvider(() -> new MyDrawable())) // @since 4.0.0 - optional, by default cached-thread-pool will be used .executorService(Executors.newCachedThreadPool()); } diff --git a/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderImpl.java b/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderImpl.java index a88a69e1..e1b92d55 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderImpl.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderImpl.java @@ -1,5 +1,6 @@ package io.noties.markwon.image; +import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Handler; @@ -144,9 +145,13 @@ class AsyncDrawableLoaderImpl extends AsyncDrawableLoader { final Drawable out = drawable; // @since 4.0.0-SNAPSHOT apply intrinsic bounds (but only if they are empty) - if (out != null - && out.getBounds().isEmpty()) { - DrawableUtils.applyIntrinsicBounds(out); + if (out != null) { + final Rect bounds = out.getBounds(); + //noinspection ConstantConditions + if (bounds == null + || bounds.isEmpty()) { + DrawableUtils.applyIntrinsicBounds(out); + } } handler.postAtTime(new Runnable() { From 213f5cf281b642a0de5024ea6abdb8d2dbc53aed Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Sat, 22 Jun 2019 12:09:53 +0300 Subject: [PATCH 30/42] ImageSizeResolver change (accept async-drawable) --- _CHANGES.md | 4 +- .../noties/markwon/image/AsyncDrawable.java | 15 +++---- .../markwon/image/ImageSizeResolver.java | 16 +------ .../markwon/image/ImageSizeResolverDef.java | 11 ++++- .../markwon/ext/latex/JLatexMathPlugin.java | 44 ++++++++++++++----- 5 files changed, 54 insertions(+), 36 deletions(-) diff --git a/_CHANGES.md b/_CHANGES.md index e20c7985..5d98cd37 100644 --- a/_CHANGES.md +++ b/_CHANGES.md @@ -10,4 +10,6 @@ * removed MarkwonPlugin#configureHtmlRenderer -> now part of HtmlPlugin * TagHandler now has `supportedTags()` method * html is moved completely to html-plugin -* OnTextAddedListener \ No newline at end of file +* OnTextAddedListener +* ImageSizeResolver signature change (accept AsyncDrawable) +* JLatexMathPlugin builder has vertical & horizontal padding \ No newline at end of file diff --git a/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawable.java b/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawable.java index dfbf8d19..7eb4b38d 100644 --- a/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawable.java +++ b/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawable.java @@ -53,7 +53,7 @@ public class AsyncDrawable extends Drawable { } /** - * @since 3.1.0-SNAPSHOT + * @since 4.0.0-SNAPSHOT */ @Nullable public ImageSize getImageSize() { @@ -61,7 +61,7 @@ public class AsyncDrawable extends Drawable { } /** - * @since 3.1.0-SNAPSHOT + * @since 4.0.0-SNAPSHOT */ @NonNull public ImageSizeResolver getImageSizeResolver() { @@ -69,7 +69,7 @@ public class AsyncDrawable extends Drawable { } /** - * @since 3.1.0-SNAPSHOT + * @since 4.0.0-SNAPSHOT */ public boolean hasKnownDimentions() { return canvasWidth > 0; @@ -77,7 +77,7 @@ public class AsyncDrawable extends Drawable { /** * @see #hasKnownDimentions() - * @since 3.1.0-SNAPSHOT + * @since 4.0.0-SNAPSHOT */ public int getLastKnownCanvasWidth() { return canvasWidth; @@ -85,7 +85,7 @@ public class AsyncDrawable extends Drawable { /** * @see #hasKnownDimentions() - * @since 3.1.0-SNAPSHOT + * @since 4.0.0-SNAPSHOT */ public float getLastKnowTextSize() { return textSize; @@ -285,13 +285,10 @@ public class AsyncDrawable extends Drawable { */ @NonNull private Rect resolveBounds() { - // @since 2.0.0 previously we were checking if image is greater than canvas width here // but as imageSizeResolver won't be null anymore, we should transfer this logic // there - return imageSizeResolver != null - ? imageSizeResolver.resolveImageSize(imageSize, result.getBounds(), canvasWidth, textSize) - : result.getBounds(); + return imageSizeResolver.resolveImageSize(this); } @Override diff --git a/markwon-core/src/main/java/io/noties/markwon/image/ImageSizeResolver.java b/markwon-core/src/main/java/io/noties/markwon/image/ImageSizeResolver.java index 8542cac5..456afae0 100644 --- a/markwon-core/src/main/java/io/noties/markwon/image/ImageSizeResolver.java +++ b/markwon-core/src/main/java/io/noties/markwon/image/ImageSizeResolver.java @@ -3,7 +3,6 @@ package io.noties.markwon.image; import android.graphics.Rect; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; /** * @since 1.0.1 @@ -12,19 +11,8 @@ import androidx.annotation.Nullable; public abstract class ImageSizeResolver { /** - * We do not expose canvas height deliberately. As we cannot rely on this value very much - * - * @param imageSize {@link ImageSize} parsed from HTML - * @param imageBounds original image bounds - * @param canvasWidth width of the canvas - * @param textSize current font size - * @return resolved image bounds + * @since 4.0.0-SNAPSHOT */ @NonNull - public abstract Rect resolveImageSize( - @Nullable ImageSize imageSize, - @NonNull Rect imageBounds, - int canvasWidth, - float textSize - ); + public abstract Rect resolveImageSize(@NonNull AsyncDrawable drawable); } diff --git a/markwon-core/src/main/java/io/noties/markwon/image/ImageSizeResolverDef.java b/markwon-core/src/main/java/io/noties/markwon/image/ImageSizeResolverDef.java index 1135d271..52d6abac 100644 --- a/markwon-core/src/main/java/io/noties/markwon/image/ImageSizeResolverDef.java +++ b/markwon-core/src/main/java/io/noties/markwon/image/ImageSizeResolverDef.java @@ -17,7 +17,16 @@ public class ImageSizeResolverDef extends ImageSizeResolver { @NonNull @Override - public Rect resolveImageSize( + public Rect resolveImageSize(@NonNull AsyncDrawable drawable) { + return resolveImageSize( + drawable.getImageSize(), + drawable.getResult().getBounds(), + drawable.getLastKnownCanvasWidth(), + drawable.getLastKnowTextSize()); + } + + @NonNull + protected Rect resolveImageSize( @Nullable ImageSize imageSize, @NonNull Rect imageBounds, int canvasWidth, diff --git a/markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathPlugin.java b/markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathPlugin.java index 9533f304..8b7bce3e 100644 --- a/markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathPlugin.java +++ b/markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathPlugin.java @@ -27,7 +27,6 @@ import io.noties.markwon.image.AsyncDrawable; import io.noties.markwon.image.AsyncDrawableLoader; import io.noties.markwon.image.AsyncDrawableScheduler; import io.noties.markwon.image.AsyncDrawableSpan; -import io.noties.markwon.image.ImageSize; import io.noties.markwon.image.ImageSizeResolver; import ru.noties.jlatexmath.JLatexMathDrawable; @@ -82,7 +81,11 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin { private final boolean fitCanvas; - private final int padding; + // @since 4.0.0-SNAPSHOT + private final int paddingHorizontal; + // @since 4.0.0-SNAPSHOT + + private final int paddingVertical; // @since 4.0.0-SNAPSHOT private final ExecutorService executorService; @@ -92,7 +95,8 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin { this.backgroundProvider = builder.backgroundProvider; this.align = builder.align; this.fitCanvas = builder.fitCanvas; - this.padding = builder.padding; + this.paddingHorizontal = builder.paddingHorizontal; + this.paddingVertical = builder.paddingVertical; // @since 4.0.0-SNAPSHOT ExecutorService executorService = builder.executorService; @@ -168,7 +172,11 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin { private boolean fitCanvas = true; - private int padding; + // @since 4.0.0-SNAPSHOT + private int paddingHorizontal; + + // @since 4.0.0-SNAPSHOT + private int paddingVertical; // @since 4.0.0-SNAPSHOT private ExecutorService executorService; @@ -197,7 +205,18 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin { @NonNull public Builder padding(@Px int padding) { - this.padding = padding; + this.paddingHorizontal = padding; + this.paddingVertical = padding; + return this; + } + + /** + * @since 4.0.0-SNAPSHOT + */ + @NonNull + public Builder builder(@Px int paddingHorizontal, @Px int paddingVertical) { + this.paddingHorizontal = paddingHorizontal; + this.paddingVertical = paddingVertical; return this; } @@ -251,7 +270,11 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin { .background(config.backgroundProvider.provide()) .align(config.align) .fitCanvas(config.fitCanvas) - .padding(config.padding) + .padding( + config.paddingHorizontal, + config.paddingVertical, + config.paddingHorizontal, + config.paddingVertical) .build(); // we must post to handler, but also have a way to identify the drawable @@ -305,11 +328,10 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin { @NonNull @Override - public Rect resolveImageSize( - @Nullable ImageSize imageSize, - @NonNull Rect imageBounds, - int canvasWidth, - float textSize) { + public Rect resolveImageSize(@NonNull AsyncDrawable drawable) { + + final Rect imageBounds = drawable.getResult().getBounds(); + final int canvasWidth = drawable.getLastKnownCanvasWidth(); if (fitCanvas && imageBounds.width() < canvasWidth) { From ffb5848c3c95cb45dbffc2446b425902c213628f Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Sat, 22 Jun 2019 15:20:46 +0300 Subject: [PATCH 31/42] Moved LinkResolver to independent entity --- _CHANGES.md | 5 ++- .../java/io/noties/markwon/LinkResolver.java | 14 ++++++ .../io/noties/markwon/LinkResolverDef.java | 6 +-- .../noties/markwon/MarkwonConfiguration.java | 9 ++-- .../noties/markwon/core/spans/LinkSpan.java | 12 ++--- .../markwon/image/ImageSizeResolver.java | 3 +- .../image/ImageSizeResolverDefTest.java | 44 ++++++++++++++++++- markwon-linkify/README.md | 2 +- 8 files changed, 75 insertions(+), 20 deletions(-) create mode 100644 markwon-core/src/main/java/io/noties/markwon/LinkResolver.java diff --git a/_CHANGES.md b/_CHANGES.md index 5d98cd37..3cd3b21a 100644 --- a/_CHANGES.md +++ b/_CHANGES.md @@ -10,6 +10,7 @@ * removed MarkwonPlugin#configureHtmlRenderer -> now part of HtmlPlugin * TagHandler now has `supportedTags()` method * html is moved completely to html-plugin -* OnTextAddedListener +* OnTextAddedListener (CorePlugin) * ImageSizeResolver signature change (accept AsyncDrawable) -* JLatexMathPlugin builder has vertical & horizontal padding \ No newline at end of file +* JLatexMathPlugin builder has vertical & horizontal padding +* LinkResolver is now an independent entity (previously part of LinkSpan) \ No newline at end of file diff --git a/markwon-core/src/main/java/io/noties/markwon/LinkResolver.java b/markwon-core/src/main/java/io/noties/markwon/LinkResolver.java new file mode 100644 index 00000000..1a6c9010 --- /dev/null +++ b/markwon-core/src/main/java/io/noties/markwon/LinkResolver.java @@ -0,0 +1,14 @@ +package io.noties.markwon; + +import android.view.View; + +import androidx.annotation.NonNull; + +/** + * @see LinkResolverDef + * @see MarkwonConfiguration.Builder#linkResolver(LinkResolver) + * @since 4.0.0-SNAPSHOT + */ +public interface LinkResolver { + void resolve(@NonNull View view, @NonNull String link); +} diff --git a/markwon-core/src/main/java/io/noties/markwon/LinkResolverDef.java b/markwon-core/src/main/java/io/noties/markwon/LinkResolverDef.java index 0b9e30fb..999dcee5 100644 --- a/markwon-core/src/main/java/io/noties/markwon/LinkResolverDef.java +++ b/markwon-core/src/main/java/io/noties/markwon/LinkResolverDef.java @@ -10,11 +10,9 @@ import android.view.View; import androidx.annotation.NonNull; -import io.noties.markwon.core.spans.LinkSpan; - -public class LinkResolverDef implements LinkSpan.Resolver { +public class LinkResolverDef implements LinkResolver { @Override - public void resolve(View view, @NonNull String link) { + public void resolve(@NonNull View view, @NonNull String link) { final Uri uri = Uri.parse(link); final Context context = view.getContext(); final Intent intent = new Intent(Intent.ACTION_VIEW, uri); diff --git a/markwon-core/src/main/java/io/noties/markwon/MarkwonConfiguration.java b/markwon-core/src/main/java/io/noties/markwon/MarkwonConfiguration.java index c7f0f04d..b911e945 100644 --- a/markwon-core/src/main/java/io/noties/markwon/MarkwonConfiguration.java +++ b/markwon-core/src/main/java/io/noties/markwon/MarkwonConfiguration.java @@ -3,7 +3,6 @@ package io.noties.markwon; import androidx.annotation.NonNull; import io.noties.markwon.core.MarkwonTheme; -import io.noties.markwon.core.spans.LinkSpan; import io.noties.markwon.image.AsyncDrawableLoader; import io.noties.markwon.image.ImageSizeResolver; import io.noties.markwon.image.ImageSizeResolverDef; @@ -26,7 +25,7 @@ public class MarkwonConfiguration { private final MarkwonTheme theme; private final AsyncDrawableLoader asyncDrawableLoader; private final SyntaxHighlight syntaxHighlight; - private final LinkSpan.Resolver linkResolver; + private final LinkResolver linkResolver; private final UrlProcessor urlProcessor; private final ImageSizeResolver imageSizeResolver; @@ -59,7 +58,7 @@ public class MarkwonConfiguration { } @NonNull - public LinkSpan.Resolver linkResolver() { + public LinkResolver linkResolver() { return linkResolver; } @@ -87,7 +86,7 @@ public class MarkwonConfiguration { private MarkwonTheme theme; private AsyncDrawableLoader asyncDrawableLoader; private SyntaxHighlight syntaxHighlight; - private LinkSpan.Resolver linkResolver; + private LinkResolver linkResolver; private UrlProcessor urlProcessor; private ImageSizeResolver imageSizeResolver; private MarkwonSpansFactory spansFactory; @@ -111,7 +110,7 @@ public class MarkwonConfiguration { } @NonNull - public Builder linkResolver(@NonNull LinkSpan.Resolver linkResolver) { + public Builder linkResolver(@NonNull LinkResolver linkResolver) { this.linkResolver = linkResolver; return this; } diff --git a/markwon-core/src/main/java/io/noties/markwon/core/spans/LinkSpan.java b/markwon-core/src/main/java/io/noties/markwon/core/spans/LinkSpan.java index 4bcbfd11..f8483423 100644 --- a/markwon-core/src/main/java/io/noties/markwon/core/spans/LinkSpan.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/spans/LinkSpan.java @@ -6,19 +6,19 @@ import android.view.View; import androidx.annotation.NonNull; +import io.noties.markwon.LinkResolver; import io.noties.markwon.core.MarkwonTheme; public class LinkSpan extends URLSpan { - public interface Resolver { - void resolve(View view, @NonNull String link); - } - private final MarkwonTheme theme; private final String link; - private final Resolver resolver; + private final LinkResolver resolver; - public LinkSpan(@NonNull MarkwonTheme theme, @NonNull String link, @NonNull Resolver resolver) { + public LinkSpan( + @NonNull MarkwonTheme theme, + @NonNull String link, + @NonNull LinkResolver resolver) { super(link); this.theme = theme; this.link = link; diff --git a/markwon-core/src/main/java/io/noties/markwon/image/ImageSizeResolver.java b/markwon-core/src/main/java/io/noties/markwon/image/ImageSizeResolver.java index 456afae0..ecd7bbcb 100644 --- a/markwon-core/src/main/java/io/noties/markwon/image/ImageSizeResolver.java +++ b/markwon-core/src/main/java/io/noties/markwon/image/ImageSizeResolver.java @@ -5,9 +5,10 @@ import android.graphics.Rect; import androidx.annotation.NonNull; /** + * @see ImageSizeResolverDef + * @see io.noties.markwon.MarkwonConfiguration.Builder#imageSizeResolver(ImageSizeResolver) * @since 1.0.1 */ -@SuppressWarnings({"WeakerAccess", "unused"}) public abstract class ImageSizeResolver { /** diff --git a/markwon-core/src/test/java/io/noties/markwon/image/ImageSizeResolverDefTest.java b/markwon-core/src/test/java/io/noties/markwon/image/ImageSizeResolverDefTest.java index 33280b03..5030986c 100644 --- a/markwon-core/src/test/java/io/noties/markwon/image/ImageSizeResolverDefTest.java +++ b/markwon-core/src/test/java/io/noties/markwon/image/ImageSizeResolverDefTest.java @@ -1,16 +1,22 @@ package io.noties.markwon.image; import android.graphics.Rect; +import android.graphics.drawable.Drawable; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -import static org.junit.Assert.assertEquals; import static io.noties.markwon.image.ImageSizeResolverDef.UNIT_EM; import static io.noties.markwon.image.ImageSizeResolverDef.UNIT_PERCENT; +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; @RunWith(RobolectricTestRunner.class) @Config(manifest = Config.NONE) @@ -23,6 +29,42 @@ public class ImageSizeResolverDefTest { def = new ImageSizeResolverDef(); } + @Test + public void correct_redirect() { + // @since 4.0.0-SNAPSHOT the main method is changed to accept AsyncDrawable + + final ImageSizeResolverDef def = mock(ImageSizeResolverDef.class, Mockito.CALLS_REAL_METHODS); + final AsyncDrawable drawable = mock(AsyncDrawable.class); + + final ImageSize imageSize = mock(ImageSize.class); + final Drawable result = mock(Drawable.class); + final Rect rect = mock(Rect.class); + when(result.getBounds()).thenReturn(rect); + + when(drawable.getImageSize()).thenReturn(imageSize); + when(drawable.getResult()).thenReturn(result); + when(drawable.getLastKnownCanvasWidth()).thenReturn(111); + when(drawable.getLastKnowTextSize()).thenReturn(24.0F); + + def.resolveImageSize(drawable); + + final ArgumentCaptor imageSizeArgumentCaptor = ArgumentCaptor.forClass(ImageSize.class); + final ArgumentCaptor rectArgumentCaptor = ArgumentCaptor.forClass(Rect.class); + final ArgumentCaptor integerArgumentCaptor = ArgumentCaptor.forClass(Integer.class); + final ArgumentCaptor floatArgumentCaptor = ArgumentCaptor.forClass(Float.class); + + verify(def).resolveImageSize( + imageSizeArgumentCaptor.capture(), + rectArgumentCaptor.capture(), + integerArgumentCaptor.capture(), + floatArgumentCaptor.capture()); + + assertEquals(imageSize, imageSizeArgumentCaptor.getValue()); + assertEquals(rect, rectArgumentCaptor.getValue()); + assertEquals((Integer) 111, integerArgumentCaptor.getValue()); + assertEquals((Float) 24.0F, floatArgumentCaptor.getValue()); + } + @Test public void no_image_size() { // no image size returns image original bounds diff --git a/markwon-linkify/README.md b/markwon-linkify/README.md index ccc0c08e..e57f87ca 100644 --- a/markwon-linkify/README.md +++ b/markwon-linkify/README.md @@ -6,4 +6,4 @@ existing links and keep only the ones it creates. Please note that usage of this plugin introduces significant performance drop due to not optimal implementation of underlying `android.text.util.Linkify`. If you have any ideas of how -to improve this - PR are welcome! \ No newline at end of file +to improve this - PRs are welcome! \ No newline at end of file From fdb0f76e13740244ab852503c067607a6e7978c7 Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Mon, 24 Jun 2019 13:47:44 +0300 Subject: [PATCH 32/42] Add html sample --- docs/docs/v4/core/configuration.md | 29 ++- docs/docs/v4/ext-latex/README.md | 2 + docs/docs/v4/html/README.md | 128 ++++++++++++ sample/src/main/AndroidManifest.xml | 1 + .../noties/markwon/sample/MainActivity.java | 5 + .../java/io/noties/markwon/sample/Sample.java | 2 +- .../markwon/sample/html/HtmlActivity.java | 190 ++++++++++++++++++ .../src/main/res/values/strings-samples.xml | 2 + 8 files changed, 341 insertions(+), 18 deletions(-) create mode 100644 sample/src/main/java/io/noties/markwon/sample/html/HtmlActivity.java diff --git a/docs/docs/v4/core/configuration.md b/docs/docs/v4/core/configuration.md index 4c4ad645..23a32fb0 100644 --- a/docs/docs/v4/core/configuration.md +++ b/docs/docs/v4/core/configuration.md @@ -4,7 +4,7 @@ These are _configurable_ properties: * `AsyncDrawableLoader` (back here since ) * `SyntaxHighlight` -* `LinkSpan.Resolver` +* `LinkResolver` (since , before — `LinkSpan.Resolver`) * `UrlProcessor` * `ImageSizeResolver` @@ -37,9 +37,9 @@ final Markwon markwon = Markwon.builder(context) ``` Currently `Markwon` provides 3 implementations for loading images: -* [own implementation](/docs/v4/image.md) with SVG, GIF, data uri and android_assets support -* [based on Picasso](/docs/v4/image-picasso.md) -* [based on Glide](/docs/v4/image-glide.md) +* [markwon implementation](/docs/v4/image/) with SVG, GIF, data uri and android_assets support +* [based on Picasso](/docs/v4/image-picasso/) +* [based on Glide](/docs/v4/image-glide/) ## SyntaxHighlight @@ -59,7 +59,7 @@ Use [syntax-highlight](/docs/v4/syntax-highlight/) to add syntax highlighting to your application ::: -## LinkSpan.Resolver +## LinkResolver React to a link click event. By default `LinkResolverDef` is used, which tries to start an Activity given the `link` argument. If no @@ -70,9 +70,9 @@ final Markwon markwon = Markwon.builder(this) .usePlugin(new AbstractMarkwonPlugin() { @Override public void configureConfiguration(@NonNull MarkwonConfiguration.Builder builder) { - builder.linkResolver(new LinkSpan.Resolver() { + builder.linkResolver(new LinkResolver() { @Override - public void resolve(View view, @NonNull String link) { + public void resolve(@NonNull View view, @NonNull String link) { // react to link click here } }); @@ -119,8 +119,7 @@ will be kept as-is. ## ImageSizeResolver -`ImageSizeResolver` controls the size of an image to be displayed. Currently it -handles only HTML images (specified via `img` tag). +`ImageSizeResolver` controls the size of an image to be displayed. ```java final Markwon markwon = Markwon.builder(this) @@ -130,12 +129,9 @@ final Markwon markwon = Markwon.builder(this) builder.imageSizeResolver(new ImageSizeResolver() { @NonNull @Override - public Rect resolveImageSize( - @Nullable ImageSize imageSize, - @NonNull Rect imageBounds, - int canvasWidth, - float textSize) { - return null; + public Rect resolveImageSize(@NonNull AsyncDrawable drawable) { + final ImageSize imageSize = drawable.getImageSize(); + return drawable.getResult().getBounds(); } }); } @@ -168,6 +164,5 @@ so we will have no point-of-reference from which to _calculate_ image height. `ImageSizeResolverDef` also takes care for an image to **not** exceed canvas width. If an image has greater width than a TextView Canvas, then image will be _scaled-down_ to fit the canvas. Please note that this rule -applies only if image has no absolute sizes (for example width is specified -in pixels). +applies only if image has no sizes specified (`ImageSize == null`). ::: \ No newline at end of file diff --git a/docs/docs/v4/ext-latex/README.md b/docs/docs/v4/ext-latex/README.md index bf8a9400..16fde085 100644 --- a/docs/docs/v4/ext-latex/README.md +++ b/docs/docs/v4/ext-latex/README.md @@ -35,6 +35,8 @@ final Markwon markwon = Markwon.builder(context) .align(JLatexMathDrawable.ALIGN_CENTER) .fitCanvas(true) .padding(paddingPx) + // @since 4.0.0 - horizontal and vertical padding + .padding(paddingHorizontalPx, paddingVerticalPx) // @since 4.0.0 - change to provider .backgroundProvider(() -> new MyDrawable())) // @since 4.0.0 - optional, by default cached-thread-pool will be used diff --git a/docs/docs/v4/html/README.md b/docs/docs/v4/html/README.md index 44b95c54..cbba91d6 100644 --- a/docs/docs/v4/html/README.md +++ b/docs/docs/v4/html/README.md @@ -104,4 +104,132 @@ If you wish to exclude some of them `TagHandlerNoOp` can be used: ## TagHandler +To define a tag-handler that applies style for the whole tag content (from start to end), +a `SimpleTagHandler` can be used. For example, let's define `` tag, which can be used +like this: +* `centered text` +* `this should be aligned at the end (right for LTR locales)` +* `regular alignment` + +```java +public class AlignTagHandler extends SimpleTagHandler { + + @Nullable + @Override + public Object getSpans( + @NonNull MarkwonConfiguration configuration, + @NonNull RenderProps renderProps, + @NonNull HtmlTag tag) { + + final Layout.Alignment alignment; + + // html attribute without value, + if (tag.attributes().containsKey("center")) { + alignment = Layout.Alignment.ALIGN_CENTER; + } else if (tag.attributes().containsKey("end")) { + alignment = Layout.Alignment.ALIGN_OPPOSITE; + } else { + // empty value or any other will make regular alignment + alignment = Layout.Alignment.ALIGN_NORMAL; + } + + return new AlignmentSpan.Standard(alignment); + } + + @NonNull + @Override + public Collection supportedTags() { + return Collections.singleton("align"); + } +} +``` + +:::tip +`SimpleTagHandler` can return an array of spans from `getSpans` method +::: + +Then register `AlignTagHandler`: + +```java +final Markwon markwon = Markwon.builder(this) + .usePlugin(HtmlPlugin.create()) + .usePlugin(new AbstractMarkwonPlugin() { + @Override + public void configure(@NonNull Registry registry) { + registry.require(HtmlPlugin.class, htmlPlugin -> htmlPlugin + .addHandler(new AlignTagHandler()); + } + }) + .build(); +``` + +or directly on `HtmlPlugin`: + +```java +final Markwon markwon = Markwon.builder(this) + .usePlugin(HtmlPlugin.create(plugin -> plugin.addHandler(new AlignTagHandler()))) + .build(); +``` + +--- + +If a tag requires special handling `TagHandler` can be used directly. For example +let's define an `` tag with `start` and `end` arguments, that will mark +start and end positions of the text that needs to be enlarged: + +```html +This is text that must be enhanced, at least a part of it +``` + + +```java +public class EnhanceTagHandler extends TagHandler { + + private final int enhanceTextSize; + + EnhanceTagHandler(@Px int enhanceTextSize) { + this.enhanceTextSize = enhanceTextSize; + } + + @Override + public void handle( + @NonNull MarkwonVisitor visitor, + @NonNull MarkwonHtmlRenderer renderer, + @NonNull HtmlTag tag) { + + // we require start and end to be present + final int start = parsePosition(tag.attributes().get("start")); + final int end = parsePosition(tag.attributes().get("end")); + + if (start > -1 && end > -1) { + visitor.builder().setSpan( + new AbsoluteSizeSpan(enhanceTextSize), + tag.start() + start, + tag.start() + end + ); + } + } + + @NonNull + @Override + public Collection supportedTags() { + return Collections.singleton("enhance"); + } + + private static int parsePosition(@Nullable String value) { + int position; + if (!TextUtils.isEmpty(value)) { + try { + position = Integer.parseInt(value); + } catch (NumberFormatException e) { + e.printStackTrace(); + position = -1; + } + } else { + position = -1; + } + return position; + } +} +``` \ No newline at end of file diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml index a26c6d72..22ebc86b 100644 --- a/sample/src/main/AndroidManifest.xml +++ b/sample/src/main/AndroidManifest.xml @@ -24,6 +24,7 @@ + diff --git a/sample/src/main/java/io/noties/markwon/sample/MainActivity.java b/sample/src/main/java/io/noties/markwon/sample/MainActivity.java index a7805f52..8c197ea7 100644 --- a/sample/src/main/java/io/noties/markwon/sample/MainActivity.java +++ b/sample/src/main/java/io/noties/markwon/sample/MainActivity.java @@ -21,6 +21,7 @@ import io.noties.markwon.Markwon; import io.noties.markwon.sample.basicplugins.BasicPluginsActivity; import io.noties.markwon.sample.core.CoreActivity; import io.noties.markwon.sample.customextension.CustomExtensionActivity; +import io.noties.markwon.sample.html.HtmlActivity; import io.noties.markwon.sample.latex.LatexActivity; import io.noties.markwon.sample.recycler.RecyclerActivity; @@ -97,6 +98,10 @@ public class MainActivity extends Activity { activity = RecyclerActivity.class; break; + case HTML: + activity = HtmlActivity.class; + break; + default: throw new IllegalStateException("No Activity is associated with sample-item: " + item); } diff --git a/sample/src/main/java/io/noties/markwon/sample/Sample.java b/sample/src/main/java/io/noties/markwon/sample/Sample.java index 459ef4c8..03160a35 100644 --- a/sample/src/main/java/io/noties/markwon/sample/Sample.java +++ b/sample/src/main/java/io/noties/markwon/sample/Sample.java @@ -15,7 +15,7 @@ public enum Sample { RECYCLER(R.string.sample_recycler), - ; + HTML(R.string.sample_html); private final int textResId; diff --git a/sample/src/main/java/io/noties/markwon/sample/html/HtmlActivity.java b/sample/src/main/java/io/noties/markwon/sample/html/HtmlActivity.java new file mode 100644 index 00000000..21613985 --- /dev/null +++ b/sample/src/main/java/io/noties/markwon/sample/html/HtmlActivity.java @@ -0,0 +1,190 @@ +package io.noties.markwon.sample.html; + +import android.app.Activity; +import android.os.Bundle; +import android.text.Layout; +import android.text.TextUtils; +import android.text.style.AbsoluteSizeSpan; +import android.text.style.AlignmentSpan; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.Px; + +import java.util.Collection; +import java.util.Collections; +import java.util.Random; + +import io.noties.markwon.AbstractMarkwonPlugin; +import io.noties.markwon.Markwon; +import io.noties.markwon.MarkwonConfiguration; +import io.noties.markwon.MarkwonVisitor; +import io.noties.markwon.RenderProps; +import io.noties.markwon.SpannableBuilder; +import io.noties.markwon.html.HtmlPlugin; +import io.noties.markwon.html.HtmlTag; +import io.noties.markwon.html.MarkwonHtmlRenderer; +import io.noties.markwon.html.TagHandler; +import io.noties.markwon.html.tag.SimpleTagHandler; +import io.noties.markwon.sample.R; + +public class HtmlActivity extends Activity { + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.activity_text_view); + + // let's define some custom tag-handlers + + final TextView textView = findViewById(R.id.text_view); + + final Markwon markwon = Markwon.builder(this) + .usePlugin(HtmlPlugin.create()) + .usePlugin(new AbstractMarkwonPlugin() { + @Override + public void configure(@NonNull Registry registry) { + registry.require(HtmlPlugin.class, htmlPlugin -> htmlPlugin + .addHandler(new AlignTagHandler()) + .addHandler(new RandomCharSize(new Random(42L), textView.getTextSize())) + .addHandler(new EnhanceTagHandler((int) (textView.getTextSize() * 2 + .05F)))); + } + }) + .build(); + + final String markdown = "# Hello, HTML\n" + + "\n" + + "We are centered\n" + + "\n" + + "We are at the end\n" + + "\n" + + "We should be at the start\n" + + "\n" + + "\n" + + "This message should have a jumpy feeling because of different sizes of characters\n" + + "\n\n" + + "This is text that must be enhanced, at least a part of it"; + + markwon.setMarkdown(textView, markdown); + } + + // we can use `SimpleTagHandler` for _simple_ cases (when the whole tag content + // will have spans from start to end) + // + // we can use any tag name, even not defined in HTML spec + private static class AlignTagHandler extends SimpleTagHandler { + + @Nullable + @Override + public Object getSpans( + @NonNull MarkwonConfiguration configuration, + @NonNull RenderProps renderProps, + @NonNull HtmlTag tag) { + + final Layout.Alignment alignment; + + // html attribute without value, + if (tag.attributes().containsKey("center")) { + alignment = Layout.Alignment.ALIGN_CENTER; + } else if (tag.attributes().containsKey("end")) { + alignment = Layout.Alignment.ALIGN_OPPOSITE; + } else { + // empty value or any other will make regular alignment + alignment = Layout.Alignment.ALIGN_NORMAL; + } + + return new AlignmentSpan.Standard(alignment); + } + + @NonNull + @Override + public Collection supportedTags() { + return Collections.singleton("align"); + } + } + + // each character will have random size + private static class RandomCharSize extends TagHandler { + + private final Random random; + private final float base; + + RandomCharSize(@NonNull Random random, float base) { + this.random = random; + this.base = base; + } + + @Override + public void handle( + @NonNull MarkwonVisitor visitor, + @NonNull MarkwonHtmlRenderer renderer, + @NonNull HtmlTag tag) { + + final SpannableBuilder builder = visitor.builder(); + + // text content is already added, we should only apply spans + + for (int i = tag.start(), end = tag.end(); i < end; i++) { + final int size = (int) (base * (random.nextFloat() + 0.5F) + 0.5F); + builder.setSpan(new AbsoluteSizeSpan(size, false), i, i + 1); + } + } + + @NonNull + @Override + public Collection supportedTags() { + return Collections.singleton("random-char-size"); + } + } + + private static class EnhanceTagHandler extends TagHandler { + + private final int enhanceTextSize; + + EnhanceTagHandler(@Px int enhanceTextSize) { + this.enhanceTextSize = enhanceTextSize; + } + + @Override + public void handle( + @NonNull MarkwonVisitor visitor, + @NonNull MarkwonHtmlRenderer renderer, + @NonNull HtmlTag tag) { + + // we require start and end to be present + final int start = parsePosition(tag.attributes().get("start")); + final int end = parsePosition(tag.attributes().get("end")); + + if (start > -1 && end > -1) { + visitor.builder().setSpan( + new AbsoluteSizeSpan(enhanceTextSize), + tag.start() + start, + tag.start() + end + ); + } + } + + @NonNull + @Override + public Collection supportedTags() { + return Collections.singleton("enhance"); + } + + private static int parsePosition(@Nullable String value) { + int position; + if (!TextUtils.isEmpty(value)) { + try { + position = Integer.parseInt(value); + } catch (NumberFormatException e) { + e.printStackTrace(); + position = -1; + } + } else { + position = -1; + } + return position; + } + } +} diff --git a/sample/src/main/res/values/strings-samples.xml b/sample/src/main/res/values/strings-samples.xml index 43de11d1..24cab950 100644 --- a/sample/src/main/res/values/strings-samples.xml +++ b/sample/src/main/res/values/strings-samples.xml @@ -15,4 +15,6 @@ # \# Recycler\n\nShow how to render markdown in a RecyclerView. Renders code blocks wrapped in a HorizontalScrollView. Renders tables in a custom view. + # \# Html\n\nShows how to define own tag handlers + \ No newline at end of file From a082e9ed440d2c4bedaa31551cc4416bca1d0424 Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Mon, 24 Jun 2019 14:35:50 +0300 Subject: [PATCH 33/42] Add simple-ext module --- markwon-simple-ext/build.gradle | 27 ++++++ markwon-simple-ext/gradle.properties | 4 + .../src/main/AndroidManifest.xml | 1 + .../markwon/simple/ext/SimpleExtBuilder.java | 64 ++++++++++++++ .../ext/SimpleExtDelimiterProcessor.java | 70 +++++++++++++++ .../markwon/simple/ext/SimpleExtNode.java | 28 ++++++ .../markwon/simple/ext/SimpleExtPlugin.java | 85 +++++++++++++++++++ sample/build.gradle | 1 + sample/src/main/AndroidManifest.xml | 1 + .../noties/markwon/sample/MainActivity.java | 5 ++ .../java/io/noties/markwon/sample/Sample.java | 4 +- .../sample/simpleext/SimpleExtActivity.java | 43 ++++++++++ .../src/main/res/values/strings-samples.xml | 3 + settings.gradle | 1 + 14 files changed, 336 insertions(+), 1 deletion(-) create mode 100644 markwon-simple-ext/build.gradle create mode 100644 markwon-simple-ext/gradle.properties create mode 100644 markwon-simple-ext/src/main/AndroidManifest.xml create mode 100644 markwon-simple-ext/src/main/java/io/noties/markwon/simple/ext/SimpleExtBuilder.java create mode 100644 markwon-simple-ext/src/main/java/io/noties/markwon/simple/ext/SimpleExtDelimiterProcessor.java create mode 100644 markwon-simple-ext/src/main/java/io/noties/markwon/simple/ext/SimpleExtNode.java create mode 100644 markwon-simple-ext/src/main/java/io/noties/markwon/simple/ext/SimpleExtPlugin.java create mode 100644 sample/src/main/java/io/noties/markwon/sample/simpleext/SimpleExtActivity.java diff --git a/markwon-simple-ext/build.gradle b/markwon-simple-ext/build.gradle new file mode 100644 index 00000000..39dc63da --- /dev/null +++ b/markwon-simple-ext/build.gradle @@ -0,0 +1,27 @@ +apply plugin: 'com.android.library' + +android { + + compileSdkVersion config['compile-sdk'] + buildToolsVersion config['build-tools'] + + defaultConfig { + minSdkVersion config['min-sdk'] + targetSdkVersion config['target-sdk'] + versionCode 1 + versionName version + } +} + +dependencies { + + api project(':markwon-core') + + deps['test'].with { + testImplementation it['junit'] + testImplementation it['robolectric'] + testImplementation it['mockito'] + } +} + +registerArtifact(this) \ No newline at end of file diff --git a/markwon-simple-ext/gradle.properties b/markwon-simple-ext/gradle.properties new file mode 100644 index 00000000..2e2ad8d5 --- /dev/null +++ b/markwon-simple-ext/gradle.properties @@ -0,0 +1,4 @@ +POM_NAME=Simple Extension +POM_ARTIFACT_ID=simple-ext +POM_DESCRIPTION=Custom extension based on simple delimiter usage +POM_PACKAGING=aar \ No newline at end of file diff --git a/markwon-simple-ext/src/main/AndroidManifest.xml b/markwon-simple-ext/src/main/AndroidManifest.xml new file mode 100644 index 00000000..26f87af2 --- /dev/null +++ b/markwon-simple-ext/src/main/AndroidManifest.xml @@ -0,0 +1 @@ + diff --git a/markwon-simple-ext/src/main/java/io/noties/markwon/simple/ext/SimpleExtBuilder.java b/markwon-simple-ext/src/main/java/io/noties/markwon/simple/ext/SimpleExtBuilder.java new file mode 100644 index 00000000..10d0ed95 --- /dev/null +++ b/markwon-simple-ext/src/main/java/io/noties/markwon/simple/ext/SimpleExtBuilder.java @@ -0,0 +1,64 @@ +package io.noties.markwon.simple.ext; + +import androidx.annotation.NonNull; + +import org.commonmark.parser.delimiter.DelimiterProcessor; + +import java.util.ArrayList; +import java.util.List; + +import io.noties.markwon.SpanFactory; + +// @since 4.0.0-SNAPSHOT +class SimpleExtBuilder { + + private final List extensions = new ArrayList<>(2); + + private boolean isBuilt; + + void addExtension( + int length, + char character, + @NonNull SpanFactory spanFactory) { + + checkState(); + + extensions.add(new SimpleExtDelimiterProcessor( + character, + character, + length, + spanFactory)); + } + + void addExtension( + int length, + char openingCharacter, + char closingCharacter, + @NonNull SpanFactory spanFactory) { + + checkState(); + + extensions.add(new SimpleExtDelimiterProcessor( + openingCharacter, + closingCharacter, + length, + spanFactory)); + } + + @NonNull + List build() { + + checkState(); + + isBuilt = true; + + return extensions; + } + + private void checkState() { + if (isBuilt) { + throw new IllegalStateException("SimpleExtBuilder is already built, " + + "do not mutate SimpleExtPlugin after configuration is finished"); + } + } +} diff --git a/markwon-simple-ext/src/main/java/io/noties/markwon/simple/ext/SimpleExtDelimiterProcessor.java b/markwon-simple-ext/src/main/java/io/noties/markwon/simple/ext/SimpleExtDelimiterProcessor.java new file mode 100644 index 00000000..5cde82fe --- /dev/null +++ b/markwon-simple-ext/src/main/java/io/noties/markwon/simple/ext/SimpleExtDelimiterProcessor.java @@ -0,0 +1,70 @@ +package io.noties.markwon.simple.ext; + +import androidx.annotation.NonNull; + +import org.commonmark.node.Node; +import org.commonmark.node.Text; +import org.commonmark.parser.delimiter.DelimiterProcessor; +import org.commonmark.parser.delimiter.DelimiterRun; + +import io.noties.markwon.SpanFactory; + +// @since 4.0.0-SNAPSHOT +class SimpleExtDelimiterProcessor implements DelimiterProcessor { + + private final char open; + private final char close; + private final int length; + private final SpanFactory spanFactory; + + SimpleExtDelimiterProcessor( + char open, + char close, + int length, + @NonNull SpanFactory spanFactory) { + this.open = open; + this.close = close; + this.length = length; + this.spanFactory = spanFactory; + } + + @Override + public char getOpeningCharacter() { + return open; + } + + @Override + public char getClosingCharacter() { + return close; + } + + @Override + public int getMinLength() { + return length; + } + + @Override + public int getDelimiterUse(DelimiterRun opener, DelimiterRun closer) { + if (opener.length() >= length && closer.length() >= length) { + return length; + } + return 0; + } + + @Override + public void process(Text opener, Text closer, int delimiterUse) { + + final Node node = new SimpleExtNode(spanFactory); + + Node tmp = opener.getNext(); + Node next; + + while (tmp != null && tmp != closer) { + next = tmp.getNext(); + node.appendChild(tmp); + tmp = next; + } + + opener.insertAfter(node); + } +} diff --git a/markwon-simple-ext/src/main/java/io/noties/markwon/simple/ext/SimpleExtNode.java b/markwon-simple-ext/src/main/java/io/noties/markwon/simple/ext/SimpleExtNode.java new file mode 100644 index 00000000..d43855e2 --- /dev/null +++ b/markwon-simple-ext/src/main/java/io/noties/markwon/simple/ext/SimpleExtNode.java @@ -0,0 +1,28 @@ +package io.noties.markwon.simple.ext; + +import androidx.annotation.NonNull; + +import org.commonmark.node.CustomNode; +import org.commonmark.node.Visitor; + +import io.noties.markwon.SpanFactory; + +// @since 4.0.0-SNAPSHOT +class SimpleExtNode extends CustomNode { + + private final SpanFactory spanFactory; + + SimpleExtNode(@NonNull SpanFactory spanFactory) { + this.spanFactory = spanFactory; + } + + @Override + public void accept(Visitor visitor) { + visitor.visit(this); + } + + @NonNull + SpanFactory spanFactory() { + return spanFactory; + } +} diff --git a/markwon-simple-ext/src/main/java/io/noties/markwon/simple/ext/SimpleExtPlugin.java b/markwon-simple-ext/src/main/java/io/noties/markwon/simple/ext/SimpleExtPlugin.java new file mode 100644 index 00000000..48e90359 --- /dev/null +++ b/markwon-simple-ext/src/main/java/io/noties/markwon/simple/ext/SimpleExtPlugin.java @@ -0,0 +1,85 @@ +package io.noties.markwon.simple.ext; + +import androidx.annotation.NonNull; + +import org.commonmark.parser.Parser; +import org.commonmark.parser.delimiter.DelimiterProcessor; + +import io.noties.markwon.AbstractMarkwonPlugin; +import io.noties.markwon.MarkwonVisitor; +import io.noties.markwon.SpanFactory; +import io.noties.markwon.SpannableBuilder; + +/** + * @since 4.0.0-SNAPSHOT + */ +public class SimpleExtPlugin extends AbstractMarkwonPlugin { + + public interface SimpleExtConfigure { + void configure(@NonNull SimpleExtPlugin plugin); + } + + @NonNull + public static SimpleExtPlugin create() { + return new SimpleExtPlugin(); + } + + @NonNull + public static SimpleExtPlugin create(@NonNull SimpleExtConfigure configure) { + final SimpleExtPlugin plugin = new SimpleExtPlugin(); + configure.configure(plugin); + return plugin; + } + + private final SimpleExtBuilder builder = new SimpleExtBuilder(); + + @SuppressWarnings("WeakerAccess") + SimpleExtPlugin() { + } + + @NonNull + public SimpleExtPlugin addExtension( + int length, + char character, + @NonNull SpanFactory spanFactory) { + builder.addExtension(length, character, spanFactory); + return this; + } + + @NonNull + public SimpleExtPlugin addExtension( + int length, + char openingCharacter, + char closingCharacter, + @NonNull SpanFactory spanFactory) { + builder.addExtension(length, openingCharacter, closingCharacter, spanFactory); + return this; + } + + @Override + public void configureParser(@NonNull Parser.Builder builder) { + for (DelimiterProcessor processor : this.builder.build()) { + builder.customDelimiterProcessor(processor); + } + } + + @Override + public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) { + builder.on(SimpleExtNode.class, new MarkwonVisitor.NodeVisitor() { + @Override + public void visit(@NonNull MarkwonVisitor visitor, @NonNull SimpleExtNode simpleExtNode) { + + final int length = visitor.length(); + + visitor.visitChildren(simpleExtNode); + + SpannableBuilder.setSpans( + visitor.builder(), + simpleExtNode.spanFactory().getSpans(visitor.configuration(), visitor.renderProps()), + length, + visitor.length() + ); + } + }); + } +} diff --git a/sample/build.gradle b/sample/build.gradle index f624824b..c3ff21dd 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -43,6 +43,7 @@ dependencies { implementation project(':markwon-syntax-highlight') implementation project(':markwon-recycler') implementation project(':markwon-recycler-table') + implementation project(':markwon-simple-ext') implementation project(':markwon-image-picasso') diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml index 22ebc86b..7018e3fc 100644 --- a/sample/src/main/AndroidManifest.xml +++ b/sample/src/main/AndroidManifest.xml @@ -25,6 +25,7 @@ + diff --git a/sample/src/main/java/io/noties/markwon/sample/MainActivity.java b/sample/src/main/java/io/noties/markwon/sample/MainActivity.java index 8c197ea7..a27d37a9 100644 --- a/sample/src/main/java/io/noties/markwon/sample/MainActivity.java +++ b/sample/src/main/java/io/noties/markwon/sample/MainActivity.java @@ -24,6 +24,7 @@ import io.noties.markwon.sample.customextension.CustomExtensionActivity; import io.noties.markwon.sample.html.HtmlActivity; import io.noties.markwon.sample.latex.LatexActivity; import io.noties.markwon.sample.recycler.RecyclerActivity; +import io.noties.markwon.sample.simpleext.SimpleExtActivity; public class MainActivity extends Activity { @@ -102,6 +103,10 @@ public class MainActivity extends Activity { activity = HtmlActivity.class; break; + case SIMPLE_EXT: + activity = SimpleExtActivity.class; + break; + default: throw new IllegalStateException("No Activity is associated with sample-item: " + item); } diff --git a/sample/src/main/java/io/noties/markwon/sample/Sample.java b/sample/src/main/java/io/noties/markwon/sample/Sample.java index 03160a35..dbe9bc8a 100644 --- a/sample/src/main/java/io/noties/markwon/sample/Sample.java +++ b/sample/src/main/java/io/noties/markwon/sample/Sample.java @@ -15,7 +15,9 @@ public enum Sample { RECYCLER(R.string.sample_recycler), - HTML(R.string.sample_html); + HTML(R.string.sample_html), + + SIMPLE_EXT(R.string.sample_simple_ext); private final int textResId; diff --git a/sample/src/main/java/io/noties/markwon/sample/simpleext/SimpleExtActivity.java b/sample/src/main/java/io/noties/markwon/sample/simpleext/SimpleExtActivity.java new file mode 100644 index 00000000..77902e16 --- /dev/null +++ b/sample/src/main/java/io/noties/markwon/sample/simpleext/SimpleExtActivity.java @@ -0,0 +1,43 @@ +package io.noties.markwon.sample.simpleext; + +import android.app.Activity; +import android.graphics.Color; +import android.os.Bundle; +import android.text.style.ForegroundColorSpan; +import android.widget.TextView; + +import androidx.annotation.Nullable; + +import io.noties.markwon.Markwon; +import io.noties.markwon.core.spans.EmphasisSpan; +import io.noties.markwon.core.spans.StrongEmphasisSpan; +import io.noties.markwon.sample.R; +import io.noties.markwon.simple.ext.SimpleExtPlugin; + +public class SimpleExtActivity extends Activity { + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.activity_text_view); + + final TextView textView = findViewById(R.id.text_view); + + final Markwon markwon = Markwon.builder(this) + .usePlugin(SimpleExtPlugin.create(plugin -> plugin + // +sometext+ + .addExtension(1, '+', (_1, _2) -> new EmphasisSpan()) + // ??sometext?? + .addExtension(2, '?', (_1, _2) -> new StrongEmphasisSpan()) + // @@sometext$$ + .addExtension(2, '@', '$', (_1, _2) -> new ForegroundColorSpan(Color.RED)))) + .build(); + + final String markdown = "# SimpleExt\n" + + "\n" + + "+let's start with `+`, ??then we can use this, and finally @@this$$??+"; + + markwon.setMarkdown(textView, markdown); + } +} diff --git a/sample/src/main/res/values/strings-samples.xml b/sample/src/main/res/values/strings-samples.xml index 24cab950..a624f921 100644 --- a/sample/src/main/res/values/strings-samples.xml +++ b/sample/src/main/res/values/strings-samples.xml @@ -17,4 +17,7 @@ # \# Html\n\nShows how to define own tag handlers + # \# SimpleExt\n\nShows how to use SimpleExtPlugin module + to create own delimited parser extensions + \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 38372eba..45a92d52 100644 --- a/settings.gradle +++ b/settings.gradle @@ -12,5 +12,6 @@ include ':app', ':sample', ':markwon-linkify', ':markwon-recycler', ':markwon-recycler-table', + ':markwon-simple-ext', ':markwon-syntax-highlight', ':markwon-test-span' From eca93dd27cc2643661dd2840af5d9cb40df7c146 Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Mon, 24 Jun 2019 15:08:43 +0300 Subject: [PATCH 34/42] Add simple-ext documentation --- docs/.vuepress/.artifacts.js | 2 +- docs/.vuepress/config.js | 1 + docs/docs/v4/simple-ext/README.md | 62 +++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 docs/docs/v4/simple-ext/README.md diff --git a/docs/.vuepress/.artifacts.js b/docs/.vuepress/.artifacts.js index a0f2a8de..62c52ab8 100644 --- a/docs/.vuepress/.artifacts.js +++ b/docs/.vuepress/.artifacts.js @@ -1,4 +1,4 @@ // this is a generated file, do not modify. To update it run 'collectArtifacts.js' script -const artifacts = [{"id":"core","name":"Core","group":"io.noties.markwon","description":"Core Markwon artifact that includes basic markdown parsing and rendering"},{"id":"ext-latex","name":"LaTeX","group":"io.noties.markwon","description":"Extension to add LaTeX formulas to Markwon markdown"},{"id":"ext-strikethrough","name":"Strikethrough","group":"io.noties.markwon","description":"Extension to add strikethrough markup to Markwon markdown"},{"id":"ext-tables","name":"Tables","group":"io.noties.markwon","description":"Extension to add tables markup (GFM) to Markwon markdown"},{"id":"ext-tasklist","name":"Task List","group":"io.noties.markwon","description":"Extension to add task lists (GFM) to Markwon markdown"},{"id":"html","name":"HTML","group":"io.noties.markwon","description":"Provides HTML parsing functionality"},{"id":"image","name":"Image","group":"io.noties.markwon","description":"Markwon image loading module (with optional GIF and SVG support)"},{"id":"image-glide","name":"Image Glide","group":"io.noties.markwon","description":"Markwon image loading module (based on Glide library)"},{"id":"image-picasso","name":"Image Picasso","group":"io.noties.markwon","description":"Markwon image loading module (based on Picasso library)"},{"id":"linkify","name":"Linkify","group":"io.noties.markwon","description":"Markwon plugin to linkify text (based on Android Linkify)"},{"id":"recycler","name":"Recycler","group":"io.noties.markwon","description":"Provides RecyclerView.Adapter to display Markwon markdown"},{"id":"recycler-table","name":"Recycler Table","group":"io.noties.markwon","description":"Provides MarkwonAdapter.Entry to render TableBlocks inside Android-native TableLayout widget"},{"id":"syntax-highlight","name":"Syntax Highlight","group":"io.noties.markwon","description":"Add syntax highlight to Markwon markdown via Prism4j library"}]; +const artifacts = [{"id":"core","name":"Core","group":"io.noties.markwon","description":"Core Markwon artifact that includes basic markdown parsing and rendering"},{"id":"ext-latex","name":"LaTeX","group":"io.noties.markwon","description":"Extension to add LaTeX formulas to Markwon markdown"},{"id":"ext-strikethrough","name":"Strikethrough","group":"io.noties.markwon","description":"Extension to add strikethrough markup to Markwon markdown"},{"id":"ext-tables","name":"Tables","group":"io.noties.markwon","description":"Extension to add tables markup (GFM) to Markwon markdown"},{"id":"ext-tasklist","name":"Task List","group":"io.noties.markwon","description":"Extension to add task lists (GFM) to Markwon markdown"},{"id":"html","name":"HTML","group":"io.noties.markwon","description":"Provides HTML parsing functionality"},{"id":"image","name":"Image","group":"io.noties.markwon","description":"Markwon image loading module (with optional GIF and SVG support)"},{"id":"image-glide","name":"Image Glide","group":"io.noties.markwon","description":"Markwon image loading module (based on Glide library)"},{"id":"image-picasso","name":"Image Picasso","group":"io.noties.markwon","description":"Markwon image loading module (based on Picasso library)"},{"id":"linkify","name":"Linkify","group":"io.noties.markwon","description":"Markwon plugin to linkify text (based on Android Linkify)"},{"id":"recycler","name":"Recycler","group":"io.noties.markwon","description":"Provides RecyclerView.Adapter to display Markwon markdown"},{"id":"recycler-table","name":"Recycler Table","group":"io.noties.markwon","description":"Provides MarkwonAdapter.Entry to render TableBlocks inside Android-native TableLayout widget"},{"id":"simple-ext","name":"Simple Extension","group":"io.noties.markwon","description":"Custom extension based on simple delimiter usage"},{"id":"syntax-highlight","name":"Syntax Highlight","group":"io.noties.markwon","description":"Add syntax highlight to Markwon markdown via Prism4j library"}]; export { artifacts }; diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index 27a4dd6b..fe306167 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -65,6 +65,7 @@ module.exports = { '/docs/v4/linkify/', '/docs/v4/recycler/', '/docs/v4/recycler-table/', + '/docs/v4/simple-ext/', '/docs/v4/syntax-highlight/', '/docs/v4/recipes.md', '/docs/v4/migration-3-4.md' diff --git a/docs/docs/v4/simple-ext/README.md b/docs/docs/v4/simple-ext/README.md new file mode 100644 index 00000000..c16fc085 --- /dev/null +++ b/docs/docs/v4/simple-ext/README.md @@ -0,0 +1,62 @@ +# Simple Extension + + + +`SimpleExtPlugin` allows creating simple _delimited_ extensions, for example: + +```md ++this is text surrounded by `+`+ +``` + +```java +final Markwon markwon = Markwon.builder(this) + .usePlugin(SimpleExtPlugin.create(plugin -> plugin + // +sometext+ + .addExtension(1, '+', new SpanFactory() { + @Override + public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) { + return new EmphasisSpan(); + } + }) + .build(); +``` + +or + +```java +final Markwon markwon = Markwon.builder(this) + .usePlugin(SimpleExtPlugin.create()) + .usePlugin(new AbstractMarkwonPlugin() { + @Override + public void configure(@NonNull Registry registry) { + registry.require(SimpleExtPlugin.class, new Action() { + @Override + public void apply(@NonNull SimpleExtPlugin plugin) { + plugin.addExtension(1, '+', new SpanFactory() { + @Override + public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) { + return new EmphasisSpan(); + } + }) + } + }); + } + }) + .build(); +``` + +If opening and closing characters are different another method can be used: + +```java +plugin.addExtension( + /*length*/2, + /*openingCharacter*/'@', + /*closingCharacter*/'$', + /*spanFactory*/(configuration, props) -> new ForegroundColorSpan(Color.RED)))) +``` + +This extension will be applied to a text like this: + +```md +@@we are inside different delimiter characters$$ +``` From 06c2763ac6cf2b29dadbfc123a43e5db6cecad34 Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Wed, 26 Jun 2019 12:57:34 +0300 Subject: [PATCH 35/42] Add LastLineSpacingSpan --- .../core/spans/LastLineSpacingSpan.java | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 markwon-core/src/main/java/io/noties/markwon/core/spans/LastLineSpacingSpan.java diff --git a/markwon-core/src/main/java/io/noties/markwon/core/spans/LastLineSpacingSpan.java b/markwon-core/src/main/java/io/noties/markwon/core/spans/LastLineSpacingSpan.java new file mode 100644 index 00000000..560e3026 --- /dev/null +++ b/markwon-core/src/main/java/io/noties/markwon/core/spans/LastLineSpacingSpan.java @@ -0,0 +1,43 @@ +package io.noties.markwon.core.spans; + +import android.graphics.Paint; +import android.text.Spanned; +import android.text.style.LineHeightSpan; + +import androidx.annotation.NonNull; +import androidx.annotation.Px; + +/** + * @since 4.0.0-SNAPSHOT + */ +public class LastLineSpacingSpan implements LineHeightSpan { + + @NonNull + public static LastLineSpacingSpan create(@Px int spacing) { + return new LastLineSpacingSpan(spacing); + } + + private final int spacing; + + public LastLineSpacingSpan(@Px int spacing) { + this.spacing = spacing; + } + + @Override + public void chooseHeight(CharSequence text, int start, int end, int spanstartv, int v, Paint.FontMetricsInt fm) { + if (selfEnd(end, text, this)) { + // let's just add what we want + fm.descent += spacing; + fm.bottom += spacing; + } + } + + private static boolean selfEnd(int end, CharSequence text, Object span) { + // this is some kind of interesting magic here... only the last + // span will receive correct _end_ argument, but previous spans + // receive it tilted by one (1). Most likely it's just a new-line character... and + // if needed we could check for that + final int spanEnd = ((Spanned) text).getSpanEnd(span); + return spanEnd == end || spanEnd == end - 1; + } +} From 18b1d5b0bbac4b1cfb6258c2c0190d7fab67ff79 Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Wed, 26 Jun 2019 13:49:35 +0300 Subject: [PATCH 36/42] Update recipes documentation page --- docs/docs/v4/recipes.md | 43 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/docs/docs/v4/recipes.md b/docs/docs/v4/recipes.md index c9aad1cb..70a1aab6 100644 --- a/docs/docs/v4/recipes.md +++ b/docs/docs/v4/recipes.md @@ -18,6 +18,49 @@ Do not use `autolink` XML attribute on your `TextView` as it will remove all lin Consider using [linkify plugin](/docs/v4/linkify/) or commonmark-java [autolink extension](https://github.com/atlassian/commonmark-java) +## List item spacing + +If your list items, task list items or paragraphs need special space between them +(increasing spacing between them, but keeping the original line height), +`LastLineSpacingSpan` can be used: + +```java +final Markwon markwon = Markwon.builder(context) + .usePlugin(new AbstractMarkwonPlugin() { + @Override + public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) { + // or Paragraph, or TaskListItem + builder.addFactory(ListItem.class, new SpanFactory() { + @Override + public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) { + return new LastLineSpacingSpan(spacingPx); + } + }); + } + }) + .build(); +``` + +## Softbreak new-line + +If you want to add a new line when a `softbreak` is used: + +```java +final Markwon markwon = Markwon.builder(context) + .usePlugin(new AbstractMarkwonPlugin() { + @Override + public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) { + builder.on(SoftLineBreak.class, new MarkwonVisitor.NodeVisitor() { + @Override + public void visit(@NonNull MarkwonVisitor visitor, @NonNull SoftLineBreak softLineBreak) { + visitor.forceNewLine(); + } + }); + } + }) + .build(); +``` + ## Custom typeface From d65a1809cae7a72e836907b012bc986110fb4de1 Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Wed, 26 Jun 2019 13:58:33 +0300 Subject: [PATCH 37/42] Move CHANGELOG from documentation to the root of repository --- docs/CHANGELOG.md => CHANGELOG.md | 51 +++++++++++++++++++------------ docs/.vuepress/config.js | 2 +- 2 files changed, 32 insertions(+), 21 deletions(-) rename docs/CHANGELOG.md => CHANGELOG.md (73%) diff --git a/docs/CHANGELOG.md b/CHANGELOG.md similarity index 73% rename from docs/CHANGELOG.md rename to CHANGELOG.md index ce8c7278..5f805716 100644 --- a/docs/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,13 @@ # Changelog -# 3.0.1 -* Add `AsyncDrawableLoader.Builder#implementation` method () -* AsyncDrawable allow placeholder to have independent size () +# 3.0.2 +* Fix `latex` plugin (#136) +* Add `#create(Call.Factory)` factory method to `OkHttpImagesPlugin` (#129) + thanks to @ZacSweers + +## 3.0.1 +* Add `AsyncDrawableLoader.Builder#implementation` method (#109) +* AsyncDrawable allow placeholder to have independent size (#115) * `addFactory` method for MarkwonSpansFactory * Add optional spans for list blocks (bullet and ordered) * AsyncDrawable placeholder bounds fix @@ -50,15 +55,16 @@ to get the full picture of latest changes. ## 2.0.1 * `SpannableMarkdownVisitor` Rename blockQuoteIndent to blockIndent -* Fixed block new lines logic for block quote and paragraph () -* AsyncDrawable fix no dimensions bug () +* Fixed block new lines logic for block quote and paragraph (#82) +* AsyncDrawable fix no dimensions bug (#81) * Update SpannableTheme to use Px instead of Dimension annotation * Allow TaskListSpan isDone mutation * Updated commonmark-java to 0.12.1 -* Add OrderedListItemSpan measure utility method () +* Add OrderedListItemSpan measure utility method (#78) * Add SpannableBuilder#getSpans method -* Fix DataUri scheme handler in image-loader () -* Introduced a "copy" builder for SpannableThem
      Thanks +* Fix DataUri scheme handler in image-loader (#74) +* Introduced a "copy" builder for SpannableThem + Thanks @c-b-h ## 2.0.0 * Add `html-parser-api` and `html-parser-impl` modules @@ -81,18 +87,21 @@ to get the full picture of latest changes. * Add sample-latex-math module ## v1.1.1 -* Fix OrderedListItemSpan text position (baseline) () -* Add softBreakAddsNewLine option for SpannableConfiguration () -* Paragraph text can now explicitly be spanned ()
      Thanks to -* Fix table border color if odd background is specified () +* Fix OrderedListItemSpan text position (baseline) (#55) +* Add softBreakAddsNewLine option for SpannableConfiguration (#54) +* Paragraph text can now explicitly be spanned (#58) + Thanks to @c-b-h +* Fix table border color if odd background is specified (#56) * Add table customizations (even and header rows) ## v1.1.0 * Update commonmark to 0.11.0 and android-gif to 1.2.14 * Add syntax highlight functionality (`library-syntax` module and `markwon-syntax` artifact) -* Add headingTypeface, headingTextSizes to SpannableTheme
      Thanks to +* Add headingTypeface, headingTextSizes to SpannableTheme + Thanks to @edenman * Introduce `MediaDecoder` abstraction to `image-loader` module -* Introduce `SpannableFactory`
      Thanks for idea to +* Introduce `SpannableFactory` + Thanks for idea to @c-b-h * Update sample application to use syntax-highlight * Update sample application to use clickable placeholder for GIF media @@ -106,11 +115,13 @@ to `ru.noties.markwon.renderer` package (one level up, previously `ru.noties.mar ## v1.0.5 * Change LinkSpan to extend URLSpan. Allow default linkColor (if not set explicitly) * Fit an image without dimensions to canvas width (and keep ratio) -* Add support for separate color for code blocks ()
      Thanks to +* Add support for separate color for code blocks (#37) + Thanks to @Arcnor ## v1.0.4 -* Fixes (tables are not rendered when at the end of the markdown) -* Adds support for `indented code blocks`
      Thanks to +* Fixes #28 (tables are not rendered when at the end of the markdown) +* Adds support for `indented code blocks` + Thanks to @dlew ## v1.0.3 * Fixed ordered lists (when number width is greater than block margin) @@ -121,11 +132,11 @@ to `ru.noties.markwon.renderer` package (one level up, previously `ru.noties.mar * Tables can have no borders ## v1.0.1 -* Support for task-lists () -* Spans now are applied in reverse order ( ) +* Support for task-lists (#2) +* Spans now are applied in reverse order (#5 #10) * Added `SpannableBuilder` to follow the reverse order of spans * Updated `commonmark-java` to `0.10.0` -* Fixes +* Fixes #1 ## v1.0.0 diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index fe306167..95ea14f8 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -13,7 +13,6 @@ module.exports = { themeConfig: { nav: [ { text: 'Install', link: '/docs/v3/install.md' }, - { text: 'Changelog', link: '/CHANGELOG.md' }, { text: 'API Version', items: [ @@ -22,6 +21,7 @@ module.exports = { { text: 'Legacy (2.x.x)', link: '/docs/v2/' } ] }, + { text: 'Changelog', link: 'https://github.com/noties/Markwon/blob/master/CHANGELOG.md' }, { text: 'Github', link: 'https://github.com/noties/Markwon' } ], sidebar: { From 386254f9620f6b432a92526f2554ceed8549bb88 Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Wed, 26 Jun 2019 17:57:33 +0300 Subject: [PATCH 38/42] Preparing 4.0.0 release --- CHANGELOG.md | 47 +++++- README.md | 5 +- _CHANGES.md | 16 -- app/build.gradle | 1 - docs/docs/v4/image-glide/README.md | 26 +++- docs/docs/v4/image-picasso/README.md | 31 +++- docs/docs/v4/image/README.md | 140 +++++++++++++++++- docs/docs/v4/linkify/README.md | 30 +++- docs/docs/v4/migration-3-4.md | 1 + docs/docs/v4/simple-ext/README.md | 8 + .../java/io/noties/markwon/LinkResolver.java | 2 +- .../main/java/io/noties/markwon/Markwon.java | 4 +- .../noties/markwon/MarkwonConfiguration.java | 4 +- .../java/io/noties/markwon/MarkwonPlugin.java | 14 +- .../java/io/noties/markwon/RegistryImpl.java | 2 +- .../io/noties/markwon/core/CorePlugin.java | 10 +- .../core/spans/LastLineSpacingSpan.java | 2 +- .../noties/markwon/image/AsyncDrawable.java | 14 +- .../markwon/image/AsyncDrawableLoader.java | 4 +- .../markwon/image/AsyncDrawableScheduler.java | 6 +- .../markwon/image/ImageSizeResolver.java | 2 +- .../image/ImageSizeResolverDefTest.java | 2 +- .../markwon/ext/latex/JLatexMathPlugin.java | 28 ++-- .../io/noties/markwon/html/HtmlPlugin.java | 14 +- .../io/noties/markwon/html/TagHandler.java | 2 +- .../noties/markwon/html/TagHandlerNoOp.java | 2 +- .../image/glide/GlideImagesPlugin.java | 2 +- .../image/picasso/PicassoImagesPlugin.java | 2 +- .../image/AsyncDrawableLoaderBuilder.java | 2 +- .../image/AsyncDrawableLoaderImpl.java | 6 +- .../io/noties/markwon/image/ImageItem.java | 16 +- .../io/noties/markwon/image/ImagesPlugin.java | 26 ++-- .../io/noties/markwon/image/MediaDecoder.java | 2 +- .../noties/markwon/image/SchemeHandler.java | 2 +- .../markwon/image/file/FileSchemeHandler.java | 2 +- .../markwon/image/gif/GifMediaDecoder.java | 4 +- .../noties/markwon/image/gif/GifSupport.java | 2 +- .../network/OkHttpNetworkSchemeHandler.java | 6 +- .../markwon/image/svg/SvgMediaDecoder.java | 4 +- .../noties/markwon/image/svg/SvgSupport.java | 2 +- markwon-linkify/README.md | 7 - .../markwon/simple/ext/SimpleExtBuilder.java | 2 +- .../ext/SimpleExtDelimiterProcessor.java | 2 +- .../markwon/simple/ext/SimpleExtNode.java | 2 +- .../markwon/simple/ext/SimpleExtPlugin.java | 2 +- sample/src/main/AndroidManifest.xml | 1 + .../noties/markwon/sample/MainActivity.java | 5 + .../java/io/noties/markwon/sample/Sample.java | 4 +- .../sample/customextension/IconPlugin.java | 7 - .../CustomExtensionActivity2.java | 123 +++++++++++++++ .../src/main/res/values/strings-samples.xml | 3 + 51 files changed, 504 insertions(+), 149 deletions(-) delete mode 100644 _CHANGES.md create mode 100644 sample/src/main/java/io/noties/markwon/sample/customextension2/CustomExtensionActivity2.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f805716..1f267a59 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,40 @@ # Changelog -# 3.0.2 +# 4.0.0 +* maven group-id change to `io.noties.markwon` (was `ru.noties.markwon`) +* package name change to `io.notier.markwon.*` (was `ru.noties.markwon.*`) +* androidx artifacts (#76) +* `Markwon#builder` does not require explicit `CorePlugin` (added automatically), +use `Markwon#builderNoCore()` to obtain a builder without `CorePlugin` +* Removed `Priority` abstraction and `MarkwonPlugin#priority` (use `MarkwonPlugin.Registry`) +* Removed `MarkwonPlugin#configureHtmlRenderer` (for configuration use `HtmlPlugin` directly) +* Removed `MarkwonPlugin#configureImages` (for configuration use `ImagesPlugin` directly) +* Added `MarkwonPlugin.Registry` and `MarkwonPlugin#configure(Registry)` method +* `CorePlugin#addOnTextAddedListener` (process raw text added) +* `ImageSizeResolver` signature change (accept `AsyncDrawable`) +* `LinkResolver` is now an independent entity (previously part of `LinkSpan`) +* `AsyncDrawableScheduler` can now be called multiple times without performance penalty +* `AsyncDrawable` now exposes its destination, image-size, last known dimensions (canvas, text-size) +* `AsyncDrawableLoader` signature change (accept `AsyncDrawable`) +* Add `LastLineSpacingSpan` +* Add `MarkwonConfiguration.Builder#asyncDrawableLoader` method +* `ImagesPlugin` removed from `core` artifact +(also removed `images-gif`, `images-okhttp` and `images-svg` artifacts and their plugins) +* `ImagesPlugin` exposes configuration (adding scheme-handler, media-decoder, etc) +* `ImagesPlugin` allows multiple images with the same source (URL) +* Add `PlaceholderProvider` and `ErrorHandler` to `ImagesPlugin` +* `GIF` and `SVG` media-decoders are automatically added to `ImagesPlugin` if required libraries are found in the classpath +* `ImageItem` is now abstract, has 2 implementations: `withResult`, `withDecodingNeeded` +* Add `images-glide`, `images-picasso`, `linkify`, `simple-ext` modules +* `JLatexMathPlugin` is now independent of `ImagesPlugin` +* Fix wrong `JLatexMathPlugin` formulas sizes (#138) +* `JLatexMathPlugin` has `backgroundProvider`, `executorService` configuration +* `HtmlPlugin` is self-contained (all configuration is moved in the plugin itself) + +## 3.0.2 * Fix `latex` plugin (#136) * Add `#create(Call.Factory)` factory method to `OkHttpImagesPlugin` (#129) - thanks to @ZacSweers +
      Thanks to @ZacSweers ## 3.0.1 * Add `AsyncDrawableLoader.Builder#implementation` method (#109) @@ -64,7 +95,7 @@ to get the full picture of latest changes. * Add SpannableBuilder#getSpans method * Fix DataUri scheme handler in image-loader (#74) * Introduced a "copy" builder for SpannableThem - Thanks @c-b-h +
      Thanks @c-b-h ## 2.0.0 * Add `html-parser-api` and `html-parser-impl` modules @@ -90,7 +121,7 @@ to get the full picture of latest changes. * Fix OrderedListItemSpan text position (baseline) (#55) * Add softBreakAddsNewLine option for SpannableConfiguration (#54) * Paragraph text can now explicitly be spanned (#58) - Thanks to @c-b-h +
      Thanks to @c-b-h * Fix table border color if odd background is specified (#56) * Add table customizations (even and header rows) @@ -98,10 +129,10 @@ to get the full picture of latest changes. * Update commonmark to 0.11.0 and android-gif to 1.2.14 * Add syntax highlight functionality (`library-syntax` module and `markwon-syntax` artifact) * Add headingTypeface, headingTextSizes to SpannableTheme - Thanks to @edenman +
      Thanks to @edenman * Introduce `MediaDecoder` abstraction to `image-loader` module * Introduce `SpannableFactory` - Thanks for idea to @c-b-h +
      Thanks for idea to @c-b-h * Update sample application to use syntax-highlight * Update sample application to use clickable placeholder for GIF media @@ -116,12 +147,12 @@ to `ru.noties.markwon.renderer` package (one level up, previously `ru.noties.mar * Change LinkSpan to extend URLSpan. Allow default linkColor (if not set explicitly) * Fit an image without dimensions to canvas width (and keep ratio) * Add support for separate color for code blocks (#37) - Thanks to @Arcnor +
      Thanks to @Arcnor ## v1.0.4 * Fixes #28 (tables are not rendered when at the end of the markdown) * Adds support for `indented code blocks` - Thanks to @dlew +
      Thanks to @dlew ## v1.0.3 * Fixed ordered lists (when number width is greater than block margin) diff --git a/README.md b/README.md index ddfd65dd..999f7e8c 100644 --- a/README.md +++ b/README.md @@ -35,13 +35,14 @@ features listed in [commonmark-spec] are supported implementation "io.noties.markwon:core:${markwonVersion}" ``` -Full list of available artifacts is present in the [install section](https://noties.github.io/Markwon/docs/v3/install.html) +Full list of available artifacts is present in the [install section](https://noties.github.io/Markwon/docs/v4/install.html) of the [documentation] web-site. Please visit [documentation] web-site for further reference. -> You can find previous version of Markwon in [2.x.x](https://github.com/noties/Markwon/tree/2.x.x) branch +> You can find previous version of Markwon in [2.x.x](https://github.com/noties/Markwon/tree/2.x.x) +and [3.x.x](https://github.com/noties/Markwon/tree/3.x.x) branches ## Supported markdown features: diff --git a/_CHANGES.md b/_CHANGES.md deleted file mode 100644 index 3cd3b21a..00000000 --- a/_CHANGES.md +++ /dev/null @@ -1,16 +0,0 @@ -* `Markwon.builder` won't require CorePlugin registration (it is done automatically) - to create a builder without CorePlugin - use `Markwon#builderNoCore` -* `JLatex` plugin now is not dependent on ImagesPlugin - also accepts a ExecutorService (optional, by default cachedThreadPool is used) -* AsyncDrawableScheduler now can be called by multiple plugins without penalty - internally caches latest state and skips scheduling if drawables are already processed -* configure with registry -* removed priority -* images-plugin moved to standalone again -* removed MarkwonPlugin#configureHtmlRenderer -> now part of HtmlPlugin -* TagHandler now has `supportedTags()` method -* html is moved completely to html-plugin -* OnTextAddedListener (CorePlugin) -* ImageSizeResolver signature change (accept AsyncDrawable) -* JLatexMathPlugin builder has vertical & horizontal padding -* LinkResolver is now an independent entity (previously part of LinkSpan) \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index c17e0fa6..33d7c8cd 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -34,7 +34,6 @@ dependencies { implementation project(':markwon-ext-tasklist') implementation project(':markwon-html') implementation project(':markwon-image') - implementation project(':markwon-linkify') implementation project(':markwon-syntax-highlight') deps.with { diff --git a/docs/docs/v4/image-glide/README.md b/docs/docs/v4/image-glide/README.md index 5d733b87..d8b361c6 100644 --- a/docs/docs/v4/image-glide/README.md +++ b/docs/docs/v4/image-glide/README.md @@ -1,3 +1,27 @@ # Image Glide - \ No newline at end of file + + +Image loading based on `Glide` library + +```java +final Markwon markwon = Markwon.builder(context) + // automatically create Glide instance + .usePlugin(GlideImagesPlugin.create(context)) + // use supplied Glide instance + .usePlugin(GlideImagesPlugin.create(Glide.with(context))) + // if you need more control + .usePlugin(GlideImagesPlugin.create(new GlideImagesPlugin.GlideStore() { + @NonNull + @Override + public RequestBuilder load(@NonNull AsyncDrawable drawable) { + return Glide.with(context).load(drawable.getDestination()); + } + + @Override + public void cancel(@NonNull Target target) { + Glide.with(context).clear(target); + } + })) + .build(); +``` \ No newline at end of file diff --git a/docs/docs/v4/image-picasso/README.md b/docs/docs/v4/image-picasso/README.md index 852ff0e5..22d5f72d 100644 --- a/docs/docs/v4/image-picasso/README.md +++ b/docs/docs/v4/image-picasso/README.md @@ -1,3 +1,32 @@ # Image Picasso - \ No newline at end of file + + +Image loading based on `Picasso` library + +```java +final Markwon markwon = Markwon.builder(context) + // automatically create Picasso instance + .usePlugin(PicassoImagesPlugin.create(context)) + // use provided picasso instance + .usePlugin(PicassoImagesPlugin.create(Picasso.get())) + // if you need more control + .usePlugin(PicassoImagesPlugin.create(new PicassoImagesPlugin.PicassoStore() { + @NonNull + @Override + public RequestCreator load(@NonNull AsyncDrawable drawable) { + return Picasso.get() + .load(drawable.getDestination()) + // please note that drawable should be used as tag (not a destination) + // otherwise there won't be support for multiple images with the same URL + .tag(drawable); + } + + @Override + public void cancel(@NonNull AsyncDrawable drawable) { + Picasso.get() + .cancelTag(drawable); + } + })) + .build(); +``` \ No newline at end of file diff --git a/docs/docs/v4/image/README.md b/docs/docs/v4/image/README.md index bee67c00..62cb8e77 100644 --- a/docs/docs/v4/image/README.md +++ b/docs/docs/v4/image/README.md @@ -194,15 +194,153 @@ introduce any unexpected behavior. ### GifMediaDecoder +Adds support for GIF media in markdown. If `pl.droidsonroids.gif:android-gif-drawable:*` dependency +is found in the classpath, then registration will happen automatically. + +```java +final Markwon markwon = Markwon.builder(context) + .usePlugin(ImagesPlugin.create(new ImagesPlugin.ImagesConfigure() { + @Override + public void configureImages(@NonNull ImagesPlugin plugin) { + // autoplayGif controls if GIF should be automatically started + plugin.addMediaDecoder(GifMediaDecoder.create(/*autoplayGif*/false)); + } + })) + .build(); +``` + ### SvgMediaDecoder +Adds support for SVG media in markdown. If `com.caverock:androidsvg:*` dependency is found +in the classpath, then registration will happen automatically. + +```java +final Markwon markwon = Markwon.builder(context) + .usePlugin(ImagesPlugin.create(new ImagesPlugin.ImagesConfigure() { + @Override + public void configureImages(@NonNull ImagesPlugin plugin) { + + // uses supplied Resources + plugin.addMediaDecoder(SvgMediaDecoder.create(context.getResources())); + + // uses Resources.getSystem() + plugin.addMediaDecoder(SvgMediaDecoder.create()); + } + })) + .build(); +``` + ### DefaultMediaDecoder +`DefaultMediaDecoder` _tries_ to decode supplied InputStream +as Bitmap (via `BitmapFactory.decodeStream(inputStream)`). This decoder is registered automatically. + +```java +final Markwon markwon = Markwon.builder(context) + .usePlugin(ImagesPlugin.create(new ImagesPlugin.ImagesConfigure() { + @Override + public void configureImages(@NonNull ImagesPlugin plugin) { + + // uses supplied Resources + plugin.defaultMediaDecoder(DefaultMediaDecoder.create(context.getResources())); + + // uses Resources.getSystem() + plugin.defaultMediaDecoder(DefaultMediaDecoder.create()); + } + })) + .build(); +``` + ## AsyncDrawableScheduler +`AsyncDrawableScheduler` is used in order to give `AsyncDrawable` a way to invalidate `TextView` +that is holding it. A plugin that is dealing with `AsyncDrawable` should always call these methods: + +```java +final Markwon markwon = Markwon.builder(context) + .usePlugin(new AbstractMarkwonPlugin() { + @Override + public void beforeSetText(@NonNull TextView textView, @NonNull Spanned markdown) { + AsyncDrawableScheduler.unschedule(textView); + } + + @Override + public void afterSetText(@NonNull TextView textView) { + AsyncDrawableScheduler.schedule(textView); + } + }) + .build(); +``` + +:::tip +Starting with multiple plugins can call `AsyncDrawableScheduler#schedule` +method without the penalty to process `AsyncDrawable` callbacks multiple times (internally caches +state which ensures that a `TextView` is processed only once the text has changed). +::: + ## ErrorHandler -## Placeholder +An `ErrorHandler` can be used to receive an error that has happened during image loading +and (optionally) return an error drawable to be displayed instead + +```java +final Markwon markwon = Markwon.builder(context) + .usePlugin(ImagesPlugin.create(new ImagesPlugin.ImagesConfigure() { + @Override + public void configureImages(@NonNull ImagesPlugin plugin) { + plugin.errorHandler(new ImagesPlugin.ErrorHandler() { + @Nullable + @Override + public Drawable handleError(@NonNull String url, @NonNull Throwable throwable) { + return null; + } + }); + } + })) + .build(); +``` + +## PlaceholderProvider + +To display a placeholder during image loading `PlaceholderProvider` can be used: + +```java +final Markwon markwon = Markwon.builder(context) + .usePlugin(ImagesPlugin.create(new ImagesPlugin.ImagesConfigure() { + @Override + public void configureImages(@NonNull ImagesPlugin plugin) { + plugin.placeholderProvider(new ImagesPlugin.PlaceholderProvider() { + @Nullable + @Override + public Drawable providePlaceholder(@NonNull AsyncDrawable drawable) { + return null; + } + }); + } + })) + .build(); +``` + +:::tip +If your placeholder drawable has _specific_ size which is not the same an image that is being loaded, +you can manually assign bounds to the placeholder: + +```java +plugin.placeholderProvider(new ImagesPlugin.PlaceholderProvider() { + @Override + public Drawable providePlaceholder(@NonNull AsyncDrawable drawable) { + final ColorDrawable placeholder = new ColorDrawable(Color.BLUE); + // these bounds will be used to display a placeholder, + // so even if loading image has size `width=100%`, placeholder + // bounds won't be affected by it + placeholder.setBounds(0, 0, 48, 48); + return placeholder; + } +}); +``` +::: + +--- :::tip If you are using [html](/docs/v4/html/) you do not have to additionally setup diff --git a/docs/docs/v4/linkify/README.md b/docs/docs/v4/linkify/README.md index 10a96b98..6140e4bc 100644 --- a/docs/docs/v4/linkify/README.md +++ b/docs/docs/v4/linkify/README.md @@ -1,3 +1,31 @@ # Linkify - \ No newline at end of file + + +A plugin to automatically add links to your markdown. Currently autolinking works for: +* email (`me@web.com`) +* phone numbers (`+10000000`) +* web URLS + +:::warning +`Linkify` plugin is based on `android.text.util.Linkify` which can lead to significant performance +drop due to its implementation based on regex. +::: + +:::danger +Do not use `autolink` XML attribute on your `TextView` as it will remove +all links except autolinked ones ¯\\\_(ツ)_/¯ +::: + +```java +final Markwon markwon = Markwon.builder(context) + // will autolink all supported types + .usePlugin(LinkifyPlugin.create()) + // the same as above + .usePlugin(LinkifyPlugin.create( + Linkify.EMAIL_ADDRESSES | Linkify.PHONE_NUMBERS | Linkify.WEB_URLS + )) + // only emails + .usePlugin(LinkifyPlugin.create(Linkify.EMAIL_ADDRESSES)) + .build(); +``` \ No newline at end of file diff --git a/docs/docs/v4/migration-3-4.md b/docs/docs/v4/migration-3-4.md index f36cf75a..8dd6bc5d 100644 --- a/docs/docs/v4/migration-3-4.md +++ b/docs/docs/v4/migration-3-4.md @@ -2,5 +2,6 @@ * maven group-id is changed: `io.noties.markwon` (was `ru.noties.markwon`) * root package-name is changed: `io.noties.markwon` (was `ru.noties.markwon`) +* `androidx` packages todo \ No newline at end of file diff --git a/docs/docs/v4/simple-ext/README.md b/docs/docs/v4/simple-ext/README.md index c16fc085..ded84bb6 100644 --- a/docs/docs/v4/simple-ext/README.md +++ b/docs/docs/v4/simple-ext/README.md @@ -60,3 +60,11 @@ This extension will be applied to a text like this: ```md @@we are inside different delimiter characters$$ ``` + +:::warning +Space character cannot be used as a delimiter (from either side). So, +```java +plugin.addExtension(1, '@', ' ', /*spanFactory*/); +``` +won't work for `@some-text ` text +::: diff --git a/markwon-core/src/main/java/io/noties/markwon/LinkResolver.java b/markwon-core/src/main/java/io/noties/markwon/LinkResolver.java index 1a6c9010..f468f872 100644 --- a/markwon-core/src/main/java/io/noties/markwon/LinkResolver.java +++ b/markwon-core/src/main/java/io/noties/markwon/LinkResolver.java @@ -7,7 +7,7 @@ import androidx.annotation.NonNull; /** * @see LinkResolverDef * @see MarkwonConfiguration.Builder#linkResolver(LinkResolver) - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ public interface LinkResolver { void resolve(@NonNull View view, @NonNull String link); diff --git a/markwon-core/src/main/java/io/noties/markwon/Markwon.java b/markwon-core/src/main/java/io/noties/markwon/Markwon.java index 1f3896ce..ac702599 100644 --- a/markwon-core/src/main/java/io/noties/markwon/Markwon.java +++ b/markwon-core/src/main/java/io/noties/markwon/Markwon.java @@ -47,14 +47,14 @@ public abstract class Markwon { @NonNull public static Builder builder(@NonNull Context context) { return new MarkwonBuilderImpl(context) - // @since 4.0.0-SNAPSHOT add CorePlugin + // @since 4.0.0 add CorePlugin .usePlugin(CorePlugin.create()); } /** * Factory method to obtain an instance of {@link Builder} without {@link CorePlugin}. * - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ @NonNull public static Builder builderNoCore(@NonNull Context context) { diff --git a/markwon-core/src/main/java/io/noties/markwon/MarkwonConfiguration.java b/markwon-core/src/main/java/io/noties/markwon/MarkwonConfiguration.java index b911e945..5b22623f 100644 --- a/markwon-core/src/main/java/io/noties/markwon/MarkwonConfiguration.java +++ b/markwon-core/src/main/java/io/noties/markwon/MarkwonConfiguration.java @@ -95,7 +95,7 @@ public class MarkwonConfiguration { } /** - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ @NonNull public Builder asyncDrawableLoader(@NonNull AsyncDrawableLoader asyncDrawableLoader) { @@ -138,7 +138,7 @@ public class MarkwonConfiguration { this.theme = theme; this.spansFactory = spansFactory; - // @since 4.0.0-SNAPSHOT + // @since 4.0.0 if (asyncDrawableLoader == null) { asyncDrawableLoader = AsyncDrawableLoader.noOp(); } diff --git a/markwon-core/src/main/java/io/noties/markwon/MarkwonPlugin.java b/markwon-core/src/main/java/io/noties/markwon/MarkwonPlugin.java index a916540a..33527a9b 100644 --- a/markwon-core/src/main/java/io/noties/markwon/MarkwonPlugin.java +++ b/markwon-core/src/main/java/io/noties/markwon/MarkwonPlugin.java @@ -26,7 +26,7 @@ public interface MarkwonPlugin { /** * @see Registry#require(Class, Action) - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ interface Action

      { void apply(@NonNull P p); @@ -34,7 +34,7 @@ public interface MarkwonPlugin { /** * @see #configure(Registry) - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ interface Registry { @@ -49,7 +49,7 @@ public interface MarkwonPlugin { /** * This method will be called before any other during {@link Markwon} instance construction. * - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ void configure(@NonNull Registry registry); @@ -91,14 +91,6 @@ public interface MarkwonPlugin { */ void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder); -// /** -// * Configure {@link MarkwonHtmlRenderer} to add or remove HTML {@link TagHandler}s -// * -// * @see MarkwonHtmlRenderer -// * @see MarkwonHtmlRenderer.Builder -// */ -// void configureHtmlRenderer(@NonNull MarkwonHtmlRenderer.Builder builder); - /** * Process input markdown and return new string to be used in parsing stage further. * Can be described as pre-processing of markdown String. diff --git a/markwon-core/src/main/java/io/noties/markwon/RegistryImpl.java b/markwon-core/src/main/java/io/noties/markwon/RegistryImpl.java index 76805be8..d1d0acdb 100644 --- a/markwon-core/src/main/java/io/noties/markwon/RegistryImpl.java +++ b/markwon-core/src/main/java/io/noties/markwon/RegistryImpl.java @@ -10,7 +10,7 @@ import java.util.Set; import io.noties.markwon.core.CorePlugin; -// @since 4.0.0-SNAPSHOT +// @since 4.0.0 class RegistryImpl implements MarkwonPlugin.Registry { private final List origin; diff --git a/markwon-core/src/main/java/io/noties/markwon/core/CorePlugin.java b/markwon-core/src/main/java/io/noties/markwon/core/CorePlugin.java index 084fb0d2..194882e3 100644 --- a/markwon-core/src/main/java/io/noties/markwon/core/CorePlugin.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/CorePlugin.java @@ -58,7 +58,7 @@ public class CorePlugin extends AbstractMarkwonPlugin { /** * @see #addOnTextAddedListener(OnTextAddedListener) - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ public interface OnTextAddedListener { @@ -88,7 +88,7 @@ public class CorePlugin extends AbstractMarkwonPlugin { return new CorePlugin(); } - // @since 4.0.0-SNAPSHOT + // @since 4.0.0 private final List onTextAddedListeners = new ArrayList<>(0); protected CorePlugin() { @@ -98,7 +98,7 @@ public class CorePlugin extends AbstractMarkwonPlugin { * Can be useful to post-process text added. For example for auto-linking capabilities. * * @see OnTextAddedListener - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ @SuppressWarnings("UnusedReturnValue") @NonNull @@ -171,7 +171,7 @@ public class CorePlugin extends AbstractMarkwonPlugin { visitor.builder().append(literal); - // @since 4.0.0-SNAPSHOT + // @since 4.0.0 if (!onTextAddedListeners.isEmpty()) { // calculate the start position final int length = visitor.length() - literal.length(); @@ -262,7 +262,7 @@ public class CorePlugin extends AbstractMarkwonPlugin { }); } - // @since 4.0.0-SNAPSHOT + // @since 4.0.0 // his method is moved from ImagesPlugin. Alternative implementations must set SpanFactory // for Image node in order for this visitor to function private static void image(MarkwonVisitor.Builder builder) { diff --git a/markwon-core/src/main/java/io/noties/markwon/core/spans/LastLineSpacingSpan.java b/markwon-core/src/main/java/io/noties/markwon/core/spans/LastLineSpacingSpan.java index 560e3026..6ef71dea 100644 --- a/markwon-core/src/main/java/io/noties/markwon/core/spans/LastLineSpacingSpan.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/spans/LastLineSpacingSpan.java @@ -8,7 +8,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Px; /** - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ public class LastLineSpacingSpan implements LineHeightSpan { diff --git a/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawable.java b/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawable.java index 7eb4b38d..62ea138a 100644 --- a/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawable.java +++ b/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawable.java @@ -53,7 +53,7 @@ public class AsyncDrawable extends Drawable { } /** - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ @Nullable public ImageSize getImageSize() { @@ -61,7 +61,7 @@ public class AsyncDrawable extends Drawable { } /** - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ @NonNull public ImageSizeResolver getImageSizeResolver() { @@ -69,7 +69,7 @@ public class AsyncDrawable extends Drawable { } /** - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ public boolean hasKnownDimentions() { return canvasWidth > 0; @@ -77,7 +77,7 @@ public class AsyncDrawable extends Drawable { /** * @see #hasKnownDimentions() - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ public int getLastKnownCanvasWidth() { return canvasWidth; @@ -85,7 +85,7 @@ public class AsyncDrawable extends Drawable { /** * @see #hasKnownDimentions() - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ public float getLastKnowTextSize() { return textSize; @@ -262,7 +262,7 @@ public class AsyncDrawable extends Drawable { if (hasResult()) { out = result.getIntrinsicWidth(); } else { - // @since 4.0.0-SNAPSHOT, must not be zero in order to receive canvas dimensions + // @since 4.0.0, must not be zero in order to receive canvas dimensions out = 1; } return out; @@ -274,7 +274,7 @@ public class AsyncDrawable extends Drawable { if (hasResult()) { out = result.getIntrinsicHeight(); } else { - // @since 4.0.0-SNAPSHOT, must not be zero in order to receive canvas dimensions + // @since 4.0.0, must not be zero in order to receive canvas dimensions out = 1; } return out; diff --git a/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawableLoader.java b/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawableLoader.java index 75c99384..9907202f 100644 --- a/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawableLoader.java +++ b/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawableLoader.java @@ -16,12 +16,12 @@ public abstract class AsyncDrawableLoader { } /** - * @since 3.1.0-SNAPSHOT + * @since 4.0.0 */ public abstract void load(@NonNull AsyncDrawable drawable); /** - * @since 3.1.0-SNAPSHOT + * @since 4.0.0 */ public abstract void cancel(@NonNull AsyncDrawable drawable); diff --git a/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawableScheduler.java b/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawableScheduler.java index 63ad3f68..a7d664e3 100644 --- a/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawableScheduler.java +++ b/markwon-core/src/main/java/io/noties/markwon/image/AsyncDrawableScheduler.java @@ -24,7 +24,7 @@ public abstract class AsyncDrawableScheduler { // hm... we need the same thing for unschedule then... we can check if last hash is !null, // if it's not -> unschedule, else ignore - // @since 4.0.0-SNAPSHOT + // @since 4.0.0 final Integer lastTextHashCode = (Integer) textView.getTag(R.id.markwon_drawables_scheduler_last_text_hashcode); final int textHashCode = textView.getText().hashCode(); @@ -69,7 +69,7 @@ public abstract class AsyncDrawableScheduler { // must be called when text manually changed in TextView public static void unschedule(@NonNull TextView view) { - // @since 4.0.0-SNAPSHOT + // @since 4.0.0 if (view.getTag(R.id.markwon_drawables_scheduler_last_text_hashcode) == null) { return; } @@ -99,7 +99,7 @@ public abstract class AsyncDrawableScheduler { } // we also could've tried the `nextSpanTransition`, but strangely it leads to worse performance - // then direct getSpans + // than direct getSpans return ((Spanned) cs).getSpans(0, length, AsyncDrawableSpan.class); } diff --git a/markwon-core/src/main/java/io/noties/markwon/image/ImageSizeResolver.java b/markwon-core/src/main/java/io/noties/markwon/image/ImageSizeResolver.java index ecd7bbcb..cc7e7060 100644 --- a/markwon-core/src/main/java/io/noties/markwon/image/ImageSizeResolver.java +++ b/markwon-core/src/main/java/io/noties/markwon/image/ImageSizeResolver.java @@ -12,7 +12,7 @@ import androidx.annotation.NonNull; public abstract class ImageSizeResolver { /** - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ @NonNull public abstract Rect resolveImageSize(@NonNull AsyncDrawable drawable); diff --git a/markwon-core/src/test/java/io/noties/markwon/image/ImageSizeResolverDefTest.java b/markwon-core/src/test/java/io/noties/markwon/image/ImageSizeResolverDefTest.java index 5030986c..455ccb74 100644 --- a/markwon-core/src/test/java/io/noties/markwon/image/ImageSizeResolverDefTest.java +++ b/markwon-core/src/test/java/io/noties/markwon/image/ImageSizeResolverDefTest.java @@ -31,7 +31,7 @@ public class ImageSizeResolverDefTest { @Test public void correct_redirect() { - // @since 4.0.0-SNAPSHOT the main method is changed to accept AsyncDrawable + // @since 4.0.0 the main method is changed to accept AsyncDrawable final ImageSizeResolverDef def = mock(ImageSizeResolverDef.class, Mockito.CALLS_REAL_METHODS); final AsyncDrawable drawable = mock(AsyncDrawable.class); diff --git a/markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathPlugin.java b/markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathPlugin.java index 8b7bce3e..6e3ea341 100644 --- a/markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathPlugin.java +++ b/markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathPlugin.java @@ -36,7 +36,7 @@ import ru.noties.jlatexmath.JLatexMathDrawable; public class JLatexMathPlugin extends AbstractMarkwonPlugin { /** - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ public interface BackgroundProvider { @NonNull @@ -73,7 +73,7 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin { private final float textSize; - // @since 4.0.0-SNAPSHOT + // @since 4.0.0 private final BackgroundProvider backgroundProvider; @JLatexMathDrawable.Align @@ -81,13 +81,13 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin { private final boolean fitCanvas; - // @since 4.0.0-SNAPSHOT + // @since 4.0.0 private final int paddingHorizontal; - // @since 4.0.0-SNAPSHOT + // @since 4.0.0 private final int paddingVertical; - // @since 4.0.0-SNAPSHOT + // @since 4.0.0 private final ExecutorService executorService; Config(@NonNull Builder builder) { @@ -98,7 +98,7 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin { this.paddingHorizontal = builder.paddingHorizontal; this.paddingVertical = builder.paddingVertical; - // @since 4.0.0-SNAPSHOT + // @since 4.0.0 ExecutorService executorService = builder.executorService; if (executorService == null) { executorService = Executors.newCachedThreadPool(); @@ -164,7 +164,7 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin { private final float textSize; - // @since 4.0.0-SNAPSHOT + // @since 4.0.0 private BackgroundProvider backgroundProvider; @JLatexMathDrawable.Align @@ -172,13 +172,13 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin { private boolean fitCanvas = true; - // @since 4.0.0-SNAPSHOT + // @since 4.0.0 private int paddingHorizontal; - // @since 4.0.0-SNAPSHOT + // @since 4.0.0 private int paddingVertical; - // @since 4.0.0-SNAPSHOT + // @since 4.0.0 private ExecutorService executorService; Builder(float textSize) { @@ -211,7 +211,7 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin { } /** - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ @NonNull public Builder builder(@Px int paddingHorizontal, @Px int paddingVertical) { @@ -221,7 +221,7 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin { } /** - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ @NonNull public Builder executorService(@NonNull ExecutorService executorService) { @@ -235,7 +235,7 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin { } } - // @since 4.0.0-SNAPSHOT + // @since 4.0.0 private static class JLatextAsyncDrawableLoader extends AsyncDrawableLoader { private final Config config; @@ -317,7 +317,7 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin { } // we must make drawable fit canvas (if specified), but do not keep the ratio whilst scaling up - // @since 4.0.0-SNAPSHOT + // @since 4.0.0 private static class JLatexImageSizeResolver extends ImageSizeResolver { private final boolean fitCanvas; diff --git a/markwon-html/src/main/java/io/noties/markwon/html/HtmlPlugin.java b/markwon-html/src/main/java/io/noties/markwon/html/HtmlPlugin.java index c4462c99..c2c13c12 100644 --- a/markwon-html/src/main/java/io/noties/markwon/html/HtmlPlugin.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/HtmlPlugin.java @@ -29,7 +29,7 @@ public class HtmlPlugin extends AbstractMarkwonPlugin { /** * @see #create(HtmlConfigure) - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ public interface HtmlConfigure { void configureHtml(@NonNull HtmlPlugin plugin); @@ -41,7 +41,7 @@ public class HtmlPlugin extends AbstractMarkwonPlugin { } /** - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ @NonNull public static HtmlPlugin create(@NonNull HtmlConfigure configure) { @@ -65,7 +65,7 @@ public class HtmlPlugin extends AbstractMarkwonPlugin { /** * @param allowNonClosedTags whether or not non-closed tags should be closed * at the document end. By default `false` - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ @NonNull public HtmlPlugin allowNonClosedTags(boolean allowNonClosedTags) { @@ -74,7 +74,7 @@ public class HtmlPlugin extends AbstractMarkwonPlugin { } /** - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ @NonNull public HtmlPlugin addHandler(@NonNull TagHandler tagHandler) { @@ -83,7 +83,7 @@ public class HtmlPlugin extends AbstractMarkwonPlugin { } /** - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ @Nullable public TagHandler getHandler(@NonNull String tagName) { @@ -96,7 +96,7 @@ public class HtmlPlugin extends AbstractMarkwonPlugin { * {@link TagHandlerNoOp} to no-op certain default tags. * * @see TagHandlerNoOp - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ @NonNull public HtmlPlugin excludeDefaults(boolean excludeDefaults) { @@ -107,7 +107,7 @@ public class HtmlPlugin extends AbstractMarkwonPlugin { @Override public void configureConfiguration(@NonNull MarkwonConfiguration.Builder configurationBuilder) { - // @since 4.0.0-SNAPSHOT we init internal html-renderer here (marks the end of configuration) + // @since 4.0.0 we init internal html-renderer here (marks the end of configuration) final MarkwonHtmlRendererImpl.Builder builder = this.builder; diff --git a/markwon-html/src/main/java/io/noties/markwon/html/TagHandler.java b/markwon-html/src/main/java/io/noties/markwon/html/TagHandler.java index 66a30e06..29693a07 100644 --- a/markwon-html/src/main/java/io/noties/markwon/html/TagHandler.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/TagHandler.java @@ -15,7 +15,7 @@ public abstract class TagHandler { ); /** - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ @NonNull public abstract Collection supportedTags(); diff --git a/markwon-html/src/main/java/io/noties/markwon/html/TagHandlerNoOp.java b/markwon-html/src/main/java/io/noties/markwon/html/TagHandlerNoOp.java index 79ba8dea..dcc31bed 100644 --- a/markwon-html/src/main/java/io/noties/markwon/html/TagHandlerNoOp.java +++ b/markwon-html/src/main/java/io/noties/markwon/html/TagHandlerNoOp.java @@ -9,7 +9,7 @@ import java.util.Collections; import io.noties.markwon.MarkwonVisitor; /** - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ public class TagHandlerNoOp extends TagHandler { diff --git a/markwon-image-glide/src/main/java/io/noties/markwon/image/glide/GlideImagesPlugin.java b/markwon-image-glide/src/main/java/io/noties/markwon/image/glide/GlideImagesPlugin.java index ae15afa4..e690c014 100644 --- a/markwon-image-glide/src/main/java/io/noties/markwon/image/glide/GlideImagesPlugin.java +++ b/markwon-image-glide/src/main/java/io/noties/markwon/image/glide/GlideImagesPlugin.java @@ -30,7 +30,7 @@ import io.noties.markwon.image.DrawableUtils; import io.noties.markwon.image.ImageSpanFactory; /** - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ public class GlideImagesPlugin extends AbstractMarkwonPlugin { diff --git a/markwon-image-picasso/src/main/java/io/noties/markwon/image/picasso/PicassoImagesPlugin.java b/markwon-image-picasso/src/main/java/io/noties/markwon/image/picasso/PicassoImagesPlugin.java index 4e92fced..ea751030 100644 --- a/markwon-image-picasso/src/main/java/io/noties/markwon/image/picasso/PicassoImagesPlugin.java +++ b/markwon-image-picasso/src/main/java/io/noties/markwon/image/picasso/PicassoImagesPlugin.java @@ -30,7 +30,7 @@ import io.noties.markwon.image.DrawableUtils; import io.noties.markwon.image.ImageSpanFactory; /** - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ public class PicassoImagesPlugin extends AbstractMarkwonPlugin { diff --git a/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderBuilder.java b/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderBuilder.java index 24ce355a..25daf016 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderBuilder.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderBuilder.java @@ -28,7 +28,7 @@ class AsyncDrawableLoaderBuilder { AsyncDrawableLoaderBuilder() { - // @since 4.0.0-SNAPSHOT + // @since 4.0.0 // okay, let's add supported schemes at the start, this would be : data-uri and default network // we should not use file-scheme as it's a bit complicated to assume file usage (lack of permissions) addSchemeHandler(DataUriSchemeHandler.create()); diff --git a/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderImpl.java b/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderImpl.java index e1b92d55..e227cc6d 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderImpl.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderImpl.java @@ -28,7 +28,7 @@ class AsyncDrawableLoaderImpl extends AsyncDrawableLoader { private final Handler handler; - // @since 4.0.0-SNAPSHOT use a hash-map with a AsyncDrawable as key for multiple requests + // @since 4.0.0 use a hash-map with a AsyncDrawable as key for multiple requests // for the same destination private final Map> requests = new HashMap<>(2); @@ -36,7 +36,7 @@ class AsyncDrawableLoaderImpl extends AsyncDrawableLoader { this(builder, new Handler(Looper.getMainLooper())); } - // @since 4.0.0-SNAPSHOT + // @since 4.0.0 @VisibleForTesting AsyncDrawableLoaderImpl(@NonNull AsyncDrawableLoaderBuilder builder, @NonNull Handler handler) { this.executorService = builder.executorService; @@ -144,7 +144,7 @@ class AsyncDrawableLoaderImpl extends AsyncDrawableLoader { final Drawable out = drawable; - // @since 4.0.0-SNAPSHOT apply intrinsic bounds (but only if they are empty) + // @since 4.0.0 apply intrinsic bounds (but only if they are empty) if (out != null) { final Rect bounds = out.getBounds(); //noinspection ConstantConditions diff --git a/markwon-image/src/main/java/io/noties/markwon/image/ImageItem.java b/markwon-image/src/main/java/io/noties/markwon/image/ImageItem.java index 191e3e10..e44587ea 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/ImageItem.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/ImageItem.java @@ -17,7 +17,7 @@ public abstract class ImageItem { * * @see #withDecodingNeeded(String, InputStream) * @see WithResult - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ @NonNull public static ImageItem withResult(@NonNull Drawable drawable) { @@ -29,7 +29,7 @@ public abstract class ImageItem { * * @see #withResult(Drawable) * @see WithDecodingNeeded - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ @NonNull public static ImageItem withDecodingNeeded( @@ -43,31 +43,31 @@ public abstract class ImageItem { } /** - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ public abstract boolean hasResult(); /** - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ public abstract boolean hasDecodingNeeded(); /** * @see #hasResult() - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ @NonNull public abstract WithResult getAsWithResult(); /** * @see #hasDecodingNeeded() - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ @NonNull public abstract WithDecodingNeeded getAsWithDecodingNeeded(); /** - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ public static class WithResult extends ImageItem { @@ -106,7 +106,7 @@ public abstract class ImageItem { } /** - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ public static class WithDecodingNeeded extends ImageItem { diff --git a/markwon-image/src/main/java/io/noties/markwon/image/ImagesPlugin.java b/markwon-image/src/main/java/io/noties/markwon/image/ImagesPlugin.java index d93ca23d..bd653369 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/ImagesPlugin.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/ImagesPlugin.java @@ -27,14 +27,14 @@ import io.noties.markwon.image.svg.SvgMediaDecoder; public class ImagesPlugin extends AbstractMarkwonPlugin { /** - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ public interface ImagesConfigure { void configureImages(@NonNull ImagesPlugin plugin); } /** - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ public interface PlaceholderProvider { @Nullable @@ -42,7 +42,7 @@ public class ImagesPlugin extends AbstractMarkwonPlugin { } /** - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ public interface ErrorHandler { @@ -74,12 +74,12 @@ public class ImagesPlugin extends AbstractMarkwonPlugin { private final AsyncDrawableLoaderBuilder builder; - // @since 4.0.0-SNAPSHOT + // @since 4.0.0 ImagesPlugin() { this(new AsyncDrawableLoaderBuilder()); } - // @since 4.0.0-SNAPSHOT + // @since 4.0.0 @VisibleForTesting ImagesPlugin(@NonNull AsyncDrawableLoaderBuilder builder) { this.builder = builder; @@ -88,7 +88,7 @@ public class ImagesPlugin extends AbstractMarkwonPlugin { /** * Optional (by default new cached thread executor will be used) * - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ @NonNull public ImagesPlugin executorService(@NonNull ExecutorService executorService) { @@ -102,7 +102,7 @@ public class ImagesPlugin extends AbstractMarkwonPlugin { * @see FileSchemeHandler * @see NetworkSchemeHandler * @see OkHttpNetworkSchemeHandler - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ @NonNull public ImagesPlugin addSchemeHandler(@NonNull SchemeHandler schemeHandler) { @@ -114,7 +114,7 @@ public class ImagesPlugin extends AbstractMarkwonPlugin { * @see DefaultMediaDecoder * @see SvgMediaDecoder * @see GifMediaDecoder - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ @NonNull public ImagesPlugin addMediaDecoder(@NonNull MediaDecoder mediaDecoder) { @@ -127,7 +127,7 @@ public class ImagesPlugin extends AbstractMarkwonPlugin { * if you need to disable default-image-media-decoder specify here own no-op implementation or null. * * @see DefaultMediaDecoder - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ @NonNull public ImagesPlugin defaultMediaDecoder(@Nullable MediaDecoder mediaDecoder) { @@ -136,7 +136,7 @@ public class ImagesPlugin extends AbstractMarkwonPlugin { } /** - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ @NonNull public ImagesPlugin removeSchemeHandler(@NonNull String scheme) { @@ -145,7 +145,7 @@ public class ImagesPlugin extends AbstractMarkwonPlugin { } /** - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ @NonNull public ImagesPlugin removeMediaDecoder(@NonNull String contentType) { @@ -154,7 +154,7 @@ public class ImagesPlugin extends AbstractMarkwonPlugin { } /** - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ @NonNull public ImagesPlugin placeholderProvider(@NonNull PlaceholderProvider placeholderProvider) { @@ -164,7 +164,7 @@ public class ImagesPlugin extends AbstractMarkwonPlugin { /** * @see ErrorHandler - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ @NonNull public ImagesPlugin errorHandler(@NonNull ErrorHandler errorHandler) { diff --git a/markwon-image/src/main/java/io/noties/markwon/image/MediaDecoder.java b/markwon-image/src/main/java/io/noties/markwon/image/MediaDecoder.java index 6b69ba03..f5f115e0 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/MediaDecoder.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/MediaDecoder.java @@ -27,7 +27,7 @@ public abstract class MediaDecoder { ); /** - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ @NonNull public abstract Collection supportedTypes(); diff --git a/markwon-image/src/main/java/io/noties/markwon/image/SchemeHandler.java b/markwon-image/src/main/java/io/noties/markwon/image/SchemeHandler.java index 6a8ccbf1..89bd4877 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/SchemeHandler.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/SchemeHandler.java @@ -24,7 +24,7 @@ public abstract class SchemeHandler { public abstract ImageItem handle(@NonNull String raw, @NonNull Uri uri); /** - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ @NonNull public abstract Collection supportedSchemes(); diff --git a/markwon-image/src/main/java/io/noties/markwon/image/file/FileSchemeHandler.java b/markwon-image/src/main/java/io/noties/markwon/image/file/FileSchemeHandler.java index 43a969f5..d7da6dc5 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/file/FileSchemeHandler.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/file/FileSchemeHandler.java @@ -40,7 +40,7 @@ public class FileSchemeHandler extends SchemeHandler { /** * @see #createWithAssets(AssetManager) * @see UrlProcessorAndroidAssets - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ @NonNull public static FileSchemeHandler createWithAssets(@NonNull Context context) { diff --git a/markwon-image/src/main/java/io/noties/markwon/image/gif/GifMediaDecoder.java b/markwon-image/src/main/java/io/noties/markwon/image/gif/GifMediaDecoder.java index 479815f4..e8ac616e 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/gif/GifMediaDecoder.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/gif/GifMediaDecoder.java @@ -26,7 +26,7 @@ public class GifMediaDecoder extends MediaDecoder { /** * Creates a {@link GifMediaDecoder} with {@code autoPlayGif = true} * - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ @NonNull public static GifMediaDecoder create() { @@ -43,7 +43,7 @@ public class GifMediaDecoder extends MediaDecoder { protected GifMediaDecoder(boolean autoPlayGif) { this.autoPlayGif = autoPlayGif; - // @since 4.0.0-SNAPSHOT + // @since 4.0.0 validate(); } diff --git a/markwon-image/src/main/java/io/noties/markwon/image/gif/GifSupport.java b/markwon-image/src/main/java/io/noties/markwon/image/gif/GifSupport.java index 3e996d45..47624d40 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/gif/GifSupport.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/gif/GifSupport.java @@ -1,7 +1,7 @@ package io.noties.markwon.image.gif; /** - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ public abstract class GifSupport { diff --git a/markwon-image/src/main/java/io/noties/markwon/image/network/OkHttpNetworkSchemeHandler.java b/markwon-image/src/main/java/io/noties/markwon/image/network/OkHttpNetworkSchemeHandler.java index 3d7bea00..84becb16 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/network/OkHttpNetworkSchemeHandler.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/network/OkHttpNetworkSchemeHandler.java @@ -16,7 +16,7 @@ import okhttp3.Response; import okhttp3.ResponseBody; /** - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ public class OkHttpNetworkSchemeHandler extends SchemeHandler { @@ -35,7 +35,7 @@ public class OkHttpNetworkSchemeHandler extends SchemeHandler { } /** - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ @NonNull public static OkHttpNetworkSchemeHandler create(@NonNull Call.Factory factory) { @@ -44,7 +44,7 @@ public class OkHttpNetworkSchemeHandler extends SchemeHandler { private static final String HEADER_CONTENT_TYPE = "Content-Type"; - // @since 4.0.0-SNAPSHOT, previously just OkHttpClient + // @since 4.0.0, previously just OkHttpClient private final Call.Factory factory; @SuppressWarnings("WeakerAccess") diff --git a/markwon-image/src/main/java/io/noties/markwon/image/svg/SvgMediaDecoder.java b/markwon-image/src/main/java/io/noties/markwon/image/svg/SvgMediaDecoder.java index 848cc82e..b307a105 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/svg/SvgMediaDecoder.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/svg/SvgMediaDecoder.java @@ -27,7 +27,7 @@ public class SvgMediaDecoder extends MediaDecoder { /** * @see #create(Resources) - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ @NonNull public static SvgMediaDecoder create() { @@ -45,7 +45,7 @@ public class SvgMediaDecoder extends MediaDecoder { SvgMediaDecoder(Resources resources) { this.resources = resources; - // @since 4.0.0-SNAPSHOT + // @since 4.0.0 validate(); } diff --git a/markwon-image/src/main/java/io/noties/markwon/image/svg/SvgSupport.java b/markwon-image/src/main/java/io/noties/markwon/image/svg/SvgSupport.java index 7ed0ce46..70293570 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/svg/SvgSupport.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/svg/SvgSupport.java @@ -1,7 +1,7 @@ package io.noties.markwon.image.svg; /** - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ public abstract class SvgSupport { diff --git a/markwon-linkify/README.md b/markwon-linkify/README.md index e57f87ca..437ce4e4 100644 --- a/markwon-linkify/README.md +++ b/markwon-linkify/README.md @@ -1,9 +1,2 @@ # Linkify -Use this module (or take a hint from it) if you would need _linkify_ capabilities. Do not -use `TextView.setAutolinkMask` (or specify `autolink` in XML) because it will remove all -existing links and keep only the ones it creates. - -Please note that usage of this plugin introduces significant performance drop due to not -optimal implementation of underlying `android.text.util.Linkify`. If you have any ideas of how -to improve this - PRs are welcome! \ No newline at end of file diff --git a/markwon-simple-ext/src/main/java/io/noties/markwon/simple/ext/SimpleExtBuilder.java b/markwon-simple-ext/src/main/java/io/noties/markwon/simple/ext/SimpleExtBuilder.java index 10d0ed95..927ba3f0 100644 --- a/markwon-simple-ext/src/main/java/io/noties/markwon/simple/ext/SimpleExtBuilder.java +++ b/markwon-simple-ext/src/main/java/io/noties/markwon/simple/ext/SimpleExtBuilder.java @@ -9,7 +9,7 @@ import java.util.List; import io.noties.markwon.SpanFactory; -// @since 4.0.0-SNAPSHOT +// @since 4.0.0 class SimpleExtBuilder { private final List extensions = new ArrayList<>(2); diff --git a/markwon-simple-ext/src/main/java/io/noties/markwon/simple/ext/SimpleExtDelimiterProcessor.java b/markwon-simple-ext/src/main/java/io/noties/markwon/simple/ext/SimpleExtDelimiterProcessor.java index 5cde82fe..924525b0 100644 --- a/markwon-simple-ext/src/main/java/io/noties/markwon/simple/ext/SimpleExtDelimiterProcessor.java +++ b/markwon-simple-ext/src/main/java/io/noties/markwon/simple/ext/SimpleExtDelimiterProcessor.java @@ -9,7 +9,7 @@ import org.commonmark.parser.delimiter.DelimiterRun; import io.noties.markwon.SpanFactory; -// @since 4.0.0-SNAPSHOT +// @since 4.0.0 class SimpleExtDelimiterProcessor implements DelimiterProcessor { private final char open; diff --git a/markwon-simple-ext/src/main/java/io/noties/markwon/simple/ext/SimpleExtNode.java b/markwon-simple-ext/src/main/java/io/noties/markwon/simple/ext/SimpleExtNode.java index d43855e2..8d1173c3 100644 --- a/markwon-simple-ext/src/main/java/io/noties/markwon/simple/ext/SimpleExtNode.java +++ b/markwon-simple-ext/src/main/java/io/noties/markwon/simple/ext/SimpleExtNode.java @@ -7,7 +7,7 @@ import org.commonmark.node.Visitor; import io.noties.markwon.SpanFactory; -// @since 4.0.0-SNAPSHOT +// @since 4.0.0 class SimpleExtNode extends CustomNode { private final SpanFactory spanFactory; diff --git a/markwon-simple-ext/src/main/java/io/noties/markwon/simple/ext/SimpleExtPlugin.java b/markwon-simple-ext/src/main/java/io/noties/markwon/simple/ext/SimpleExtPlugin.java index 48e90359..a5d2cf8c 100644 --- a/markwon-simple-ext/src/main/java/io/noties/markwon/simple/ext/SimpleExtPlugin.java +++ b/markwon-simple-ext/src/main/java/io/noties/markwon/simple/ext/SimpleExtPlugin.java @@ -11,7 +11,7 @@ import io.noties.markwon.SpanFactory; import io.noties.markwon.SpannableBuilder; /** - * @since 4.0.0-SNAPSHOT + * @since 4.0.0 */ public class SimpleExtPlugin extends AbstractMarkwonPlugin { diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml index 7018e3fc..5434d3f5 100644 --- a/sample/src/main/AndroidManifest.xml +++ b/sample/src/main/AndroidManifest.xml @@ -26,6 +26,7 @@ + diff --git a/sample/src/main/java/io/noties/markwon/sample/MainActivity.java b/sample/src/main/java/io/noties/markwon/sample/MainActivity.java index a27d37a9..2614b239 100644 --- a/sample/src/main/java/io/noties/markwon/sample/MainActivity.java +++ b/sample/src/main/java/io/noties/markwon/sample/MainActivity.java @@ -21,6 +21,7 @@ import io.noties.markwon.Markwon; import io.noties.markwon.sample.basicplugins.BasicPluginsActivity; import io.noties.markwon.sample.core.CoreActivity; import io.noties.markwon.sample.customextension.CustomExtensionActivity; +import io.noties.markwon.sample.customextension2.CustomExtensionActivity2; import io.noties.markwon.sample.html.HtmlActivity; import io.noties.markwon.sample.latex.LatexActivity; import io.noties.markwon.sample.recycler.RecyclerActivity; @@ -107,6 +108,10 @@ public class MainActivity extends Activity { activity = SimpleExtActivity.class; break; + case CUSTOM_EXTENSION_2: + activity = CustomExtensionActivity2.class; + break; + default: throw new IllegalStateException("No Activity is associated with sample-item: " + item); } diff --git a/sample/src/main/java/io/noties/markwon/sample/Sample.java b/sample/src/main/java/io/noties/markwon/sample/Sample.java index dbe9bc8a..e892a5ce 100644 --- a/sample/src/main/java/io/noties/markwon/sample/Sample.java +++ b/sample/src/main/java/io/noties/markwon/sample/Sample.java @@ -17,7 +17,9 @@ public enum Sample { HTML(R.string.sample_html), - SIMPLE_EXT(R.string.sample_simple_ext); + SIMPLE_EXT(R.string.sample_simple_ext), + + CUSTOM_EXTENSION_2(R.string.sample_custom_extension_2); private final int textResId; diff --git a/sample/src/main/java/io/noties/markwon/sample/customextension/IconPlugin.java b/sample/src/main/java/io/noties/markwon/sample/customextension/IconPlugin.java index e8459dd3..53c94571 100644 --- a/sample/src/main/java/io/noties/markwon/sample/customextension/IconPlugin.java +++ b/sample/src/main/java/io/noties/markwon/sample/customextension/IconPlugin.java @@ -22,13 +22,6 @@ public class IconPlugin extends AbstractMarkwonPlugin { this.iconSpanProvider = iconSpanProvider; } -// @NonNull -// @Override -// public Priority priority() { -// // define images dependency -// return Priority.after(ImagesPlugin.class); -// } - @Override public void configureParser(@NonNull Parser.Builder builder) { builder.customDelimiterProcessor(IconProcessor.create()); diff --git a/sample/src/main/java/io/noties/markwon/sample/customextension2/CustomExtensionActivity2.java b/sample/src/main/java/io/noties/markwon/sample/customextension2/CustomExtensionActivity2.java new file mode 100644 index 00000000..735d6c0c --- /dev/null +++ b/sample/src/main/java/io/noties/markwon/sample/customextension2/CustomExtensionActivity2.java @@ -0,0 +1,123 @@ +package io.noties.markwon.sample.customextension2; + +import android.app.Activity; +import android.os.Bundle; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import org.commonmark.node.Link; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import io.noties.markwon.AbstractMarkwonPlugin; +import io.noties.markwon.Markwon; +import io.noties.markwon.MarkwonConfiguration; +import io.noties.markwon.MarkwonVisitor; +import io.noties.markwon.RenderProps; +import io.noties.markwon.SpannableBuilder; +import io.noties.markwon.core.CorePlugin; +import io.noties.markwon.core.CoreProps; +import io.noties.markwon.sample.R; + +public class CustomExtensionActivity2 extends Activity { + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_text_view); + + final TextView textView = findViewById(R.id.text_view); + + // let's look for github special links: + // * `#1` - an issue or a pull request + // * `@user` link to a user + + final Markwon markwon = Markwon.builder(this) + .usePlugin(new AbstractMarkwonPlugin() { + @Override + public void configure(@NonNull Registry registry) { + registry.require(CorePlugin.class, corePlugin -> + corePlugin.addOnTextAddedListener(new GithubLinkifyRegexTextAddedListener())); + } + }) + .build(); + + final String md = "# Custom Extension 2\n" + + "\n" + + "This is an issue #1\n" + + "Done by @noties"; + + markwon.setMarkdown(textView, md); + } + + private static class GithubLinkifyRegexTextAddedListener implements CorePlugin.OnTextAddedListener { + + private static final Pattern PATTERN = Pattern.compile("((#\\d+)|(@\\w+))", Pattern.MULTILINE); + + @Override + public void onTextAdded(@NonNull MarkwonVisitor visitor, @NonNull String text, int start) { + + final Matcher matcher = PATTERN.matcher(text); + + String value; + String url; + int index; + + while (matcher.find()) { + + value = matcher.group(1); + + // detect which one it is + if ('#' == value.charAt(0)) { + url = createIssueOrPullRequestLink(value.substring(1)); + } else { + url = createUserLink(value.substring(1)); + } + + // it's important to use `start` value (represents start-index of `text` in the visitor) + index = start + matcher.start(); + + setLink(visitor, url, index, index + value.length()); + } + } + + @NonNull + private String createIssueOrPullRequestLink(@NonNull String number) { + // issues and pull-requests on github follow the same pattern and we + // cannot know for sure which one it is, but if we use issues for all types, + // github will automatically redirect to pull-request if it's the one which is opened + return "https://github.com/noties/Markwon/issues/" + number; + } + + @NonNull + private String createUserLink(@NonNull String user) { + return "https://github.com/" + user; + } + + private void setLink(@NonNull MarkwonVisitor visitor, @NonNull String destination, int start, int end) { + + // might a simpler one, but it doesn't respect possible changes to links +// visitor.builder().setSpan( +// new LinkSpan(visitor.configuration().theme(), destination, visitor.configuration().linkResolver()), +// start, +// end +// ); + + // use default handlers for links + final MarkwonConfiguration configuration = visitor.configuration(); + final RenderProps renderProps = visitor.renderProps(); + + CoreProps.LINK_DESTINATION.set(renderProps, destination); + + SpannableBuilder.setSpans( + visitor.builder(), + configuration.spansFactory().require(Link.class).getSpans(configuration, renderProps), + start, + end + ); + } + } +} diff --git a/sample/src/main/res/values/strings-samples.xml b/sample/src/main/res/values/strings-samples.xml index a624f921..c1206e4b 100644 --- a/sample/src/main/res/values/strings-samples.xml +++ b/sample/src/main/res/values/strings-samples.xml @@ -20,4 +20,7 @@ # \# SimpleExt\n\nShows how to use SimpleExtPlugin module to create own delimited parser extensions + # \# Custom extension 2\n\nAutomatically + convert `#1` and `@user` to Github links + \ No newline at end of file From b7606c7ee77ffa7cd0ea3f9be7e048026efe36ea Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Wed, 26 Jun 2019 18:48:00 +0300 Subject: [PATCH 39/42] Update CHANGELOG --- CHANGELOG.md | 97 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 71 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f267a59..7551a2a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ # 4.0.0 * maven group-id change to `io.noties.markwon` (was `ru.noties.markwon`) * package name change to `io.notier.markwon.*` (was `ru.noties.markwon.*`) -* androidx artifacts (#76) +* androidx artifacts ([#76]) * `Markwon#builder` does not require explicit `CorePlugin` (added automatically), use `Markwon#builderNoCore()` to obtain a builder without `CorePlugin` * Removed `Priority` abstraction and `MarkwonPlugin#priority` (use `MarkwonPlugin.Registry`) @@ -27,18 +27,27 @@ use `Markwon#builderNoCore()` to obtain a builder without `CorePlugin` * `ImageItem` is now abstract, has 2 implementations: `withResult`, `withDecodingNeeded` * Add `images-glide`, `images-picasso`, `linkify`, `simple-ext` modules * `JLatexMathPlugin` is now independent of `ImagesPlugin` -* Fix wrong `JLatexMathPlugin` formulas sizes (#138) +* Fix wrong `JLatexMathPlugin` formulas sizes ([#138]) * `JLatexMathPlugin` has `backgroundProvider`, `executorService` configuration * `HtmlPlugin` is self-contained (all configuration is moved in the plugin itself) +[#76]: https://github.com/noties/Markwon/issues/76 +[#138]: https://github.com/noties/Markwon/issues/138 + + ## 3.0.2 -* Fix `latex` plugin (#136) -* Add `#create(Call.Factory)` factory method to `OkHttpImagesPlugin` (#129) -
      Thanks to @ZacSweers +* Fix `latex` plugin ([#136]) +* Add `#create(Call.Factory)` factory method to `OkHttpImagesPlugin` ([#129]) +
      Thanks to [@ZacSweers] + +[#136]: https://github.com/noties/Markwon/issues/136 +[#129]: https://github.com/noties/Markwon/issues/129 +[@ZacSweers]: https://github.com/ZacSweers + ## 3.0.1 -* Add `AsyncDrawableLoader.Builder#implementation` method (#109) -* AsyncDrawable allow placeholder to have independent size (#115) +* Add `AsyncDrawableLoader.Builder#implementation` method ([#109]) +* AsyncDrawable allow placeholder to have independent size ([#115]) * `addFactory` method for MarkwonSpansFactory * Add optional spans for list blocks (bullet and ordered) * AsyncDrawable placeholder bounds fix @@ -46,6 +55,10 @@ use `Markwon#builderNoCore()` to obtain a builder without `CorePlugin` * Add `requireFactory` method to MarkwonSpansFactory * Add DrawableUtils +[#109]: https://github.com/noties/Markwon/issues/109 +[#115]: https://github.com/noties/Markwon/issues/115 + + ## 3.0.0 * Plugins, plugins, plugins * Split basic functionality blocks into standalone modules @@ -86,16 +99,23 @@ to get the full picture of latest changes. ## 2.0.1 * `SpannableMarkdownVisitor` Rename blockQuoteIndent to blockIndent -* Fixed block new lines logic for block quote and paragraph (#82) -* AsyncDrawable fix no dimensions bug (#81) +* Fixed block new lines logic for block quote and paragraph ([#82]) +* AsyncDrawable fix no dimensions bug ([#81]) * Update SpannableTheme to use Px instead of Dimension annotation * Allow TaskListSpan isDone mutation * Updated commonmark-java to 0.12.1 -* Add OrderedListItemSpan measure utility method (#78) +* Add OrderedListItemSpan measure utility method ([#78]) * Add SpannableBuilder#getSpans method -* Fix DataUri scheme handler in image-loader (#74) +* Fix DataUri scheme handler in image-loader ([#74]) * Introduced a "copy" builder for SpannableThem -
      Thanks @c-b-h +
      Thanks [@c-b-h] + +[#82]: https://github.com/noties/Markwon/issues/82 +[#81]: https://github.com/noties/Markwon/issues/81 +[#78]: https://github.com/noties/Markwon/issues/78 +[#74]: https://github.com/noties/Markwon/issues/74 +[@c-b-h]: https://github.com/c-b-h + ## 2.0.0 * Add `html-parser-api` and `html-parser-impl` modules @@ -118,24 +138,35 @@ to get the full picture of latest changes. * Add sample-latex-math module ## v1.1.1 -* Fix OrderedListItemSpan text position (baseline) (#55) -* Add softBreakAddsNewLine option for SpannableConfiguration (#54) -* Paragraph text can now explicitly be spanned (#58) -
      Thanks to @c-b-h -* Fix table border color if odd background is specified (#56) +* Fix OrderedListItemSpan text position (baseline) ([#55]) +* Add softBreakAddsNewLine option for SpannableConfiguration ([#54]) +* Paragraph text can now explicitly be spanned ([#58]) +
      Thanks to [@c-b-h] +* Fix table border color if odd background is specified ([#56]) * Add table customizations (even and header rows) +[#55]: https://github.com/noties/Markwon/issues/55 +[#54]: https://github.com/noties/Markwon/issues/54 +[#58]: https://github.com/noties/Markwon/issues/58 +[#56]: https://github.com/noties/Markwon/issues/56 +[@c-b-h]: https://github.com/c-b-h + + ## v1.1.0 * Update commonmark to 0.11.0 and android-gif to 1.2.14 * Add syntax highlight functionality (`library-syntax` module and `markwon-syntax` artifact) * Add headingTypeface, headingTextSizes to SpannableTheme -
      Thanks to @edenman +
      Thanks to [@edenman] * Introduce `MediaDecoder` abstraction to `image-loader` module * Introduce `SpannableFactory` -
      Thanks for idea to @c-b-h +
      Thanks for idea to [@c-b-h] * Update sample application to use syntax-highlight * Update sample application to use clickable placeholder for GIF media +[@edenman]: https://github.com/edenman +[@c-b-h]: https://github.com/c-b-h + + ## v1.0.6 * Fix bullet list item size (depend on text size and not top-bottom arguments) * Add ability to specify MovementMethod when applying markdown to a TextView @@ -146,13 +177,21 @@ to `ru.noties.markwon.renderer` package (one level up, previously `ru.noties.mar ## v1.0.5 * Change LinkSpan to extend URLSpan. Allow default linkColor (if not set explicitly) * Fit an image without dimensions to canvas width (and keep ratio) -* Add support for separate color for code blocks (#37) -
      Thanks to @Arcnor +* Add support for separate color for code blocks ([#37]) +
      Thanks to [@Arcnor] + +[#37]: https://github.com/noties/Markwon/issues/37 +[@Arcnor]: https://github.com/Arcnor + ## v1.0.4 -* Fixes #28 (tables are not rendered when at the end of the markdown) +* Fixes [#28] (tables are not rendered when at the end of the markdown) * Adds support for `indented code blocks` -
      Thanks to @dlew +
      Thanks to [@dlew] + +[#28]: https://github.com/noties/Markwon/issues/ +[@dlew]: https://github.com/dlew + ## v1.0.3 * Fixed ordered lists (when number width is greater than block margin) @@ -163,11 +202,17 @@ to `ru.noties.markwon.renderer` package (one level up, previously `ru.noties.mar * Tables can have no borders ## v1.0.1 -* Support for task-lists (#2) -* Spans now are applied in reverse order (#5 #10) +* Support for task-lists ([#2]) +* Spans now are applied in reverse order ([#5] [#10]) * Added `SpannableBuilder` to follow the reverse order of spans * Updated `commonmark-java` to `0.10.0` -* Fixes #1 +* Fixes [#1] + +[#1]: https://github.com/noties/Markwon/issues/1 +[#2]: https://github.com/noties/Markwon/issues/2 +[#5]: https://github.com/noties/Markwon/issues/5 +[#10]: https://github.com/noties/Markwon/issues/10 + ## v1.0.0 From f99952ec0143e14164a4d809665551c2d625dce9 Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Wed, 26 Jun 2019 19:05:23 +0300 Subject: [PATCH 40/42] Ensure README in all modules --- markwon-core/README.md | 3 ++ markwon-ext-latex/README.md | 12 +----- markwon-ext-strikethrough/README.md | 36 +--------------- markwon-ext-tables/README.md | 46 +------------------- markwon-ext-tasklist/README.md | 3 ++ markwon-html/README.md | 3 ++ markwon-image-glide/README.md | 3 ++ markwon-image-picasso/README.md | 3 ++ markwon-image/README.md | 3 ++ markwon-linkify/README.md | 1 + markwon-recycler-table/README.md | 3 ++ markwon-recycler/README.md | 3 ++ markwon-simple-ext/README.md | 3 ++ markwon-syntax-highlight/README.md | 65 +---------------------------- 14 files changed, 36 insertions(+), 151 deletions(-) create mode 100644 markwon-core/README.md create mode 100644 markwon-ext-tasklist/README.md create mode 100644 markwon-html/README.md create mode 100644 markwon-image-glide/README.md create mode 100644 markwon-image-picasso/README.md create mode 100644 markwon-image/README.md create mode 100644 markwon-recycler-table/README.md create mode 100644 markwon-recycler/README.md create mode 100644 markwon-simple-ext/README.md diff --git a/markwon-core/README.md b/markwon-core/README.md new file mode 100644 index 00000000..1d8653c2 --- /dev/null +++ b/markwon-core/README.md @@ -0,0 +1,3 @@ +# Markwon Core + +https://noties.io/Markwon/docs/v4/core/getting-started.html \ No newline at end of file diff --git a/markwon-ext-latex/README.md b/markwon-ext-latex/README.md index 442fc61e..aad7a9ea 100644 --- a/markwon-ext-latex/README.md +++ b/markwon-ext-latex/README.md @@ -1,11 +1,3 @@ -# LaTeX +# LaTeX Extension -![stable](https://img.shields.io/maven-central/v/io.noties.markwon/ext-latex.svg) -![snapshot](https://img.shields.io/nexus/s/https/oss.sonatype.org/io.noties.markwon/ext-latex.svg) - -```kotlin -implementation "io.noties.markwon:ext-strikethrough:${markwonVersion}" -``` - - -[Documentation](https://noties.github.io/Markwon/docs/v3/ext-latex) +https://noties.io/Markwon/docs/v4/ext-latex/ diff --git a/markwon-ext-strikethrough/README.md b/markwon-ext-strikethrough/README.md index 8ef64b38..c8bd9c60 100644 --- a/markwon-ext-strikethrough/README.md +++ b/markwon-ext-strikethrough/README.md @@ -1,35 +1,3 @@ -# Strikethrough +# Strikethrough Extension -![stable](https://img.shields.io/maven-central/v/io.noties.markwon/ext-strikethrough.svg) -![snapshot](https://img.shields.io/nexus/s/https/oss.sonatype.org/io.noties.markwon/ext-strikethrough.svg) - -```kotlin -implementation "io.noties.markwon:ext-strikethrough:${markwonVersion}" -``` - - -This module adds `strikethrough` functionality to `Markwon` via `StrikethroughPlugin`: - -```java -Markwon.builder(context) - .usePlugin(StrikethroughPlugin.create()) -``` - -This plugin registers `SpanFactory` for `Strikethrough` node, so it's possible to customize Strikethrough Span that is used in rendering: - -```java -Markwon.builder(context) - .usePlugin(StrikethroughPlugin.create()) - .usePlugin(new AbstractMarkwonPlugin() { - @Override - public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) { - builder.setFactory(Strikethrough.class, new SpanFactory() { - @Override - public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) { - // will use Underline span instead of Strikethrough - return new UnderlineSpan(); - } - }); - } - }) -``` \ No newline at end of file +https://noties.io/Markwon/docs/v4/ext-strikethrough/ \ No newline at end of file diff --git a/markwon-ext-tables/README.md b/markwon-ext-tables/README.md index 5bb0effd..fce38a27 100644 --- a/markwon-ext-tables/README.md +++ b/markwon-ext-tables/README.md @@ -1,45 +1,3 @@ -# Tables +# Tables Extension -[![ext-tables](https://img.shields.io/maven-central/v/io.noties.markwon/ext-tables.svg?label=ext-tables)](http://search.maven.org/#search|ga|1|g%3A%22io.noties.markwon%22%20AND%20a%3A%22ext-tables%22) - -This extension adds support for GFM tables. - -```java -final Markwon markwon = Markwon.builder(context) - // create default instance of TablePlugin - .usePlugin(TablePlugin.create(context)) -``` - -```java -final TableTheme tableTheme = TableTheme.builder() - .tableBorderColor(Color.RED) - .tableBorderWidth(0) - .tableCellPadding(0) - .tableHeaderRowBackgroundColor(Color.BLACK) - .tableEvenRowBackgroundColor(Color.GREEN) - .tableOddRowBackgroundColor(Color.YELLOW) - .build(); - -final Markwon markwon = Markwon.builder(context) - .usePlugin(TablePlugin.create(tableTheme)) -``` - -Please note, that _by default_ tables have limitations. For example, there is no support -for images inside table cells. And table contents won't be copied to clipboard if a TextView -has such functionality. Table will always take full width of a TextView in which it is displayed. -All columns will always be the of the same width. So, _default_ implementation provides basic -functionality which can answer some needs. These all come from the limited nature of the TextView -to display such content. - -In order to provide full-fledged experience, tables must be displayed in a special widget. -Since version `3.0.0` Markwon provides a special artifact `markwon-recycler` that allows -to render markdown in a set of widgets in a RecyclerView. It also gives ability to change -display widget form TextView to any other. - -```java -final Table table = Table.parse(Markwon, TableBlock); -myTableWidget.setTable(table); -``` - -Unfortunately Markwon does not provide a widget that can be used for tables. But it does -provide API that can be used to achieve desired result. +https://noties.io/Markwon/docs/v4/ext-tables/ diff --git a/markwon-ext-tasklist/README.md b/markwon-ext-tasklist/README.md new file mode 100644 index 00000000..d86b540c --- /dev/null +++ b/markwon-ext-tasklist/README.md @@ -0,0 +1,3 @@ +# Task-list Extension + +https://noties.io/Markwon/docs/v4/ext-tasklist/ \ No newline at end of file diff --git a/markwon-html/README.md b/markwon-html/README.md new file mode 100644 index 00000000..1e165bd6 --- /dev/null +++ b/markwon-html/README.md @@ -0,0 +1,3 @@ +# HTML + +https://noties.io/Markwon/docs/v4/html/ \ No newline at end of file diff --git a/markwon-image-glide/README.md b/markwon-image-glide/README.md new file mode 100644 index 00000000..59fb1db0 --- /dev/null +++ b/markwon-image-glide/README.md @@ -0,0 +1,3 @@ +# Images (Glide) + +https://noties.io/Markwon/docs/v4/image-glide/ \ No newline at end of file diff --git a/markwon-image-picasso/README.md b/markwon-image-picasso/README.md new file mode 100644 index 00000000..be648fee --- /dev/null +++ b/markwon-image-picasso/README.md @@ -0,0 +1,3 @@ +# Images (Picasso) + +https://noties.io/Markwon/docs/v4/image-picasso/ \ No newline at end of file diff --git a/markwon-image/README.md b/markwon-image/README.md new file mode 100644 index 00000000..fd86cbf4 --- /dev/null +++ b/markwon-image/README.md @@ -0,0 +1,3 @@ +# Images + +https://noties.io/Markwon/docs/v4/image/ \ No newline at end of file diff --git a/markwon-linkify/README.md b/markwon-linkify/README.md index 437ce4e4..08bdc0c9 100644 --- a/markwon-linkify/README.md +++ b/markwon-linkify/README.md @@ -1,2 +1,3 @@ # Linkify +https://noties.io/Markwon/docs/v4/linkify/ \ No newline at end of file diff --git a/markwon-recycler-table/README.md b/markwon-recycler-table/README.md new file mode 100644 index 00000000..786cece9 --- /dev/null +++ b/markwon-recycler-table/README.md @@ -0,0 +1,3 @@ +# Recycler Table + +https://noties.io/Markwon/docs/v4/recycler-table/ \ No newline at end of file diff --git a/markwon-recycler/README.md b/markwon-recycler/README.md new file mode 100644 index 00000000..cbe20950 --- /dev/null +++ b/markwon-recycler/README.md @@ -0,0 +1,3 @@ +# Recycler + +https://noties.io/Markwon/docs/v4/recycler/ \ No newline at end of file diff --git a/markwon-simple-ext/README.md b/markwon-simple-ext/README.md new file mode 100644 index 00000000..51f8be2f --- /dev/null +++ b/markwon-simple-ext/README.md @@ -0,0 +1,3 @@ +# Simple Extension + +https://noties.io/Markwon/docs/v4/simple-ext/ \ No newline at end of file diff --git a/markwon-syntax-highlight/README.md b/markwon-syntax-highlight/README.md index 4c7a0c74..e7892419 100644 --- a/markwon-syntax-highlight/README.md +++ b/markwon-syntax-highlight/README.md @@ -1,64 +1,3 @@ -# Markwon-syntax +# Syntax Highlight -This is a simple module to add **syntax-highlight** functionality to your markdown rendered with Markwon library. It is based on [Prism4j](https://github.com/noties/Prism4j) so lead there to understand how to configure `Prism4j` instance. - -![theme-default](../art/markwon-syntax-default.png) - -![theme-darkula](../art/markwon-syntax-darkula.png) - ---- - -First, we need to obtain an instance of `Prism4jSyntaxHighlight` which implements Markwon's `SyntaxHighlight`: - -```java -final SyntaxHighlight highlight = - Prism4jSyntaxHighlight.create(Prism4j, Prism4jTheme); -``` - -we also can obtain an instance of `Prism4jSyntaxHighlight` that has a _fallback_ option (if a language is not defined in `Prism4j` instance, fallback language can be used): - -```java -final SyntaxHighlight highlight = - Prism4jSyntaxHighlight.create(Prism4j, Prism4jTheme, String); -``` - -Generally obtaining a `Prism4j` instance is pretty easy: - -```java -final Prism4j prism4j = new Prism4j(new GrammarLocatorDef()); -``` - -Where `GrammarLocatorDef` is a generated grammar locator (if you use `prism4j-bundler` annotation processor) - -`Prism4jTheme` is a specific type that is defined in this module (`prism4j` doesn't know anything about rendering). It has 2 implementations: - -* `Prism4jThemeDefault` -* `Prism4jThemeDarkula` - -Both of them can be obtained via factory method `create`: - -* `Prism4jThemeDefault.create()` -* `Prism4jThemeDarkula.create()` - -But of cause nothing is stopping you from defining your own theme: - -```java -public interface Prism4jTheme { - - @ColorInt - int background(); - - @ColorInt - int textColor(); - - void apply( - @NonNull String language, - @NonNull Prism4j.Syntax syntax, - @NonNull SpannableStringBuilder builder, - int start, - int end - ); -} -``` - -> You can extend `Prism4jThemeBase` which has some helper methods +https://noties.io/Markwon/docs/v4/syntax-highlight/ \ No newline at end of file From 1407ae0cf873a192d3d8b2dd255f6278067aa8d1 Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Mon, 1 Jul 2019 15:24:33 +0300 Subject: [PATCH 41/42] Prepare 4.0.0 release --- gradle.properties | 2 +- .../src/main/java/io/noties/markwon/image/MediaDecoder.java | 2 +- .../src/main/java/io/noties/markwon/image/SchemeHandler.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gradle.properties b/gradle.properties index 2642f708..26870ef3 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,7 +8,7 @@ android.enableJetifier=true android.enableBuildCache=true android.buildCacheDir=build/pre-dex-cache -VERSION_NAME=4.0.0-SNAPSHOT +VERSION_NAME=4.0.0 GROUP=io.noties.markwon POM_DESCRIPTION=Markwon markdown for Android diff --git a/markwon-image/src/main/java/io/noties/markwon/image/MediaDecoder.java b/markwon-image/src/main/java/io/noties/markwon/image/MediaDecoder.java index f5f115e0..39a6f013 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/MediaDecoder.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/MediaDecoder.java @@ -14,7 +14,7 @@ import java.util.Collection; public abstract class MediaDecoder { /** - * Changes since 4.0.0-SNAPSHOT: + * Changes since 4.0.0: *

        *
      • Returns `non-null` drawable
      • *
      • Added `contentType` method parameter
      • diff --git a/markwon-image/src/main/java/io/noties/markwon/image/SchemeHandler.java b/markwon-image/src/main/java/io/noties/markwon/image/SchemeHandler.java index 89bd4877..25268f6b 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/SchemeHandler.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/SchemeHandler.java @@ -12,7 +12,7 @@ import java.util.Collection; public abstract class SchemeHandler { /** - * Changes since 4.0.0-SNAPSHOT: + * Changes since 4.0.0: *
          *
        • Returns `non-null` image-item
        • *
        From aa64aa70204f9f66f52ceb01a65b9a9ac6019007 Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Mon, 1 Jul 2019 19:50:33 +0300 Subject: [PATCH 42/42] Update documentation to 4.0.0 --- docs/.vuepress/config.js | 79 +++++++++++++-------------- docs/README.md | 20 +++---- docs/docs/v3/ext-tables/README.md | 2 +- docs/docs/v4/ext-tables/README.md | 2 +- docs/docs/v4/migration-3-4.md | 7 --- docs/docs/v4/recycler-table/README.md | 2 +- docs/docs/v4/recycler/README.md | 2 +- 7 files changed, 53 insertions(+), 61 deletions(-) delete mode 100644 docs/docs/v4/migration-3-4.md diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index 95ea14f8..de897e67 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -12,12 +12,12 @@ module.exports = { ], themeConfig: { nav: [ - { text: 'Install', link: '/docs/v3/install.md' }, + { text: 'Install', link: '/docs/v4/install.md' }, { text: 'API Version', items: [ - { text: 'Current (3.x.x)', link: '/' }, - { text: 'Beta (4.x.x)', link: '/docs/v4/install.md' }, + { text: 'Current (4.x.x)', link: '/' }, + { text: 'Legacy (3.x.x)', link: '/docs/v3/install.md' }, { text: 'Legacy (2.x.x)', link: '/docs/v2/' } ] }, @@ -36,42 +36,8 @@ module.exports = { '/docs/v2/html.md', '/docs/v2/view.md' ], - '/docs/v4': [ - '/docs/v4/install.md', - { - title: 'Core', - collapsable: false, - children: [ - '/docs/v4/core/getting-started.md', - '/docs/v4/core/plugins.md', - '/docs/v4/core/registry.md', - '/docs/v4/core/theme.md', - '/docs/v4/core/configuration.md', - '/docs/v4/core/visitor.md', - '/docs/v4/core/spans-factory.md', - '/docs/v4/core/core-plugin.md', - '/docs/v4/core/movement-method-plugin.md', - '/docs/v4/core/render-props.md' - ] - }, - '/docs/v4/ext-latex/', - '/docs/v4/ext-strikethrough/', - '/docs/v4/ext-tables/', - '/docs/v4/ext-tasklist/', - '/docs/v4/html/', - '/docs/v4/image/', - '/docs/v4/image-glide/', - '/docs/v4/image-picasso/', - '/docs/v4/linkify/', - '/docs/v4/recycler/', - '/docs/v4/recycler-table/', - '/docs/v4/simple-ext/', - '/docs/v4/syntax-highlight/', - '/docs/v4/recipes.md', - '/docs/v4/migration-3-4.md' - ], - '/': [ - '', + '/docs/v3': [ + '/docs/v3/install.md', { title: 'Core', collapsable: false, @@ -101,7 +67,40 @@ module.exports = { '/docs/v3/recycler-table/', '/docs/v3/syntax-highlight/', '/docs/v3/migration-2-3.md' - ] + ], + '/': [ + '', + { + title: 'Core', + collapsable: false, + children: [ + '/docs/v4/core/getting-started.md', + '/docs/v4/core/plugins.md', + '/docs/v4/core/registry.md', + '/docs/v4/core/theme.md', + '/docs/v4/core/configuration.md', + '/docs/v4/core/visitor.md', + '/docs/v4/core/spans-factory.md', + '/docs/v4/core/core-plugin.md', + '/docs/v4/core/movement-method-plugin.md', + '/docs/v4/core/render-props.md' + ] + }, + '/docs/v4/ext-latex/', + '/docs/v4/ext-strikethrough/', + '/docs/v4/ext-tables/', + '/docs/v4/ext-tasklist/', + '/docs/v4/html/', + '/docs/v4/image/', + '/docs/v4/image-glide/', + '/docs/v4/image-picasso/', + '/docs/v4/linkify/', + '/docs/v4/recycler/', + '/docs/v4/recycler-table/', + '/docs/v4/simple-ext/', + '/docs/v4/syntax-highlight/', + '/docs/v4/recipes.md' + ], }, sidebarDepth: 2, lastUpdated: true diff --git a/docs/README.md b/docs/README.md index d1acc437..abab2311 100644 --- a/docs/README.md +++ b/docs/README.md @@ -5,7 +5,7 @@ title: 'Introduction' Markwon Logo

        -[![markwon](https://img.shields.io/maven-central/v/ru.noties.markwon/core.svg?label=markwon)](http://search.maven.org/#search|ga|1|g%3A%22ru.noties.markwon%22%20) +[![markwon](https://img.shields.io/maven-central/v/io.noties.markwon/core.svg?label=markwon)](http://search.maven.org/#search|ga|1|g%3A%22io.noties.markwon%22%20) [![Build Status](https://travis-ci.org/noties/Markwon.svg?branch=master)](https://travis-ci.org/noties/Markwon) **Markwon** is a markdown library for Android. It parses markdown following @@ -27,17 +27,17 @@ listed in are supported (including support for * * Strong emphasis (`**`, `__`) * Headers (`#{1,6}`) * Links (`[]()` && `[][]`) -* [Images](/docs/v3/core/images.md) +* [Images](/docs/v4/image/) * Thematic break (`---`, `***`, `___`) * Quotes & nested quotes (`>{1,}`) * Ordered & non-ordered lists & nested ones * Inline code * Code blocks -* [Strike-through](/docs/v3/ext-strikethrough/) (`~~`) -* [Tables](/docs/v3/ext-tables/) (*with limitations*) -* [Syntax highlight](/docs/v3/syntax-highlight/) -* [LaTeX](/docs/v3/ext-latex/) formulas -* [HTML](/docs/v3/html/) +* [Strike-through](/docs/v4/ext-strikethrough/) (`~~`) +* [Tables](/docs/v4/ext-tables/) (*with limitations*) +* [Syntax highlight](/docs/v4/syntax-highlight/) +* [LaTeX](/docs/v4/ext-latex/) formulas +* [HTML](/docs/v4/html/) * Emphasis (``, ``, ``, ``) * Strong emphasis (``, ``) * SuperScript (``) @@ -49,9 +49,9 @@ listed in are supported (including support for * * Images (`img` will require configured image loader) * Blockquote (`blockquote`) * Heading (`h1`, `h2`, `h3`, `h4`, `h5`, `h6`) - * there is support to render any HTML tag, but it will require to create a special `TagHandler`, - more information can be found in [HTML section](/docs/v3/core/html-renderer.md) -* [Task lists](/docs/v3/ext-tasklist/): + * there is support to render any HTML/XML tag, but it will require to create a special `TagHandler`, + more information can be found in [HTML section](/docs/v4/html/#taghandler) +* [Task lists](/docs/v4/ext-tasklist/):
        • Not done
        • Done with X
        • diff --git a/docs/docs/v3/ext-tables/README.md b/docs/docs/v3/ext-tables/README.md index 8c75fc21..49282a05 100644 --- a/docs/docs/v3/ext-tables/README.md +++ b/docs/docs/v3/ext-tables/README.md @@ -56,7 +56,7 @@ myTableWidget.setTable(table); :::tip To take advantage of this functionality and render tables without limitations (including -horizontally scrollable layout when its contents exceed screen width), refer to [recycler-table](/docs/v3/recycler-table/) +horizontally scrollable layout when its contents exceed screen width), refer to [recycler-table](/docs/v4/recycler-table/) module documentation that adds support for rendering `TableBlock` markdown node inside Android-native `TableLayout` widget. ::: diff --git a/docs/docs/v4/ext-tables/README.md b/docs/docs/v4/ext-tables/README.md index 04df9c5e..403cdb92 100644 --- a/docs/docs/v4/ext-tables/README.md +++ b/docs/docs/v4/ext-tables/README.md @@ -56,7 +56,7 @@ myTableWidget.setTable(table); :::tip To take advantage of this functionality and render tables without limitations (including -horizontally scrollable layout when its contents exceed screen width), refer to [recycler-table](/docs/v3/recycler-table/) +horizontally scrollable layout when its contents exceed screen width), refer to [recycler-table](/docs/v4/recycler-table/) module documentation that adds support for rendering `TableBlock` markdown node inside Android-native `TableLayout` widget. ::: diff --git a/docs/docs/v4/migration-3-4.md b/docs/docs/v4/migration-3-4.md deleted file mode 100644 index 8dd6bc5d..00000000 --- a/docs/docs/v4/migration-3-4.md +++ /dev/null @@ -1,7 +0,0 @@ -# Migration 3.x.x -> 4.x.x - -* maven group-id is changed: `io.noties.markwon` (was `ru.noties.markwon`) -* root package-name is changed: `io.noties.markwon` (was `ru.noties.markwon`) -* `androidx` packages - -todo \ No newline at end of file diff --git a/docs/docs/v4/recycler-table/README.md b/docs/docs/v4/recycler-table/README.md index 1841e832..b8d9c193 100644 --- a/docs/docs/v4/recycler-table/README.md +++ b/docs/docs/v4/recycler-table/README.md @@ -2,7 +2,7 @@ -Artifact that provides [MarkwonAdapter.Entry](/docs/v3/recycler/) to render `TableBlock` inside +Artifact that provides [MarkwonAdapter.Entry](/docs/v4/recycler/) to render `TableBlock` inside Android-native `TableLayout` widget. screenshot diff --git a/docs/docs/v4/recycler/README.md b/docs/docs/v4/recycler/README.md index 2273915e..175d333c 100644 --- a/docs/docs/v4/recycler/README.md +++ b/docs/docs/v4/recycler/README.md @@ -149,5 +149,5 @@ parsed only once and each subsequent adapter binding call will reuse previously :::tip Tables There is a standalone artifact that adds support for displaying markdown tables -natively via `TableLayout`. Please refer to its [documentation](/docs/v3/recycler-table/) +natively via `TableLayout`. Please refer to its [documentation](/docs/v4/recycler-table/) ::: \ No newline at end of file