Preparing 4.0.0 release

This commit is contained in:
Dimitry Ivanov 2019-06-26 17:57:33 +03:00
parent d65a1809ca
commit 386254f962
51 changed files with 504 additions and 149 deletions

View File

@ -1,9 +1,40 @@
# Changelog # 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) * Fix `latex` plugin (#136)
* Add `#create(Call.Factory)` factory method to `OkHttpImagesPlugin` (#129) * Add `#create(Call.Factory)` factory method to `OkHttpImagesPlugin` (#129)
thanks to @ZacSweers <br>Thanks to @ZacSweers
## 3.0.1 ## 3.0.1
* Add `AsyncDrawableLoader.Builder#implementation` method (#109) * Add `AsyncDrawableLoader.Builder#implementation` method (#109)
@ -64,7 +95,7 @@ to get the full picture of latest changes.
* Add SpannableBuilder#getSpans method * 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 * Introduced a "copy" builder for SpannableThem
Thanks @c-b-h <br>Thanks @c-b-h
## 2.0.0 ## 2.0.0
* Add `html-parser-api` and `html-parser-impl` modules * 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) * Fix OrderedListItemSpan text position (baseline) (#55)
* Add softBreakAddsNewLine option for SpannableConfiguration (#54) * Add softBreakAddsNewLine option for SpannableConfiguration (#54)
* Paragraph text can now explicitly be spanned (#58) * Paragraph text can now explicitly be spanned (#58)
Thanks to @c-b-h <br>Thanks to @c-b-h
* Fix table border color if odd background is specified (#56) * Fix table border color if odd background is specified (#56)
* Add table customizations (even and header rows) * 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 * 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 syntax highlight functionality (`library-syntax` module and `markwon-syntax` artifact)
* Add headingTypeface, headingTextSizes to SpannableTheme * Add headingTypeface, headingTextSizes to SpannableTheme
Thanks to @edenman <br>Thanks to @edenman
* Introduce `MediaDecoder` abstraction to `image-loader` module * Introduce `MediaDecoder` abstraction to `image-loader` module
* Introduce `SpannableFactory` * Introduce `SpannableFactory`
Thanks for idea to @c-b-h <br>Thanks for idea to @c-b-h
* Update sample application to use syntax-highlight * Update sample application to use syntax-highlight
* Update sample application to use clickable placeholder for GIF media * 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) * Change LinkSpan to extend URLSpan. Allow default linkColor (if not set explicitly)
* Fit an image without dimensions to canvas width (and keep ratio) * Fit an image without dimensions to canvas width (and keep ratio)
* Add support for separate color for code blocks (#37) * Add support for separate color for code blocks (#37)
Thanks to @Arcnor <br>Thanks to @Arcnor
## v1.0.4 ## 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` * Adds support for `indented code blocks`
Thanks to @dlew <br>Thanks to @dlew
## v1.0.3 ## v1.0.3
* Fixed ordered lists (when number width is greater than block margin) * Fixed ordered lists (when number width is greater than block margin)

View File

@ -35,13 +35,14 @@ features listed in [commonmark-spec] are supported
implementation "io.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) 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. of the [documentation] web-site.
Please visit [documentation] web-site for further reference. 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: ## Supported markdown features:

View File

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

View File

@ -34,7 +34,6 @@ dependencies {
implementation project(':markwon-ext-tasklist') implementation project(':markwon-ext-tasklist')
implementation project(':markwon-html') implementation project(':markwon-html')
implementation project(':markwon-image') implementation project(':markwon-image')
implementation project(':markwon-linkify')
implementation project(':markwon-syntax-highlight') implementation project(':markwon-syntax-highlight')
deps.with { deps.with {

View File

@ -1,3 +1,27 @@
# Image Glide # Image Glide
<MavenBadge4 :artifact="'image-glide'" /> <MavenBadge4 :artifact="'image-glide'" />
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<Drawable> load(@NonNull AsyncDrawable drawable) {
return Glide.with(context).load(drawable.getDestination());
}
@Override
public void cancel(@NonNull Target<?> target) {
Glide.with(context).clear(target);
}
}))
.build();
```

View File

@ -1,3 +1,32 @@
# Image Picasso # Image Picasso
<MavenBadge4 :artifact="'image-picasso'" /> <MavenBadge4 :artifact="'image-picasso'" />
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();
```

View File

@ -194,15 +194,153 @@ introduce any unexpected behavior.
### GifMediaDecoder ### 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 ### 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
`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
`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 <Badge text="4.0.0" /> 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 ## 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 :::tip
If you are using [html](/docs/v4/html/) you do not have to additionally setup If you are using [html](/docs/v4/html/) you do not have to additionally setup

View File

@ -1,3 +1,31 @@
# Linkify # Linkify
<MavenBadge4 :artifact="'linkify'" /> <MavenBadge4 :artifact="'linkify'" />
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();
```

View File

@ -2,5 +2,6 @@
* maven group-id is changed: `io.noties.markwon` (was `ru.noties.markwon`) * maven group-id is changed: `io.noties.markwon` (was `ru.noties.markwon`)
* root package-name is changed: `io.noties.markwon` (was `ru.noties.markwon`) * root package-name is changed: `io.noties.markwon` (was `ru.noties.markwon`)
* `androidx` packages
todo todo

View File

@ -60,3 +60,11 @@ This extension will be applied to a text like this:
```md ```md
@@we are inside different delimiter characters$$ @@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
:::

View File

@ -7,7 +7,7 @@ import androidx.annotation.NonNull;
/** /**
* @see LinkResolverDef * @see LinkResolverDef
* @see MarkwonConfiguration.Builder#linkResolver(LinkResolver) * @see MarkwonConfiguration.Builder#linkResolver(LinkResolver)
* @since 4.0.0-SNAPSHOT * @since 4.0.0
*/ */
public interface LinkResolver { public interface LinkResolver {
void resolve(@NonNull View view, @NonNull String link); void resolve(@NonNull View view, @NonNull String link);

View File

@ -47,14 +47,14 @@ public abstract class Markwon {
@NonNull @NonNull
public static Builder builder(@NonNull Context context) { public static Builder builder(@NonNull Context context) {
return new MarkwonBuilderImpl(context) return new MarkwonBuilderImpl(context)
// @since 4.0.0-SNAPSHOT add CorePlugin // @since 4.0.0 add CorePlugin
.usePlugin(CorePlugin.create()); .usePlugin(CorePlugin.create());
} }
/** /**
* Factory method to obtain an instance of {@link Builder} without {@link CorePlugin}. * Factory method to obtain an instance of {@link Builder} without {@link CorePlugin}.
* *
* @since 4.0.0-SNAPSHOT * @since 4.0.0
*/ */
@NonNull @NonNull
public static Builder builderNoCore(@NonNull Context context) { public static Builder builderNoCore(@NonNull Context context) {

View File

@ -95,7 +95,7 @@ public class MarkwonConfiguration {
} }
/** /**
* @since 4.0.0-SNAPSHOT * @since 4.0.0
*/ */
@NonNull @NonNull
public Builder asyncDrawableLoader(@NonNull AsyncDrawableLoader asyncDrawableLoader) { public Builder asyncDrawableLoader(@NonNull AsyncDrawableLoader asyncDrawableLoader) {
@ -138,7 +138,7 @@ public class MarkwonConfiguration {
this.theme = theme; this.theme = theme;
this.spansFactory = spansFactory; this.spansFactory = spansFactory;
// @since 4.0.0-SNAPSHOT // @since 4.0.0
if (asyncDrawableLoader == null) { if (asyncDrawableLoader == null) {
asyncDrawableLoader = AsyncDrawableLoader.noOp(); asyncDrawableLoader = AsyncDrawableLoader.noOp();
} }

View File

@ -26,7 +26,7 @@ public interface MarkwonPlugin {
/** /**
* @see Registry#require(Class, Action) * @see Registry#require(Class, Action)
* @since 4.0.0-SNAPSHOT * @since 4.0.0
*/ */
interface Action<P extends MarkwonPlugin> { interface Action<P extends MarkwonPlugin> {
void apply(@NonNull P p); void apply(@NonNull P p);
@ -34,7 +34,7 @@ public interface MarkwonPlugin {
/** /**
* @see #configure(Registry) * @see #configure(Registry)
* @since 4.0.0-SNAPSHOT * @since 4.0.0
*/ */
interface Registry { interface Registry {
@ -49,7 +49,7 @@ public interface MarkwonPlugin {
/** /**
* This method will be called before any other during {@link Markwon} instance construction. * 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); void configure(@NonNull Registry registry);
@ -91,14 +91,6 @@ public interface MarkwonPlugin {
*/ */
void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder); 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. * Process input markdown and return new string to be used in parsing stage further.
* Can be described as <code>pre-processing</code> of markdown String. * Can be described as <code>pre-processing</code> of markdown String.

View File

@ -10,7 +10,7 @@ import java.util.Set;
import io.noties.markwon.core.CorePlugin; import io.noties.markwon.core.CorePlugin;
// @since 4.0.0-SNAPSHOT // @since 4.0.0
class RegistryImpl implements MarkwonPlugin.Registry { class RegistryImpl implements MarkwonPlugin.Registry {
private final List<MarkwonPlugin> origin; private final List<MarkwonPlugin> origin;

View File

@ -58,7 +58,7 @@ public class CorePlugin extends AbstractMarkwonPlugin {
/** /**
* @see #addOnTextAddedListener(OnTextAddedListener) * @see #addOnTextAddedListener(OnTextAddedListener)
* @since 4.0.0-SNAPSHOT * @since 4.0.0
*/ */
public interface OnTextAddedListener { public interface OnTextAddedListener {
@ -88,7 +88,7 @@ public class CorePlugin extends AbstractMarkwonPlugin {
return new CorePlugin(); return new CorePlugin();
} }
// @since 4.0.0-SNAPSHOT // @since 4.0.0
private final List<OnTextAddedListener> onTextAddedListeners = new ArrayList<>(0); private final List<OnTextAddedListener> onTextAddedListeners = new ArrayList<>(0);
protected CorePlugin() { 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. * Can be useful to post-process text added. For example for auto-linking capabilities.
* *
* @see OnTextAddedListener * @see OnTextAddedListener
* @since 4.0.0-SNAPSHOT * @since 4.0.0
*/ */
@SuppressWarnings("UnusedReturnValue") @SuppressWarnings("UnusedReturnValue")
@NonNull @NonNull
@ -171,7 +171,7 @@ public class CorePlugin extends AbstractMarkwonPlugin {
visitor.builder().append(literal); visitor.builder().append(literal);
// @since 4.0.0-SNAPSHOT // @since 4.0.0
if (!onTextAddedListeners.isEmpty()) { if (!onTextAddedListeners.isEmpty()) {
// calculate the start position // calculate the start position
final int length = visitor.length() - literal.length(); 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 // his method is moved from ImagesPlugin. Alternative implementations must set SpanFactory
// for Image node in order for this visitor to function // for Image node in order for this visitor to function
private static void image(MarkwonVisitor.Builder builder) { private static void image(MarkwonVisitor.Builder builder) {

View File

@ -8,7 +8,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Px; import androidx.annotation.Px;
/** /**
* @since 4.0.0-SNAPSHOT * @since 4.0.0
*/ */
public class LastLineSpacingSpan implements LineHeightSpan { public class LastLineSpacingSpan implements LineHeightSpan {

View File

@ -53,7 +53,7 @@ public class AsyncDrawable extends Drawable {
} }
/** /**
* @since 4.0.0-SNAPSHOT * @since 4.0.0
*/ */
@Nullable @Nullable
public ImageSize getImageSize() { public ImageSize getImageSize() {
@ -61,7 +61,7 @@ public class AsyncDrawable extends Drawable {
} }
/** /**
* @since 4.0.0-SNAPSHOT * @since 4.0.0
*/ */
@NonNull @NonNull
public ImageSizeResolver getImageSizeResolver() { public ImageSizeResolver getImageSizeResolver() {
@ -69,7 +69,7 @@ public class AsyncDrawable extends Drawable {
} }
/** /**
* @since 4.0.0-SNAPSHOT * @since 4.0.0
*/ */
public boolean hasKnownDimentions() { public boolean hasKnownDimentions() {
return canvasWidth > 0; return canvasWidth > 0;
@ -77,7 +77,7 @@ public class AsyncDrawable extends Drawable {
/** /**
* @see #hasKnownDimentions() * @see #hasKnownDimentions()
* @since 4.0.0-SNAPSHOT * @since 4.0.0
*/ */
public int getLastKnownCanvasWidth() { public int getLastKnownCanvasWidth() {
return canvasWidth; return canvasWidth;
@ -85,7 +85,7 @@ public class AsyncDrawable extends Drawable {
/** /**
* @see #hasKnownDimentions() * @see #hasKnownDimentions()
* @since 4.0.0-SNAPSHOT * @since 4.0.0
*/ */
public float getLastKnowTextSize() { public float getLastKnowTextSize() {
return textSize; return textSize;
@ -262,7 +262,7 @@ public class AsyncDrawable extends Drawable {
if (hasResult()) { if (hasResult()) {
out = result.getIntrinsicWidth(); out = result.getIntrinsicWidth();
} else { } 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; out = 1;
} }
return out; return out;
@ -274,7 +274,7 @@ public class AsyncDrawable extends Drawable {
if (hasResult()) { if (hasResult()) {
out = result.getIntrinsicHeight(); out = result.getIntrinsicHeight();
} else { } 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; out = 1;
} }
return out; return out;

View File

@ -16,12 +16,12 @@ public abstract class AsyncDrawableLoader {
} }
/** /**
* @since 3.1.0-SNAPSHOT * @since 4.0.0
*/ */
public abstract void load(@NonNull AsyncDrawable drawable); public abstract void load(@NonNull AsyncDrawable drawable);
/** /**
* @since 3.1.0-SNAPSHOT * @since 4.0.0
*/ */
public abstract void cancel(@NonNull AsyncDrawable drawable); public abstract void cancel(@NonNull AsyncDrawable drawable);

View File

@ -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, // hm... we need the same thing for unschedule then... we can check if last hash is !null,
// if it's not -> unschedule, else ignore // if it's not -> unschedule, else ignore
// @since 4.0.0-SNAPSHOT // @since 4.0.0
final Integer lastTextHashCode = final Integer lastTextHashCode =
(Integer) textView.getTag(R.id.markwon_drawables_scheduler_last_text_hashcode); (Integer) textView.getTag(R.id.markwon_drawables_scheduler_last_text_hashcode);
final int textHashCode = textView.getText().hashCode(); final int textHashCode = textView.getText().hashCode();
@ -69,7 +69,7 @@ public abstract class AsyncDrawableScheduler {
// must be called when text manually changed in TextView // must be called when text manually changed in TextView
public static void unschedule(@NonNull TextView view) { 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) { if (view.getTag(R.id.markwon_drawables_scheduler_last_text_hashcode) == null) {
return; return;
} }
@ -99,7 +99,7 @@ public abstract class AsyncDrawableScheduler {
} }
// we also could've tried the `nextSpanTransition`, but strangely it leads to worse performance // 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); return ((Spanned) cs).getSpans(0, length, AsyncDrawableSpan.class);
} }

View File

@ -12,7 +12,7 @@ import androidx.annotation.NonNull;
public abstract class ImageSizeResolver { public abstract class ImageSizeResolver {
/** /**
* @since 4.0.0-SNAPSHOT * @since 4.0.0
*/ */
@NonNull @NonNull
public abstract Rect resolveImageSize(@NonNull AsyncDrawable drawable); public abstract Rect resolveImageSize(@NonNull AsyncDrawable drawable);

View File

@ -31,7 +31,7 @@ public class ImageSizeResolverDefTest {
@Test @Test
public void correct_redirect() { 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 ImageSizeResolverDef def = mock(ImageSizeResolverDef.class, Mockito.CALLS_REAL_METHODS);
final AsyncDrawable drawable = mock(AsyncDrawable.class); final AsyncDrawable drawable = mock(AsyncDrawable.class);

View File

@ -36,7 +36,7 @@ import ru.noties.jlatexmath.JLatexMathDrawable;
public class JLatexMathPlugin extends AbstractMarkwonPlugin { public class JLatexMathPlugin extends AbstractMarkwonPlugin {
/** /**
* @since 4.0.0-SNAPSHOT * @since 4.0.0
*/ */
public interface BackgroundProvider { public interface BackgroundProvider {
@NonNull @NonNull
@ -73,7 +73,7 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin {
private final float textSize; private final float textSize;
// @since 4.0.0-SNAPSHOT // @since 4.0.0
private final BackgroundProvider backgroundProvider; private final BackgroundProvider backgroundProvider;
@JLatexMathDrawable.Align @JLatexMathDrawable.Align
@ -81,13 +81,13 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin {
private final boolean fitCanvas; private final boolean fitCanvas;
// @since 4.0.0-SNAPSHOT // @since 4.0.0
private final int paddingHorizontal; private final int paddingHorizontal;
// @since 4.0.0-SNAPSHOT // @since 4.0.0
private final int paddingVertical; private final int paddingVertical;
// @since 4.0.0-SNAPSHOT // @since 4.0.0
private final ExecutorService executorService; private final ExecutorService executorService;
Config(@NonNull Builder builder) { Config(@NonNull Builder builder) {
@ -98,7 +98,7 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin {
this.paddingHorizontal = builder.paddingHorizontal; this.paddingHorizontal = builder.paddingHorizontal;
this.paddingVertical = builder.paddingVertical; this.paddingVertical = builder.paddingVertical;
// @since 4.0.0-SNAPSHOT // @since 4.0.0
ExecutorService executorService = builder.executorService; ExecutorService executorService = builder.executorService;
if (executorService == null) { if (executorService == null) {
executorService = Executors.newCachedThreadPool(); executorService = Executors.newCachedThreadPool();
@ -164,7 +164,7 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin {
private final float textSize; private final float textSize;
// @since 4.0.0-SNAPSHOT // @since 4.0.0
private BackgroundProvider backgroundProvider; private BackgroundProvider backgroundProvider;
@JLatexMathDrawable.Align @JLatexMathDrawable.Align
@ -172,13 +172,13 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin {
private boolean fitCanvas = true; private boolean fitCanvas = true;
// @since 4.0.0-SNAPSHOT // @since 4.0.0
private int paddingHorizontal; private int paddingHorizontal;
// @since 4.0.0-SNAPSHOT // @since 4.0.0
private int paddingVertical; private int paddingVertical;
// @since 4.0.0-SNAPSHOT // @since 4.0.0
private ExecutorService executorService; private ExecutorService executorService;
Builder(float textSize) { Builder(float textSize) {
@ -211,7 +211,7 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin {
} }
/** /**
* @since 4.0.0-SNAPSHOT * @since 4.0.0
*/ */
@NonNull @NonNull
public Builder builder(@Px int paddingHorizontal, @Px int paddingVertical) { 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 @NonNull
public Builder executorService(@NonNull ExecutorService executorService) { 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 static class JLatextAsyncDrawableLoader extends AsyncDrawableLoader {
private final Config config; 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 // 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 static class JLatexImageSizeResolver extends ImageSizeResolver {
private final boolean fitCanvas; private final boolean fitCanvas;

View File

@ -29,7 +29,7 @@ public class HtmlPlugin extends AbstractMarkwonPlugin {
/** /**
* @see #create(HtmlConfigure) * @see #create(HtmlConfigure)
* @since 4.0.0-SNAPSHOT * @since 4.0.0
*/ */
public interface HtmlConfigure { public interface HtmlConfigure {
void configureHtml(@NonNull HtmlPlugin plugin); void configureHtml(@NonNull HtmlPlugin plugin);
@ -41,7 +41,7 @@ public class HtmlPlugin extends AbstractMarkwonPlugin {
} }
/** /**
* @since 4.0.0-SNAPSHOT * @since 4.0.0
*/ */
@NonNull @NonNull
public static HtmlPlugin create(@NonNull HtmlConfigure configure) { 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 * @param allowNonClosedTags whether or not non-closed tags should be closed
* at the document end. By default `false` * at the document end. By default `false`
* @since 4.0.0-SNAPSHOT * @since 4.0.0
*/ */
@NonNull @NonNull
public HtmlPlugin allowNonClosedTags(boolean allowNonClosedTags) { public HtmlPlugin allowNonClosedTags(boolean allowNonClosedTags) {
@ -74,7 +74,7 @@ public class HtmlPlugin extends AbstractMarkwonPlugin {
} }
/** /**
* @since 4.0.0-SNAPSHOT * @since 4.0.0
*/ */
@NonNull @NonNull
public HtmlPlugin addHandler(@NonNull TagHandler tagHandler) { 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 @Nullable
public TagHandler getHandler(@NonNull String tagName) { public TagHandler getHandler(@NonNull String tagName) {
@ -96,7 +96,7 @@ public class HtmlPlugin extends AbstractMarkwonPlugin {
* {@link TagHandlerNoOp} to no-op certain default tags. * {@link TagHandlerNoOp} to no-op certain default tags.
* *
* @see TagHandlerNoOp * @see TagHandlerNoOp
* @since 4.0.0-SNAPSHOT * @since 4.0.0
*/ */
@NonNull @NonNull
public HtmlPlugin excludeDefaults(boolean excludeDefaults) { public HtmlPlugin excludeDefaults(boolean excludeDefaults) {
@ -107,7 +107,7 @@ public class HtmlPlugin extends AbstractMarkwonPlugin {
@Override @Override
public void configureConfiguration(@NonNull MarkwonConfiguration.Builder configurationBuilder) { 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; final MarkwonHtmlRendererImpl.Builder builder = this.builder;

View File

@ -15,7 +15,7 @@ public abstract class TagHandler {
); );
/** /**
* @since 4.0.0-SNAPSHOT * @since 4.0.0
*/ */
@NonNull @NonNull
public abstract Collection<String> supportedTags(); public abstract Collection<String> supportedTags();

View File

@ -9,7 +9,7 @@ import java.util.Collections;
import io.noties.markwon.MarkwonVisitor; import io.noties.markwon.MarkwonVisitor;
/** /**
* @since 4.0.0-SNAPSHOT * @since 4.0.0
*/ */
public class TagHandlerNoOp extends TagHandler { public class TagHandlerNoOp extends TagHandler {

View File

@ -30,7 +30,7 @@ import io.noties.markwon.image.DrawableUtils;
import io.noties.markwon.image.ImageSpanFactory; import io.noties.markwon.image.ImageSpanFactory;
/** /**
* @since 4.0.0-SNAPSHOT * @since 4.0.0
*/ */
public class GlideImagesPlugin extends AbstractMarkwonPlugin { public class GlideImagesPlugin extends AbstractMarkwonPlugin {

View File

@ -30,7 +30,7 @@ import io.noties.markwon.image.DrawableUtils;
import io.noties.markwon.image.ImageSpanFactory; import io.noties.markwon.image.ImageSpanFactory;
/** /**
* @since 4.0.0-SNAPSHOT * @since 4.0.0
*/ */
public class PicassoImagesPlugin extends AbstractMarkwonPlugin { public class PicassoImagesPlugin extends AbstractMarkwonPlugin {

View File

@ -28,7 +28,7 @@ class AsyncDrawableLoaderBuilder {
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 // 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) // we should not use file-scheme as it's a bit complicated to assume file usage (lack of permissions)
addSchemeHandler(DataUriSchemeHandler.create()); addSchemeHandler(DataUriSchemeHandler.create());

View File

@ -28,7 +28,7 @@ class AsyncDrawableLoaderImpl extends AsyncDrawableLoader {
private final Handler handler; 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 // for the same destination
private final Map<AsyncDrawable, Future<?>> requests = new HashMap<>(2); private final Map<AsyncDrawable, Future<?>> requests = new HashMap<>(2);
@ -36,7 +36,7 @@ class AsyncDrawableLoaderImpl extends AsyncDrawableLoader {
this(builder, new Handler(Looper.getMainLooper())); this(builder, new Handler(Looper.getMainLooper()));
} }
// @since 4.0.0-SNAPSHOT // @since 4.0.0
@VisibleForTesting @VisibleForTesting
AsyncDrawableLoaderImpl(@NonNull AsyncDrawableLoaderBuilder builder, @NonNull Handler handler) { AsyncDrawableLoaderImpl(@NonNull AsyncDrawableLoaderBuilder builder, @NonNull Handler handler) {
this.executorService = builder.executorService; this.executorService = builder.executorService;
@ -144,7 +144,7 @@ class AsyncDrawableLoaderImpl extends AsyncDrawableLoader {
final Drawable out = drawable; 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) { if (out != null) {
final Rect bounds = out.getBounds(); final Rect bounds = out.getBounds();
//noinspection ConstantConditions //noinspection ConstantConditions

View File

@ -17,7 +17,7 @@ public abstract class ImageItem {
* *
* @see #withDecodingNeeded(String, InputStream) * @see #withDecodingNeeded(String, InputStream)
* @see WithResult * @see WithResult
* @since 4.0.0-SNAPSHOT * @since 4.0.0
*/ */
@NonNull @NonNull
public static ImageItem withResult(@NonNull Drawable drawable) { public static ImageItem withResult(@NonNull Drawable drawable) {
@ -29,7 +29,7 @@ public abstract class ImageItem {
* *
* @see #withResult(Drawable) * @see #withResult(Drawable)
* @see WithDecodingNeeded * @see WithDecodingNeeded
* @since 4.0.0-SNAPSHOT * @since 4.0.0
*/ */
@NonNull @NonNull
public static ImageItem withDecodingNeeded( 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(); public abstract boolean hasResult();
/** /**
* @since 4.0.0-SNAPSHOT * @since 4.0.0
*/ */
public abstract boolean hasDecodingNeeded(); public abstract boolean hasDecodingNeeded();
/** /**
* @see #hasResult() * @see #hasResult()
* @since 4.0.0-SNAPSHOT * @since 4.0.0
*/ */
@NonNull @NonNull
public abstract WithResult getAsWithResult(); public abstract WithResult getAsWithResult();
/** /**
* @see #hasDecodingNeeded() * @see #hasDecodingNeeded()
* @since 4.0.0-SNAPSHOT * @since 4.0.0
*/ */
@NonNull @NonNull
public abstract WithDecodingNeeded getAsWithDecodingNeeded(); public abstract WithDecodingNeeded getAsWithDecodingNeeded();
/** /**
* @since 4.0.0-SNAPSHOT * @since 4.0.0
*/ */
public static class WithResult extends ImageItem { 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 { public static class WithDecodingNeeded extends ImageItem {

View File

@ -27,14 +27,14 @@ import io.noties.markwon.image.svg.SvgMediaDecoder;
public class ImagesPlugin extends AbstractMarkwonPlugin { public class ImagesPlugin extends AbstractMarkwonPlugin {
/** /**
* @since 4.0.0-SNAPSHOT * @since 4.0.0
*/ */
public interface ImagesConfigure { public interface ImagesConfigure {
void configureImages(@NonNull ImagesPlugin plugin); void configureImages(@NonNull ImagesPlugin plugin);
} }
/** /**
* @since 4.0.0-SNAPSHOT * @since 4.0.0
*/ */
public interface PlaceholderProvider { public interface PlaceholderProvider {
@Nullable @Nullable
@ -42,7 +42,7 @@ public class ImagesPlugin extends AbstractMarkwonPlugin {
} }
/** /**
* @since 4.0.0-SNAPSHOT * @since 4.0.0
*/ */
public interface ErrorHandler { public interface ErrorHandler {
@ -74,12 +74,12 @@ public class ImagesPlugin extends AbstractMarkwonPlugin {
private final AsyncDrawableLoaderBuilder builder; private final AsyncDrawableLoaderBuilder builder;
// @since 4.0.0-SNAPSHOT // @since 4.0.0
ImagesPlugin() { ImagesPlugin() {
this(new AsyncDrawableLoaderBuilder()); this(new AsyncDrawableLoaderBuilder());
} }
// @since 4.0.0-SNAPSHOT // @since 4.0.0
@VisibleForTesting @VisibleForTesting
ImagesPlugin(@NonNull AsyncDrawableLoaderBuilder builder) { ImagesPlugin(@NonNull AsyncDrawableLoaderBuilder builder) {
this.builder = builder; this.builder = builder;
@ -88,7 +88,7 @@ public class ImagesPlugin extends AbstractMarkwonPlugin {
/** /**
* Optional (by default new cached thread executor will be used) * Optional (by default new cached thread executor will be used)
* *
* @since 4.0.0-SNAPSHOT * @since 4.0.0
*/ */
@NonNull @NonNull
public ImagesPlugin executorService(@NonNull ExecutorService executorService) { public ImagesPlugin executorService(@NonNull ExecutorService executorService) {
@ -102,7 +102,7 @@ public class ImagesPlugin extends AbstractMarkwonPlugin {
* @see FileSchemeHandler * @see FileSchemeHandler
* @see NetworkSchemeHandler * @see NetworkSchemeHandler
* @see OkHttpNetworkSchemeHandler * @see OkHttpNetworkSchemeHandler
* @since 4.0.0-SNAPSHOT * @since 4.0.0
*/ */
@NonNull @NonNull
public ImagesPlugin addSchemeHandler(@NonNull SchemeHandler schemeHandler) { public ImagesPlugin addSchemeHandler(@NonNull SchemeHandler schemeHandler) {
@ -114,7 +114,7 @@ public class ImagesPlugin extends AbstractMarkwonPlugin {
* @see DefaultMediaDecoder * @see DefaultMediaDecoder
* @see SvgMediaDecoder * @see SvgMediaDecoder
* @see GifMediaDecoder * @see GifMediaDecoder
* @since 4.0.0-SNAPSHOT * @since 4.0.0
*/ */
@NonNull @NonNull
public ImagesPlugin addMediaDecoder(@NonNull MediaDecoder mediaDecoder) { 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. * if you need to disable default-image-media-decoder specify here own no-op implementation or null.
* *
* @see DefaultMediaDecoder * @see DefaultMediaDecoder
* @since 4.0.0-SNAPSHOT * @since 4.0.0
*/ */
@NonNull @NonNull
public ImagesPlugin defaultMediaDecoder(@Nullable MediaDecoder mediaDecoder) { 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 @NonNull
public ImagesPlugin removeSchemeHandler(@NonNull String scheme) { 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 @NonNull
public ImagesPlugin removeMediaDecoder(@NonNull String contentType) { 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 @NonNull
public ImagesPlugin placeholderProvider(@NonNull PlaceholderProvider placeholderProvider) { public ImagesPlugin placeholderProvider(@NonNull PlaceholderProvider placeholderProvider) {
@ -164,7 +164,7 @@ public class ImagesPlugin extends AbstractMarkwonPlugin {
/** /**
* @see ErrorHandler * @see ErrorHandler
* @since 4.0.0-SNAPSHOT * @since 4.0.0
*/ */
@NonNull @NonNull
public ImagesPlugin errorHandler(@NonNull ErrorHandler errorHandler) { public ImagesPlugin errorHandler(@NonNull ErrorHandler errorHandler) {

View File

@ -27,7 +27,7 @@ public abstract class MediaDecoder {
); );
/** /**
* @since 4.0.0-SNAPSHOT * @since 4.0.0
*/ */
@NonNull @NonNull
public abstract Collection<String> supportedTypes(); public abstract Collection<String> supportedTypes();

View File

@ -24,7 +24,7 @@ public abstract class SchemeHandler {
public abstract ImageItem handle(@NonNull String raw, @NonNull Uri uri); public abstract ImageItem handle(@NonNull String raw, @NonNull Uri uri);
/** /**
* @since 4.0.0-SNAPSHOT * @since 4.0.0
*/ */
@NonNull @NonNull
public abstract Collection<String> supportedSchemes(); public abstract Collection<String> supportedSchemes();

View File

@ -40,7 +40,7 @@ public class FileSchemeHandler extends SchemeHandler {
/** /**
* @see #createWithAssets(AssetManager) * @see #createWithAssets(AssetManager)
* @see UrlProcessorAndroidAssets * @see UrlProcessorAndroidAssets
* @since 4.0.0-SNAPSHOT * @since 4.0.0
*/ */
@NonNull @NonNull
public static FileSchemeHandler createWithAssets(@NonNull Context context) { public static FileSchemeHandler createWithAssets(@NonNull Context context) {

View File

@ -26,7 +26,7 @@ public class GifMediaDecoder extends MediaDecoder {
/** /**
* Creates a {@link GifMediaDecoder} with {@code autoPlayGif = true} * Creates a {@link GifMediaDecoder} with {@code autoPlayGif = true}
* *
* @since 4.0.0-SNAPSHOT * @since 4.0.0
*/ */
@NonNull @NonNull
public static GifMediaDecoder create() { public static GifMediaDecoder create() {
@ -43,7 +43,7 @@ public class GifMediaDecoder extends MediaDecoder {
protected GifMediaDecoder(boolean autoPlayGif) { protected GifMediaDecoder(boolean autoPlayGif) {
this.autoPlayGif = autoPlayGif; this.autoPlayGif = autoPlayGif;
// @since 4.0.0-SNAPSHOT // @since 4.0.0
validate(); validate();
} }

View File

@ -1,7 +1,7 @@
package io.noties.markwon.image.gif; package io.noties.markwon.image.gif;
/** /**
* @since 4.0.0-SNAPSHOT * @since 4.0.0
*/ */
public abstract class GifSupport { public abstract class GifSupport {

View File

@ -16,7 +16,7 @@ import okhttp3.Response;
import okhttp3.ResponseBody; import okhttp3.ResponseBody;
/** /**
* @since 4.0.0-SNAPSHOT * @since 4.0.0
*/ */
public class OkHttpNetworkSchemeHandler extends SchemeHandler { public class OkHttpNetworkSchemeHandler extends SchemeHandler {
@ -35,7 +35,7 @@ public class OkHttpNetworkSchemeHandler extends SchemeHandler {
} }
/** /**
* @since 4.0.0-SNAPSHOT * @since 4.0.0
*/ */
@NonNull @NonNull
public static OkHttpNetworkSchemeHandler create(@NonNull Call.Factory factory) { 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"; 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; private final Call.Factory factory;
@SuppressWarnings("WeakerAccess") @SuppressWarnings("WeakerAccess")

View File

@ -27,7 +27,7 @@ public class SvgMediaDecoder extends MediaDecoder {
/** /**
* @see #create(Resources) * @see #create(Resources)
* @since 4.0.0-SNAPSHOT * @since 4.0.0
*/ */
@NonNull @NonNull
public static SvgMediaDecoder create() { public static SvgMediaDecoder create() {
@ -45,7 +45,7 @@ public class SvgMediaDecoder extends MediaDecoder {
SvgMediaDecoder(Resources resources) { SvgMediaDecoder(Resources resources) {
this.resources = resources; this.resources = resources;
// @since 4.0.0-SNAPSHOT // @since 4.0.0
validate(); validate();
} }

View File

@ -1,7 +1,7 @@
package io.noties.markwon.image.svg; package io.noties.markwon.image.svg;
/** /**
* @since 4.0.0-SNAPSHOT * @since 4.0.0
*/ */
public abstract class SvgSupport { public abstract class SvgSupport {

View File

@ -1,9 +1,2 @@
# Linkify # 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!

View File

@ -9,7 +9,7 @@ import java.util.List;
import io.noties.markwon.SpanFactory; import io.noties.markwon.SpanFactory;
// @since 4.0.0-SNAPSHOT // @since 4.0.0
class SimpleExtBuilder { class SimpleExtBuilder {
private final List<DelimiterProcessor> extensions = new ArrayList<>(2); private final List<DelimiterProcessor> extensions = new ArrayList<>(2);

View File

@ -9,7 +9,7 @@ import org.commonmark.parser.delimiter.DelimiterRun;
import io.noties.markwon.SpanFactory; import io.noties.markwon.SpanFactory;
// @since 4.0.0-SNAPSHOT // @since 4.0.0
class SimpleExtDelimiterProcessor implements DelimiterProcessor { class SimpleExtDelimiterProcessor implements DelimiterProcessor {
private final char open; private final char open;

View File

@ -7,7 +7,7 @@ import org.commonmark.node.Visitor;
import io.noties.markwon.SpanFactory; import io.noties.markwon.SpanFactory;
// @since 4.0.0-SNAPSHOT // @since 4.0.0
class SimpleExtNode extends CustomNode { class SimpleExtNode extends CustomNode {
private final SpanFactory spanFactory; private final SpanFactory spanFactory;

View File

@ -11,7 +11,7 @@ import io.noties.markwon.SpanFactory;
import io.noties.markwon.SpannableBuilder; import io.noties.markwon.SpannableBuilder;
/** /**
* @since 4.0.0-SNAPSHOT * @since 4.0.0
*/ */
public class SimpleExtPlugin extends AbstractMarkwonPlugin { public class SimpleExtPlugin extends AbstractMarkwonPlugin {

View File

@ -26,6 +26,7 @@
<activity android:name="io.noties.markwon.sample.theme.ThemeActivity" /> <activity android:name="io.noties.markwon.sample.theme.ThemeActivity" />
<activity android:name=".html.HtmlActivity" /> <activity android:name=".html.HtmlActivity" />
<activity android:name=".simpleext.SimpleExtActivity" /> <activity android:name=".simpleext.SimpleExtActivity" />
<activity android:name=".customextension2.CustomExtensionActivity2" />
</application> </application>

View File

@ -21,6 +21,7 @@ import io.noties.markwon.Markwon;
import io.noties.markwon.sample.basicplugins.BasicPluginsActivity; import io.noties.markwon.sample.basicplugins.BasicPluginsActivity;
import io.noties.markwon.sample.core.CoreActivity; import io.noties.markwon.sample.core.CoreActivity;
import io.noties.markwon.sample.customextension.CustomExtensionActivity; 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.html.HtmlActivity;
import io.noties.markwon.sample.latex.LatexActivity; import io.noties.markwon.sample.latex.LatexActivity;
import io.noties.markwon.sample.recycler.RecyclerActivity; import io.noties.markwon.sample.recycler.RecyclerActivity;
@ -107,6 +108,10 @@ public class MainActivity extends Activity {
activity = SimpleExtActivity.class; activity = SimpleExtActivity.class;
break; break;
case CUSTOM_EXTENSION_2:
activity = CustomExtensionActivity2.class;
break;
default: default:
throw new IllegalStateException("No Activity is associated with sample-item: " + item); throw new IllegalStateException("No Activity is associated with sample-item: " + item);
} }

View File

@ -17,7 +17,9 @@ public enum Sample {
HTML(R.string.sample_html), 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; private final int textResId;

View File

@ -22,13 +22,6 @@ public class IconPlugin extends AbstractMarkwonPlugin {
this.iconSpanProvider = iconSpanProvider; this.iconSpanProvider = iconSpanProvider;
} }
// @NonNull
// @Override
// public Priority priority() {
// // define images dependency
// return Priority.after(ImagesPlugin.class);
// }
@Override @Override
public void configureParser(@NonNull Parser.Builder builder) { public void configureParser(@NonNull Parser.Builder builder) {
builder.customDelimiterProcessor(IconProcessor.create()); builder.customDelimiterProcessor(IconProcessor.create());

View File

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

View File

@ -20,4 +20,7 @@
<string name="sample_simple_ext"># \# SimpleExt\n\nShows how to use SimpleExtPlugin module <string name="sample_simple_ext"># \# SimpleExt\n\nShows how to use SimpleExtPlugin module
to create own delimited parser extensions</string> to create own delimited parser extensions</string>
<string name="sample_custom_extension_2"># \# Custom extension 2\n\nAutomatically
convert `#1` and `@user` to Github links</string>
</resources> </resources>