Preparing 4.0.0 release
This commit is contained in:
		
							parent
							
								
									d65a1809ca
								
							
						
					
					
						commit
						386254f962
					
				
							
								
								
									
										47
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										47
									
								
								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  | ||||
| <br>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 | ||||
| <br>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 | ||||
| <br>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 | ||||
| <br>Thanks to @edenman | ||||
| * Introduce `MediaDecoder` abstraction to `image-loader` module | ||||
| * 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 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 | ||||
| <br>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 | ||||
| <br>Thanks to @dlew | ||||
| 
 | ||||
| ## v1.0.3 | ||||
| * Fixed ordered lists (when number width is greater than block margin) | ||||
|  | ||||
| @ -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: | ||||
|  | ||||
							
								
								
									
										16
									
								
								_CHANGES.md
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								_CHANGES.md
									
									
									
									
									
								
							| @ -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) | ||||
| @ -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 { | ||||
|  | ||||
| @ -1,3 +1,27 @@ | ||||
| # 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(); | ||||
| ``` | ||||
| @ -1,3 +1,32 @@ | ||||
| # 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(); | ||||
| ``` | ||||
| @ -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 <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 | ||||
| 
 | ||||
| ## 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 | ||||
|  | ||||
| @ -1,3 +1,31 @@ | ||||
| # 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(); | ||||
| ``` | ||||
| @ -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 | ||||
| @ -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 | ||||
| ::: | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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) { | ||||
|  | ||||
| @ -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(); | ||||
|             } | ||||
|  | ||||
| @ -26,7 +26,7 @@ public interface MarkwonPlugin { | ||||
| 
 | ||||
|     /** | ||||
|      * @see Registry#require(Class, Action) | ||||
|      * @since 4.0.0-SNAPSHOT | ||||
|      * @since 4.0.0 | ||||
|      */ | ||||
|     interface Action<P extends MarkwonPlugin> { | ||||
|         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 <code>pre-processing</code> of markdown String. | ||||
|  | ||||
| @ -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<MarkwonPlugin> origin; | ||||
|  | ||||
| @ -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<OnTextAddedListener> 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) { | ||||
|  | ||||
| @ -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 { | ||||
| 
 | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
| @ -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); | ||||
| 
 | ||||
|  | ||||
| @ -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); | ||||
|     } | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
| @ -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; | ||||
| 
 | ||||
|  | ||||
| @ -15,7 +15,7 @@ public abstract class TagHandler { | ||||
|     ); | ||||
| 
 | ||||
|     /** | ||||
|      * @since 4.0.0-SNAPSHOT | ||||
|      * @since 4.0.0 | ||||
|      */ | ||||
|     @NonNull | ||||
|     public abstract Collection<String> supportedTags(); | ||||
|  | ||||
| @ -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 { | ||||
| 
 | ||||
|  | ||||
| @ -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 { | ||||
| 
 | ||||
|  | ||||
| @ -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 { | ||||
| 
 | ||||
|  | ||||
| @ -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()); | ||||
|  | ||||
| @ -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<AsyncDrawable, Future<?>> 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 | ||||
|  | ||||
| @ -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 { | ||||
| 
 | ||||
|  | ||||
| @ -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) { | ||||
|  | ||||
| @ -27,7 +27,7 @@ public abstract class MediaDecoder { | ||||
|     ); | ||||
| 
 | ||||
|     /** | ||||
|      * @since 4.0.0-SNAPSHOT | ||||
|      * @since 4.0.0 | ||||
|      */ | ||||
|     @NonNull | ||||
|     public abstract Collection<String> supportedTypes(); | ||||
|  | ||||
| @ -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<String> supportedSchemes(); | ||||
|  | ||||
| @ -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) { | ||||
|  | ||||
| @ -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(); | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| package io.noties.markwon.image.gif; | ||||
| 
 | ||||
| /** | ||||
|  * @since 4.0.0-SNAPSHOT | ||||
|  * @since 4.0.0 | ||||
|  */ | ||||
| public abstract class GifSupport { | ||||
| 
 | ||||
|  | ||||
| @ -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") | ||||
|  | ||||
| @ -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(); | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| package io.noties.markwon.image.svg; | ||||
| 
 | ||||
| /** | ||||
|  * @since 4.0.0-SNAPSHOT | ||||
|  * @since 4.0.0 | ||||
|  */ | ||||
| public abstract class SvgSupport { | ||||
| 
 | ||||
|  | ||||
| @ -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! | ||||
| @ -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<DelimiterProcessor> extensions = new ArrayList<>(2); | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
| @ -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 { | ||||
| 
 | ||||
|  | ||||
| @ -26,6 +26,7 @@ | ||||
|         <activity android:name="io.noties.markwon.sample.theme.ThemeActivity" /> | ||||
|         <activity android:name=".html.HtmlActivity" /> | ||||
|         <activity android:name=".simpleext.SimpleExtActivity" /> | ||||
|         <activity android:name=".customextension2.CustomExtensionActivity2" /> | ||||
| 
 | ||||
|     </application> | ||||
| 
 | ||||
|  | ||||
| @ -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); | ||||
|         } | ||||
|  | ||||
| @ -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; | ||||
| 
 | ||||
|  | ||||
| @ -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()); | ||||
|  | ||||
| @ -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 | ||||
|             ); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -20,4 +20,7 @@ | ||||
|     <string name="sample_simple_ext"># \# SimpleExt\n\nShows how to use SimpleExtPlugin module | ||||
|         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> | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Dimitry Ivanov
						Dimitry Ivanov