Add sample-latex-math module
This commit is contained in:
parent
fde9712454
commit
073f41b5f6
23
sample-latex-math/build.gradle
Normal file
23
sample-latex-math/build.gradle
Normal file
@ -0,0 +1,23 @@
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
|
||||
compileSdkVersion config['compile-sdk']
|
||||
buildToolsVersion config['build-tools']
|
||||
|
||||
defaultConfig {
|
||||
|
||||
applicationId "ru.noties.markwon.sample.jlatexmath"
|
||||
|
||||
minSdkVersion config['min-sdk']
|
||||
targetSdkVersion config['target-sdk']
|
||||
versionCode 1
|
||||
versionName version
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation project(':markwon')
|
||||
implementation project(':markwon-image-loader')
|
||||
implementation 'ru.noties:jlatexmath-android:0.1.0'
|
||||
}
|
18
sample-latex-math/src/main/AndroidManifest.xml
Normal file
18
sample-latex-math/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="ru.noties.markwon.sample.jlatexmath">
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:label="@string/app_name"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme">
|
||||
<activity android:name=".MainActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
@ -0,0 +1,16 @@
|
||||
package ru.noties.markwon.sample.jlatexmath;
|
||||
|
||||
import org.commonmark.node.CustomBlock;
|
||||
|
||||
public class JLatexMathBlock extends CustomBlock {
|
||||
|
||||
private String latex;
|
||||
|
||||
public String latex() {
|
||||
return latex;
|
||||
}
|
||||
|
||||
public void latex(String latex) {
|
||||
this.latex = latex;
|
||||
}
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
package ru.noties.markwon.sample.jlatexmath;
|
||||
|
||||
import org.commonmark.node.Block;
|
||||
import org.commonmark.parser.block.AbstractBlockParser;
|
||||
import org.commonmark.parser.block.AbstractBlockParserFactory;
|
||||
import org.commonmark.parser.block.BlockContinue;
|
||||
import org.commonmark.parser.block.BlockStart;
|
||||
import org.commonmark.parser.block.MatchedBlockParser;
|
||||
import org.commonmark.parser.block.ParserState;
|
||||
|
||||
public class JLatexMathBlockParser extends AbstractBlockParser {
|
||||
|
||||
private final JLatexMathBlock block = new JLatexMathBlock();
|
||||
|
||||
private final StringBuilder builder = new StringBuilder();
|
||||
|
||||
private boolean isClosed;
|
||||
|
||||
@Override
|
||||
public Block getBlock() {
|
||||
return block;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockContinue tryContinue(ParserState parserState) {
|
||||
|
||||
if (isClosed) {
|
||||
return BlockContinue.finished();
|
||||
}
|
||||
|
||||
return BlockContinue.atIndex(parserState.getIndex());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addLine(CharSequence line) {
|
||||
|
||||
if (builder.length() > 0) {
|
||||
builder.append('\n');
|
||||
}
|
||||
|
||||
builder.append(line);
|
||||
|
||||
final int length = builder.length();
|
||||
if (length > 1) {
|
||||
isClosed = '$' == builder.charAt(length - 1)
|
||||
&& '$' == builder.charAt(length - 2);
|
||||
if (isClosed) {
|
||||
builder.replace(length - 2, length, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeBlock() {
|
||||
block.latex(builder.toString());
|
||||
}
|
||||
|
||||
public static class Factory extends AbstractBlockParserFactory {
|
||||
|
||||
@Override
|
||||
public BlockStart tryStart(ParserState state, MatchedBlockParser matchedBlockParser) {
|
||||
|
||||
final CharSequence line = state.getLine();
|
||||
final int length = line != null
|
||||
? line.length()
|
||||
: 0;
|
||||
|
||||
if (length > 1) {
|
||||
if ('$' == line.charAt(0)
|
||||
&& '$' == line.charAt(1)) {
|
||||
return BlockStart.of(new JLatexMathBlockParser())
|
||||
.atIndex(state.getIndex() + 2);
|
||||
}
|
||||
}
|
||||
|
||||
return BlockStart.none();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,137 @@
|
||||
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 android.util.Log;
|
||||
|
||||
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.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;
|
||||
}
|
||||
}
|
||||
|
||||
public static final String SCHEME = "jlatexmath";
|
||||
|
||||
@NonNull
|
||||
public static String makeDestination(@NonNull String latex) {
|
||||
return SCHEME + "://" + latex;
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
Log.e("handle", raw);
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
Log.e("decode", latex);
|
||||
|
||||
if (latex == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// todo: change to float
|
||||
return JLatexMathDrawable.builder(latex)
|
||||
.textSize((int) config.textSize)
|
||||
.background(config.background)
|
||||
.align(config.align)
|
||||
.fitCanvas(config.fitCanvas)
|
||||
.padding(config.padding)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,113 @@
|
||||
package ru.noties.markwon.sample.jlatexmath;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
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.jlatexmath.JLatexMathDrawable;
|
||||
import ru.noties.markwon.Markwon;
|
||||
import ru.noties.markwon.SpannableBuilder;
|
||||
import ru.noties.markwon.SpannableConfiguration;
|
||||
import ru.noties.markwon.il.AsyncDrawableLoader;
|
||||
import ru.noties.markwon.renderer.ImageSize;
|
||||
import ru.noties.markwon.renderer.SpannableMarkdownVisitor;
|
||||
|
||||
public class MainActivity extends Activity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main);
|
||||
|
||||
// todo: later version has automatic initialization
|
||||
JLatexMathAndroid.init(this);
|
||||
|
||||
final TextView textView = findViewById(R.id.text_view);
|
||||
|
||||
// this one fails due input sanitizing on commonmark-java side
|
||||
String latex = "\\begin{array}{l}";
|
||||
latex += "\\forall\\varepsilon\\in\\mathbb{R}_+^*\\ \\exists\\eta>0\\ |x-x_0|\\leq\\eta\\Longrightarrow|f(x)-f(x_0)|\\leq\\varepsilon\\\\";
|
||||
latex += "\\det\\begin{bmatrix}a_{11}&a_{12}&\\cdots&a_{1n}\\\\a_{21}&\\ddots&&\\vdots\\\\\\vdots&&\\ddots&\\vdots\\\\a_{n1}&\\cdots&\\cdots&a_{nn}\\end{bmatrix}\\overset{\\mathrm{def}}{=}\\sum_{\\sigma\\in\\mathfrak{S}_n}\\varepsilon(\\sigma)\\prod_{k=1}^n a_{k\\sigma(k)}\\\\";
|
||||
latex += "\\sideset{_\\alpha^\\beta}{_\\gamma^\\delta}{\\begin{pmatrix}a&b\\\\c&d\\end{pmatrix}}\\\\";
|
||||
latex += "\\int_0^\\infty{x^{2n} e^{-a x^2}\\,dx} = \\frac{2n-1}{2a} \\int_0^\\infty{x^{2(n-1)} e^{-a x^2}\\,dx} = \\frac{(2n-1)!!}{2^{n+1}} \\sqrt{\\frac{\\pi}{a^{2n+1}}}\\\\";
|
||||
latex += "\\int_a^b{f(x)\\,dx} = (b - a) \\sum\\limits_{n = 1}^\\infty {\\sum\\limits_{m = 1}^{2^n - 1} {\\left( { - 1} \\right)^{m + 1} } } 2^{ - n} f(a + m\\left( {b - a} \\right)2^{-n} )\\\\";
|
||||
latex += "\\int_{-\\pi}^{\\pi} \\sin(\\alpha x) \\sin^n(\\beta x) dx = \\textstyle{\\left \\{ \\begin{array}{cc} (-1)^{(n+1)/2} (-1)^m \\frac{2 \\pi}{2^n} \\binom{n}{m} & n \\mbox{ odd},\\ \\alpha = \\beta (2m-n) \\\\ 0 & \\mbox{otherwise} \\\\ \\end{array} \\right .}\\\\";
|
||||
latex += "L = \\int_a^b \\sqrt{ \\left|\\sum_{i,j=1}^ng_{ij}(\\gamma(t))\\left(\\frac{d}{dt}x^i\\circ\\gamma(t)\\right)\\left(\\frac{d}{dt}x^j\\circ\\gamma(t)\\right)\\right|}\\,dt\\\\";
|
||||
latex += "\\begin{array}{rl} s &= \\int_a^b\\left\\|\\frac{d}{dt}\\vec{r}\\,(u(t),v(t))\\right\\|\\,dt \\\\ &= \\int_a^b \\sqrt{u'(t)^2\\,\\vec{r}_u\\cdot\\vec{r}_u + 2u'(t)v'(t)\\, \\vec{r}_u\\cdot\\vec{r}_v+ v'(t)^2\\,\\vec{r}_v\\cdot\\vec{r}_v}\\,\\,\\, dt. \\end{array}\\\\";
|
||||
latex += "\\end{array}";
|
||||
|
||||
// String latex = "\\text{A long division \\longdiv{12345}{13}";
|
||||
// String latex = "{a \\bangle b} {c \\brace d} {e \\brack f} {g \\choose h}";
|
||||
|
||||
// String latex = "\\begin{array}{cc}";
|
||||
// latex += "\\fbox{\\text{A framed box with \\textdbend}}&\\shadowbox{\\text{A shadowed box}}\\cr";
|
||||
// latex += "\\doublebox{\\text{A double framed box}}&\\ovalbox{\\text{An oval framed box}}\\cr";
|
||||
// latex += "\\end{array}";
|
||||
|
||||
// mention another way of doing this: through async drawable to process formulas in background
|
||||
|
||||
|
||||
final JLatexMathMedia.Config config = new JLatexMathMedia.Config(textView.getTextSize()) {{
|
||||
// align = JLatexMathDrawable.ALIGN_RIGHT;
|
||||
}};
|
||||
final JLatexMathMedia jLatexMathMedia = new JLatexMathMedia(config);
|
||||
|
||||
final AsyncDrawableLoader asyncDrawableLoader = AsyncDrawableLoader.builder()
|
||||
.schemeHandler(JLatexMathMedia.SCHEME, jLatexMathMedia.schemeHandler())
|
||||
.mediaDecoders(jLatexMathMedia.mediaDecoder())
|
||||
.build();
|
||||
|
||||
final SpannableConfiguration configuration = SpannableConfiguration.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())
|
||||
.build();
|
||||
|
||||
final Node node = parser.parse(markdown);
|
||||
final SpannableBuilder builder = new SpannableBuilder();
|
||||
final SpannableMarkdownVisitor visitor = new SpannableMarkdownVisitor(SpannableConfiguration.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());
|
||||
}
|
||||
}
|
14
sample-latex-math/src/main/res/layout/activity_main.xml
Normal file
14
sample-latex-math/src/main/res/layout/activity_main.xml
Normal file
@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="16dip" />
|
||||
|
||||
</ScrollView>
|
3
sample-latex-math/src/main/res/values/strings.xml
Normal file
3
sample-latex-math/src/main/res/values/strings.xml
Normal file
@ -0,0 +1,3 @@
|
||||
<resources>
|
||||
<string name="app_name">Markwon-JLatexMath</string>
|
||||
</resources>
|
6
sample-latex-math/src/main/res/values/styles.xml
Normal file
6
sample-latex-math/src/main/res/values/styles.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<resources>
|
||||
|
||||
<style name="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar">
|
||||
</style>
|
||||
|
||||
</resources>
|
@ -1,3 +1,3 @@
|
||||
rootProject.name = 'MarkwonProject'
|
||||
include ':app', ':markwon', ':markwon-image-loader', ':markwon-view', ':sample-custom-extension',
|
||||
include ':app', ':markwon', ':markwon-image-loader', ':markwon-view', ':sample-custom-extension', ':sample-latex-math',
|
||||
':markwon-syntax-highlight', ':markwon-html-parser-api', ':markwon-html-parser-impl'
|
||||
|
Loading…
x
Reference in New Issue
Block a user