Add markwon-ext-latex module extension
This commit is contained in:
		
							parent
							
								
									6a82b75aba
								
							
						
					
					
						commit
						577c3fc782
					
				| @ -61,6 +61,7 @@ ext { | ||||
|             'commonmark-table'        : "com.atlassian.commonmark:commonmark-ext-gfm-tables:$commonMarkVersion", | ||||
|             'android-svg'             : 'com.caverock:androidsvg:1.2.1', | ||||
|             'android-gif'             : 'pl.droidsonroids.gif:android-gif-drawable:1.2.14', | ||||
|             'jlatexmath-android'      : 'ru.noties:jlatexmath-android:0.1.0', | ||||
|             'okhttp'                  : 'com.squareup.okhttp3:okhttp:3.9.0', | ||||
|             'prism4j'                 : 'ru.noties:prism4j:1.1.0', | ||||
|             'debug'                   : 'ru.noties:debug:3.0.0@jar', | ||||
|  | ||||
							
								
								
									
										22
									
								
								markwon-ext-latex/build.gradle
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								markwon-ext-latex/build.gradle
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | ||||
| apply plugin: 'com.android.library' | ||||
| 
 | ||||
| android { | ||||
| 
 | ||||
|     compileSdkVersion config['compile-sdk'] | ||||
|     buildToolsVersion config['build-tools'] | ||||
| 
 | ||||
|     defaultConfig { | ||||
|         minSdkVersion config['min-sdk'] | ||||
|         targetSdkVersion config['target-sdk'] | ||||
|         versionCode 1 | ||||
|         versionName version | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| dependencies { | ||||
| 
 | ||||
|     api project(':markwon') | ||||
|     api deps['jlatexmath-android'] | ||||
| } | ||||
| 
 | ||||
| registerArtifact(this) | ||||
							
								
								
									
										1
									
								
								markwon-ext-latex/src/main/AndroidManifest.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								markwon-ext-latex/src/main/AndroidManifest.xml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | ||||
| <manifest package="ru.noties.markwon.ext.latex" /> | ||||
| @ -1,4 +1,4 @@ | ||||
| package ru.noties.markwon.sample.jlatexmath; | ||||
| package ru.noties.markwon.ext.latex; | ||||
| 
 | ||||
| import org.commonmark.node.CustomBlock; | ||||
| 
 | ||||
| @ -1,4 +1,4 @@ | ||||
| package ru.noties.markwon.sample.jlatexmath; | ||||
| package ru.noties.markwon.ext.latex; | ||||
| 
 | ||||
| import org.commonmark.node.Block; | ||||
| import org.commonmark.parser.block.AbstractBlockParser; | ||||
| @ -0,0 +1,143 @@ | ||||
| package ru.noties.markwon.ext.latex; | ||||
| 
 | ||||
| import android.graphics.drawable.Drawable; | ||||
| import android.net.Uri; | ||||
| import android.support.annotation.NonNull; | ||||
| import android.support.annotation.Nullable; | ||||
| 
 | ||||
| import org.commonmark.parser.Parser; | ||||
| 
 | ||||
| import java.io.ByteArrayInputStream; | ||||
| import java.io.InputStream; | ||||
| import java.io.UnsupportedEncodingException; | ||||
| import java.util.Scanner; | ||||
| 
 | ||||
| import ru.noties.jlatexmath.JLatexMathDrawable; | ||||
| import ru.noties.markwon.AbstractMarkwonPlugin; | ||||
| import ru.noties.markwon.MarkwonConfiguration; | ||||
| import ru.noties.markwon.MarkwonVisitor; | ||||
| import ru.noties.markwon.image.AsyncDrawableLoader; | ||||
| import ru.noties.markwon.image.ImageItem; | ||||
| import ru.noties.markwon.image.ImageSize; | ||||
| import ru.noties.markwon.image.MediaDecoder; | ||||
| import ru.noties.markwon.image.SchemeHandler; | ||||
| 
 | ||||
| public class JLatexMathPlugin extends AbstractMarkwonPlugin { | ||||
| 
 | ||||
|     @NonNull | ||||
|     public static JLatexMathPlugin create(@NonNull Config config) { | ||||
|         return new JLatexMathPlugin(config); | ||||
|     } | ||||
| 
 | ||||
|     public static class Config { | ||||
| 
 | ||||
|         protected final float textSize; | ||||
| 
 | ||||
|         protected Drawable background; | ||||
| 
 | ||||
|         @JLatexMathDrawable.Align | ||||
|         protected int align = JLatexMathDrawable.ALIGN_CENTER; | ||||
| 
 | ||||
|         protected boolean fitCanvas = true; | ||||
| 
 | ||||
|         protected int padding; | ||||
| 
 | ||||
|         public Config(float textSize) { | ||||
|             this.textSize = textSize; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     public static String makeDestination(@NonNull String latex) { | ||||
|         return SCHEME + "://" + latex; | ||||
|     } | ||||
| 
 | ||||
|     private static final String SCHEME = "jlatexmath"; | ||||
|     private static final String CONTENT_TYPE = "text/jlatexmath"; | ||||
| 
 | ||||
|     private final Config config; | ||||
| 
 | ||||
|     JLatexMathPlugin(@NonNull Config config) { | ||||
|         this.config = config; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void configureParser(@NonNull Parser.Builder builder) { | ||||
|         builder.customBlockParserFactory(new JLatexMathBlockParser.Factory()); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) { | ||||
|         builder.on(JLatexMathBlock.class, new MarkwonVisitor.NodeVisitor<JLatexMathBlock>() { | ||||
|             @Override | ||||
|             public void visit(@NonNull MarkwonVisitor visitor, @NonNull JLatexMathBlock jLatexMathBlock) { | ||||
| 
 | ||||
|                 final String latex = jLatexMathBlock.latex(); | ||||
| 
 | ||||
|                 final int length = visitor.length(); | ||||
|                 visitor.builder().append(latex); | ||||
| 
 | ||||
|                 final MarkwonConfiguration configuration = visitor.configuration(); | ||||
| 
 | ||||
|                 visitor.setSpans( | ||||
|                         length, | ||||
|                         configuration.factory().image( | ||||
|                                 visitor.theme(), | ||||
|                                 makeDestination(latex), | ||||
|                                 configuration.asyncDrawableLoader(), | ||||
|                                 configuration.imageSizeResolver(), | ||||
|                                 new ImageSize(new ImageSize.Dimension(100, "%"), null), | ||||
|                                 false | ||||
|                         ) | ||||
|                 ); | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void configureImages(@NonNull AsyncDrawableLoader.Builder builder) { | ||||
|         builder | ||||
|                 .addSchemeHandler(SCHEME, new SchemeHandler() { | ||||
|                     @Nullable | ||||
|                     @Override | ||||
|                     public ImageItem handle(@NonNull String raw, @NonNull Uri uri) { | ||||
| 
 | ||||
|                         ImageItem item = null; | ||||
| 
 | ||||
|                         try { | ||||
|                             final byte[] bytes = raw.substring(SCHEME.length()).getBytes("UTF-8"); | ||||
|                             item = new ImageItem( | ||||
|                                     CONTENT_TYPE, | ||||
|                                     new ByteArrayInputStream(bytes)); | ||||
|                         } catch (UnsupportedEncodingException e) { | ||||
|                             e.printStackTrace(); | ||||
|                         } | ||||
| 
 | ||||
|                         return item; | ||||
|                     } | ||||
|                 }) | ||||
|                 .addMediaDecoder(CONTENT_TYPE, new MediaDecoder() { | ||||
|                     @Nullable | ||||
|                     @Override | ||||
|                     public Drawable decode(@NonNull InputStream inputStream) { | ||||
| 
 | ||||
|                         final Scanner scanner = new Scanner(inputStream, "UTF-8").useDelimiter("\\A"); | ||||
|                         final String latex = scanner.hasNext() | ||||
|                                 ? scanner.next() | ||||
|                                 : null; | ||||
| 
 | ||||
|                         if (latex == null) { | ||||
|                             return null; | ||||
|                         } | ||||
| 
 | ||||
|                         return JLatexMathDrawable.builder(latex) | ||||
|                                 .textSize(config.textSize) | ||||
|                                 .background(config.background) | ||||
|                                 .align(config.align) | ||||
|                                 .fitCanvas(config.fitCanvas) | ||||
|                                 .padding(config.padding) | ||||
|                                 .build(); | ||||
|                     } | ||||
|                 }); | ||||
|     } | ||||
| } | ||||
| @ -79,12 +79,6 @@ public class CorePlugin extends AbstractMarkwonPlugin { | ||||
|     @Override | ||||
|     public void beforeSetText(@NonNull TextView textView, @NonNull CharSequence markdown) { | ||||
|         OrderedListItemSpan.measure(textView, markdown); | ||||
|         AsyncDrawableScheduler.unschedule(textView); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void afterSetText(@NonNull TextView textView) { | ||||
|         AsyncDrawableScheduler.schedule(textView); | ||||
|     } | ||||
| 
 | ||||
|     protected void text(@NonNull MarkwonVisitor.Builder builder) { | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| package ru.noties.markwon.core; | ||||
| package ru.noties.markwon.image; | ||||
| 
 | ||||
| import android.graphics.Rect; | ||||
| import android.graphics.drawable.Drawable; | ||||
| @ -15,12 +15,11 @@ import java.util.Collections; | ||||
| import java.util.List; | ||||
| 
 | ||||
| import ru.noties.markwon.renderer.R; | ||||
| import ru.noties.markwon.image.AsyncDrawable; | ||||
| import ru.noties.markwon.spans.AsyncDrawableSpan; | ||||
| 
 | ||||
| abstract class AsyncDrawableScheduler { | ||||
| public abstract class AsyncDrawableScheduler { | ||||
| 
 | ||||
|     static void schedule(@NonNull final TextView textView) { | ||||
|     public static void schedule(@NonNull final TextView textView) { | ||||
| 
 | ||||
|         final List<AsyncDrawable> list = extract(textView); | ||||
|         if (list.size() > 0) { | ||||
| @ -50,7 +49,7 @@ abstract class AsyncDrawableScheduler { | ||||
|     } | ||||
| 
 | ||||
|     // must be called when text manually changed in TextView | ||||
|     static void unschedule(@NonNull TextView view) { | ||||
|     public static void unschedule(@NonNull TextView view) { | ||||
|         for (AsyncDrawable drawable : extract(view)) { | ||||
|             drawable.setCallback2(null); | ||||
|         } | ||||
| @ -2,6 +2,7 @@ package ru.noties.markwon.image; | ||||
| 
 | ||||
| import android.content.Context; | ||||
| import android.support.annotation.NonNull; | ||||
| import android.widget.TextView; | ||||
| 
 | ||||
| import org.commonmark.node.Image; | ||||
| import org.commonmark.node.Link; | ||||
| @ -89,4 +90,14 @@ public class ImagesPlugin extends AbstractMarkwonPlugin { | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void beforeSetText(@NonNull TextView textView, @NonNull CharSequence markdown) { | ||||
|         AsyncDrawableScheduler.unschedule(textView); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void afterSetText(@NonNull TextView textView) { | ||||
|         AsyncDrawableScheduler.schedule(textView); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -18,6 +18,7 @@ android { | ||||
| 
 | ||||
| dependencies { | ||||
|     implementation project(':markwon') | ||||
|     implementation project(':markwon-ext-latex') | ||||
| //    implementation project(':markwon-image-loader') | ||||
|     implementation 'ru.noties:jlatexmath-android:0.1.0' | ||||
| //    implementation 'ru.noties:jlatexmath-android:0.1.0' | ||||
| } | ||||
|  | ||||
| @ -1,138 +0,0 @@ | ||||
| package ru.noties.markwon.sample.jlatexmath; | ||||
| 
 | ||||
| import android.graphics.drawable.Drawable; | ||||
| import android.net.Uri; | ||||
| import android.support.annotation.NonNull; | ||||
| import android.support.annotation.Nullable; | ||||
| 
 | ||||
| import java.io.ByteArrayInputStream; | ||||
| import java.io.InputStream; | ||||
| import java.io.UnsupportedEncodingException; | ||||
| import java.util.Collection; | ||||
| import java.util.Collections; | ||||
| import java.util.Scanner; | ||||
| 
 | ||||
| import ru.noties.jlatexmath.JLatexMathDrawable; | ||||
| import ru.noties.markwon.il.ImageItem; | ||||
| import ru.noties.markwon.il.MediaDecoder; | ||||
| import ru.noties.markwon.il.SchemeHandler; | ||||
| 
 | ||||
| public class JLatexMathMedia { | ||||
| 
 | ||||
|     public static class Config { | ||||
| 
 | ||||
|         protected final float textSize; | ||||
| 
 | ||||
|         protected Drawable background; | ||||
| 
 | ||||
|         @JLatexMathDrawable.Align | ||||
|         protected int align = JLatexMathDrawable.ALIGN_CENTER; | ||||
| 
 | ||||
|         protected boolean fitCanvas = true; | ||||
| 
 | ||||
|         protected int padding; | ||||
| 
 | ||||
|         public Config(float textSize) { | ||||
|             this.textSize = textSize; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     public static String makeDestination(@NonNull String latex) { | ||||
|         return SCHEME + "://" + latex; | ||||
|     } | ||||
| 
 | ||||
|     private static final String SCHEME = "jlatexmath"; | ||||
|     private static final String CONTENT_TYPE = "text/jlatexmath"; | ||||
| 
 | ||||
|     private final Config config; | ||||
| 
 | ||||
|     public JLatexMathMedia(@NonNull Config config) { | ||||
|         this.config = config; | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     public SchemeHandler schemeHandler() { | ||||
|         return new SchemeHandlerImpl(); | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     public MediaDecoder mediaDecoder() { | ||||
|         return new MediaDecoderImpl(config); | ||||
|     } | ||||
| 
 | ||||
|     static class SchemeHandlerImpl extends SchemeHandler { | ||||
| 
 | ||||
|         @Nullable | ||||
|         @Override | ||||
|         public ImageItem handle(@NonNull String raw, @NonNull Uri uri) { | ||||
| 
 | ||||
|             ImageItem item = null; | ||||
| 
 | ||||
|             try { | ||||
|                 final byte[] bytes = raw.substring(SCHEME.length()).getBytes("UTF-8"); | ||||
|                 item = new ImageItem( | ||||
|                         CONTENT_TYPE, | ||||
|                         new ByteArrayInputStream(bytes), | ||||
|                         null | ||||
|                 ); | ||||
|             } catch (UnsupportedEncodingException e) { | ||||
|                 e.printStackTrace(); | ||||
|             } | ||||
| 
 | ||||
|             return item; | ||||
|         } | ||||
| 
 | ||||
|         @Override | ||||
|         public void cancel(@NonNull String raw) { | ||||
|             // no op | ||||
|         } | ||||
| 
 | ||||
|         @NonNull | ||||
|         @Override | ||||
|         public Collection<String> schemes() { | ||||
|             return Collections.singleton(SCHEME); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     static class MediaDecoderImpl extends MediaDecoder { | ||||
| 
 | ||||
|         private final Config config; | ||||
| 
 | ||||
|         MediaDecoderImpl(@NonNull Config config) { | ||||
|             this.config = config; | ||||
|         } | ||||
| 
 | ||||
|         @Override | ||||
|         public boolean canDecodeByContentType(@Nullable String contentType) { | ||||
|             return CONTENT_TYPE.equals(contentType); | ||||
|         } | ||||
| 
 | ||||
|         @Override | ||||
|         public boolean canDecodeByFileName(@NonNull String fileName) { | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         @Nullable | ||||
|         @Override | ||||
|         public Drawable decode(@NonNull InputStream inputStream) { | ||||
| 
 | ||||
|             final Scanner scanner = new Scanner(inputStream, "UTF-8").useDelimiter("\\A"); | ||||
|             final String latex = scanner.hasNext() | ||||
|                     ? scanner.next() | ||||
|                     : null; | ||||
| 
 | ||||
|             if (latex == null) { | ||||
|                 return null; | ||||
|             } | ||||
| 
 | ||||
|             return JLatexMathDrawable.builder(latex) | ||||
|                     .textSize(config.textSize) | ||||
|                     .background(config.background) | ||||
|                     .align(config.align) | ||||
|                     .fitCanvas(config.fitCanvas) | ||||
|                     .padding(config.padding) | ||||
|                     .build(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -4,17 +4,10 @@ import android.app.Activity; | ||||
| import android.os.Bundle; | ||||
| import android.widget.TextView; | ||||
| 
 | ||||
| import org.commonmark.node.CustomBlock; | ||||
| import org.commonmark.node.Node; | ||||
| import org.commonmark.parser.Parser; | ||||
| 
 | ||||
| import ru.noties.jlatexmath.JLatexMathAndroid; | ||||
| import ru.noties.markwon.Markwon; | ||||
| import ru.noties.markwon.MarkwonConfiguration; | ||||
| import ru.noties.markwon.SpannableBuilder; | ||||
| import ru.noties.markwon.il.AsyncDrawableLoader; | ||||
| import ru.noties.markwon.image.ImageSize; | ||||
| import ru.noties.markwon.renderer.SpannableMarkdownVisitor; | ||||
| import ru.noties.markwon.core.CorePlugin; | ||||
| import ru.noties.markwon.ext.latex.JLatexMathPlugin; | ||||
| import ru.noties.markwon.image.ImagesPlugin; | ||||
| 
 | ||||
| public class MainActivity extends Activity { | ||||
| 
 | ||||
| @ -45,61 +38,21 @@ public class MainActivity extends Activity { | ||||
| //        latex += "\\end{array}"; | ||||
| 
 | ||||
| 
 | ||||
|         final JLatexMathMedia.Config config = new JLatexMathMedia.Config(textView.getTextSize()) {{ | ||||
|         final JLatexMathPlugin.Config config = new JLatexMathPlugin.Config(textView.getTextSize()) {{ | ||||
| //            align = JLatexMathDrawable.ALIGN_RIGHT; | ||||
|         }}; | ||||
|         final JLatexMathMedia jLatexMathMedia = new JLatexMathMedia(config); | ||||
| 
 | ||||
|         final AsyncDrawableLoader asyncDrawableLoader = AsyncDrawableLoader.builder() | ||||
|                 .addSchemeHandler(jLatexMathMedia.schemeHandler()) | ||||
|                 .mediaDecoders(jLatexMathMedia.mediaDecoder()) | ||||
|                 .build(); | ||||
| 
 | ||||
|         final MarkwonConfiguration configuration = MarkwonConfiguration.builder(this) | ||||
|                 .asyncDrawableLoader(asyncDrawableLoader) | ||||
|                 .build(); | ||||
| 
 | ||||
|         final String markdown = "# Example of LaTeX\n\n$$" | ||||
|                 + latex + "$$\n\n something like **this**"; | ||||
| 
 | ||||
|         final Parser parser = new Parser.Builder() | ||||
|                 .customBlockParserFactory(new JLatexMathBlockParser.Factory()) | ||||
|         final Markwon markwon = Markwon.builder(this) | ||||
|                 .use(CorePlugin.create()) | ||||
|                 // strictly speaking this one is not required as long as JLatexMathPlugin schedules | ||||
|                 // drawables on it's own | ||||
|                 .use(ImagesPlugin.create(this)) | ||||
|                 .use(JLatexMathPlugin.create(config)) | ||||
|                 .build(); | ||||
| 
 | ||||
|         final Node node = parser.parse(markdown); | ||||
|         final SpannableBuilder builder = new SpannableBuilder(); | ||||
|         final SpannableMarkdownVisitor visitor = new SpannableMarkdownVisitor(MarkwonConfiguration.create(this), builder) { | ||||
| 
 | ||||
|             @Override | ||||
|             public void visit(CustomBlock customBlock) { | ||||
| 
 | ||||
|                 if (!(customBlock instanceof JLatexMathBlock)) { | ||||
|                     super.visit(customBlock); | ||||
|                     return; | ||||
|                 } | ||||
| 
 | ||||
|                 final String latex = ((JLatexMathBlock) customBlock).latex(); | ||||
| 
 | ||||
|                 final int length = builder.length(); | ||||
|                 builder.append(latex); | ||||
| 
 | ||||
|                 SpannableBuilder.setSpans( | ||||
|                         builder, | ||||
|                         configuration.factory().image( | ||||
|                                 configuration.theme(), | ||||
|                                 JLatexMathMedia.makeDestination(latex), | ||||
|                                 configuration.asyncDrawableLoader(), | ||||
|                                 configuration.imageSizeResolver(), | ||||
|                                 new ImageSize(new ImageSize.Dimension(100, "%"), null), | ||||
|                                 false | ||||
|                         ), | ||||
|                         length, | ||||
|                         builder.length() | ||||
|                 ); | ||||
|             } | ||||
|         }; | ||||
|         node.accept(visitor); | ||||
| 
 | ||||
|         Markwon.setText(textView, builder.text()); | ||||
|         markwon.setMarkdown(textView, markdown); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -1,6 +1,7 @@ | ||||
| rootProject.name = 'MarkwonProject' | ||||
| include ':app', | ||||
|         ':markwon', | ||||
|         ':markwon-ext-latex', | ||||
|         ':markwon-ext-strikethrough', | ||||
|         ':markwon-ext-tables', | ||||
|         ':markwon-ext-tasklist', | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Dimitry Ivanov
						Dimitry Ivanov