diff --git a/app/build.gradle b/app/build.gradle
index 4d5a2ae1..3c747a17 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -18,4 +18,5 @@ dependencies {
compile project(':library-renderer')
compile 'ru.noties:debug:3.0.0@jar'
compile 'com.squareup.picasso:picasso:2.5.2'
+ compile 'com.squareup.okhttp3:okhttp:3.8.0'
}
diff --git a/app/src/main/java/ru/noties/markwon/MainActivity.java b/app/src/main/java/ru/noties/markwon/MainActivity.java
index eb178f80..8c22023a 100644
--- a/app/src/main/java/ru/noties/markwon/MainActivity.java
+++ b/app/src/main/java/ru/noties/markwon/MainActivity.java
@@ -30,7 +30,7 @@ import ru.noties.debug.Debug;
import ru.noties.markwon.renderer.*;
import ru.noties.markwon.spans.AsyncDrawable;
import ru.noties.markwon.spans.CodeSpan;
-import ru.noties.markwon.spans.DrawableSpanUtils;
+import ru.noties.markwon.spans.AsyncDrawableSpanUtils;
public class MainActivity extends Activity {
@@ -101,50 +101,52 @@ public class MainActivity extends Activity {
.build();
final Node node = parser.parse(md);
- final SpannableConfiguration configuration = SpannableConfiguration.builder(MainActivity.this)
- .setAsyncDrawableLoader(new AsyncDrawable.Loader() {
- @Override
- public void load(@NonNull String destination, @NonNull final AsyncDrawable drawable) {
- Debug.i(destination);
- final Target target = new Target() {
- @Override
- public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
- Debug.i();
- final Drawable d = new BitmapDrawable(getResources(), bitmap);
- d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
- drawable.setResult(d);
-// textView.setText(textView.getText());
- }
+// final SpannableConfiguration configuration = SpannableConfiguration.builder(MainActivity.this)
+// .setAsyncDrawableLoader(new AsyncDrawable.Loader() {
+// @Override
+// public void load(@NonNull String destination, @NonNull final AsyncDrawable drawable) {
+// Debug.i(destination);
+// final Target target = new Target() {
+// @Override
+// public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
+// Debug.i();
+// final Drawable d = new BitmapDrawable(getResources(), bitmap);
+// d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
+// drawable.setResult(d);
+//// textView.setText(textView.getText());
+// }
+//
+// @Override
+// public void onBitmapFailed(Drawable errorDrawable) {
+// Debug.i();
+// }
+//
+// @Override
+// public void onPrepareLoad(Drawable placeHolderDrawable) {
+// Debug.i();
+// }
+// };
+// targets.add(target);
+//
+// picasso.load(destination)
+// .tag(destination)
+// .into(target);
+//
+// }
+//
+// @Override
+// public void cancel(@NonNull String destination) {
+// Debug.i(destination);
+// picasso
+// .cancelTag(destination);
+// }
+// })
+// .setCodeConfig(CodeSpan.Config.builder().setTextSize(
+// (int) (getResources().getDisplayMetrics().density * 14 + .5F)
+// ).setMultilineMargin((int) (getResources().getDisplayMetrics().density * 8 + .5F)).build())
+// .build();
- @Override
- public void onBitmapFailed(Drawable errorDrawable) {
- Debug.i();
- }
-
- @Override
- public void onPrepareLoad(Drawable placeHolderDrawable) {
- Debug.i();
- }
- };
- targets.add(target);
-
- picasso.load(destination)
- .tag(destination)
- .into(target);
-
- }
-
- @Override
- public void cancel(@NonNull String destination) {
- Debug.i(destination);
- picasso
- .cancelTag(destination);
- }
- })
- .setCodeConfig(CodeSpan.Config.builder().setTextSize(
- (int) (getResources().getDisplayMetrics().density * 14 + .5F)
- ).setMultilineMargin((int) (getResources().getDisplayMetrics().density * 8 + .5F)).build())
- .build();
+ final SpannableConfiguration configuration = SpannableConfiguration.create(MainActivity.this);
final CharSequence text = new ru.noties.markwon.renderer.SpannableRenderer().render(
configuration,
@@ -168,7 +170,7 @@ public class MainActivity extends Activity {
// NB! LinkMovementMethod forces frequent updates...
textView.setMovementMethod(LinkMovementMethod.getInstance());
textView.setText(text);
- DrawableSpanUtils.scheduleDrawables(textView);
+ AsyncDrawableSpanUtils.scheduleDrawables(textView);
}
});
}
diff --git a/app/src/main/java/ru/noties/markwon/SpannableRenderer.java b/app/src/main/java/ru/noties/markwon/SpannableRenderer.java
index 7d381fb2..aee93ac4 100644
--- a/app/src/main/java/ru/noties/markwon/SpannableRenderer.java
+++ b/app/src/main/java/ru/noties/markwon/SpannableRenderer.java
@@ -53,8 +53,8 @@
//import ru.noties.markwon.spans.EmphasisSpan;
//import ru.noties.markwon.spans.BulletListItemSpan;
//import ru.noties.markwon.spans.StrongEmphasisSpan;
-//import ru.noties.markwon.spans.SubSpan;
-//import ru.noties.markwon.spans.SupSpan;
+//import ru.noties.markwon.spans.SubScriptSpan;
+//import ru.noties.markwon.spans.SuperScriptSpan;
//import ru.noties.markwon.spans.ThematicBreakSpan;
//
//public class SpannableRenderer implements Renderer {
@@ -263,9 +263,9 @@
// final int end = builder.length();
// // here, additionally, we can render some tags ourselves (sup/sub)
// if ("sup".equals(item.tag)) {
-// builder.setSpan(new SupSpan(), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+// builder.setSpan(new SuperScriptSpan(), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
// } else if("sub".equals(item.tag)) {
-// builder.setSpan(new SubSpan(), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+// builder.setSpan(new SubScriptSpan(), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
// } else if("del".equals(item.tag)) {
// // weird, but `Html` class does not return a spannable for `o`
// // seems like a bug
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index fb275f3b..3dacf3f3 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -5,7 +5,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
-
- #3F51B5
- #303F9F
- #FF4081
+ #424242
+ #212121
+ #4caf50
diff --git a/build.gradle b/build.gradle
index 43ca8a81..9b51f6fc 100644
--- a/build.gradle
+++ b/build.gradle
@@ -3,7 +3,7 @@ buildscript {
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:2.3.1'
+ classpath 'com.android.tools.build:gradle:2.3.2'
}
}
diff --git a/library-renderer/build.gradle b/library-renderer/build.gradle
index faf18fd8..0a53e40a 100644
--- a/library-renderer/build.gradle
+++ b/library-renderer/build.gradle
@@ -15,8 +15,6 @@ android {
dependencies {
- compile project(':library-spans')
-
compile SUPPORT_ANNOTATIONS
compile COMMON_MARK
compile COMMON_MARK_STRIKETHROUGHT
diff --git a/library-renderer/src/main/java/ru/noties/markwon/renderer/LinkResolverDef.java b/library-renderer/src/main/java/ru/noties/markwon/renderer/LinkResolverDef.java
new file mode 100644
index 00000000..a653e1bb
--- /dev/null
+++ b/library-renderer/src/main/java/ru/noties/markwon/renderer/LinkResolverDef.java
@@ -0,0 +1,27 @@
+package ru.noties.markwon.renderer;
+
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.provider.Browser;
+import android.support.annotation.NonNull;
+import android.util.Log;
+import android.view.View;
+
+import ru.noties.markwon.spans.LinkSpan;
+
+class LinkResolverDef implements LinkSpan.Resolver {
+ @Override
+ public void resolve(View view, @NonNull String link) {
+ final Uri uri = Uri.parse(link);
+ final Context context = view.getContext();
+ final Intent intent = new Intent(Intent.ACTION_VIEW, uri);
+ intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
+ try {
+ context.startActivity(intent);
+ } catch (ActivityNotFoundException e) {
+ Log.w("LinkResolverDef", "Actvity was not found for intent, " + intent.toString());
+ }
+ }
+}
diff --git a/library-renderer/src/main/java/ru/noties/markwon/renderer/SpannableConfiguration.java b/library-renderer/src/main/java/ru/noties/markwon/renderer/SpannableConfiguration.java
index a483e045..32652faa 100644
--- a/library-renderer/src/main/java/ru/noties/markwon/renderer/SpannableConfiguration.java
+++ b/library-renderer/src/main/java/ru/noties/markwon/renderer/SpannableConfiguration.java
@@ -4,12 +4,8 @@ import android.content.Context;
import android.support.annotation.NonNull;
import ru.noties.markwon.spans.AsyncDrawable;
-import ru.noties.markwon.spans.BlockQuoteSpan;
-import ru.noties.markwon.spans.BulletListItemSpan;
-import ru.noties.markwon.spans.CodeSpan;
-import ru.noties.markwon.spans.HeadingSpan;
-import ru.noties.markwon.spans.OrderedListItemSpan;
-import ru.noties.markwon.spans.ThematicBreakSpan;
+import ru.noties.markwon.spans.LinkSpan;
+import ru.noties.markwon.spans.SpannableTheme;
public class SpannableConfiguration {
@@ -22,140 +18,81 @@ public class SpannableConfiguration {
return new Builder(context);
}
- private final BlockQuoteSpan.Config blockQuoteConfig;
- private final CodeSpan.Config codeConfig;
- private final BulletListItemSpan.Config bulletListConfig;
- private final HeadingSpan.Config headingConfig;
- private final ThematicBreakSpan.Config thematicConfig;
- private final OrderedListItemSpan.Config orderedListConfig;
+ private final SpannableTheme theme;
private final AsyncDrawable.Loader asyncDrawableLoader;
+ private final SyntaxHighlight syntaxHighlight;
+ private final LinkSpan.Resolver linkResolver;
private SpannableConfiguration(Builder builder) {
- this.blockQuoteConfig = builder.blockQuoteConfig;
- this.codeConfig = builder.codeConfig;
- this.bulletListConfig = builder.bulletListConfig;
- this.headingConfig = builder.headingConfig;
- this.thematicConfig = builder.thematicConfig;
- this.orderedListConfig = builder.orderedListConfig;
+ this.theme = builder.theme;
this.asyncDrawableLoader = builder.asyncDrawableLoader;
+ this.syntaxHighlight = builder.syntaxHighlight;
+ this.linkResolver = builder.linkResolver;
}
- public BlockQuoteSpan.Config getBlockQuoteConfig() {
- return blockQuoteConfig;
+ public SpannableTheme theme() {
+ return theme;
}
- public CodeSpan.Config getCodeConfig() {
- return codeConfig;
- }
-
- public BulletListItemSpan.Config getBulletListConfig() {
- return bulletListConfig;
- }
-
- public HeadingSpan.Config getHeadingConfig() {
- return headingConfig;
- }
-
- public ThematicBreakSpan.Config getThematicConfig() {
- return thematicConfig;
- }
-
- public OrderedListItemSpan.Config getOrderedListConfig() {
- return orderedListConfig;
- }
-
- public AsyncDrawable.Loader getAsyncDrawableLoader() {
+ public AsyncDrawable.Loader asyncDrawableLoader() {
return asyncDrawableLoader;
}
+ public SyntaxHighlight syntaxHighlight() {
+ return syntaxHighlight;
+ }
+
+ public LinkSpan.Resolver linkResolver() {
+ return linkResolver;
+ }
+
public static class Builder {
private final Context context;
- private BlockQuoteSpan.Config blockQuoteConfig;
- private CodeSpan.Config codeConfig;
- private BulletListItemSpan.Config bulletListConfig;
- private HeadingSpan.Config headingConfig;
- private ThematicBreakSpan.Config thematicConfig;
- private OrderedListItemSpan.Config orderedListConfig;
+ private SpannableTheme theme;
private AsyncDrawable.Loader asyncDrawableLoader;
+ private SyntaxHighlight syntaxHighlight;
+ private LinkSpan.Resolver linkResolver;
public Builder(Context context) {
this.context = context;
}
- public Builder setBlockQuoteConfig(@NonNull BlockQuoteSpan.Config blockQuoteConfig) {
- this.blockQuoteConfig = blockQuoteConfig;
+ public Builder theme(SpannableTheme theme) {
+ this.theme = theme;
return this;
}
- public Builder setCodeConfig(@NonNull CodeSpan.Config codeConfig) {
- this.codeConfig = codeConfig;
- return this;
- }
-
- public Builder setBulletListConfig(@NonNull BulletListItemSpan.Config bulletListConfig) {
- this.bulletListConfig = bulletListConfig;
- return this;
- }
-
- public Builder setHeadingConfig(@NonNull HeadingSpan.Config headingConfig) {
- this.headingConfig = headingConfig;
- return this;
- }
-
- public Builder setThematicConfig(@NonNull ThematicBreakSpan.Config thematicConfig) {
- this.thematicConfig = thematicConfig;
- return this;
- }
-
- public Builder setOrderedListConfig(@NonNull OrderedListItemSpan.Config orderedListConfig) {
- this.orderedListConfig = orderedListConfig;
- return this;
- }
-
- public Builder setAsyncDrawableLoader(AsyncDrawable.Loader asyncDrawableLoader) {
+ public Builder asyncDrawableLoader(AsyncDrawable.Loader asyncDrawableLoader) {
this.asyncDrawableLoader = asyncDrawableLoader;
return this;
}
- // todo, change to something more reliable
- // todo, must mention that bullet/ordered/quote must have the same margin (or maybe we can just enforce it?)
- // actually it does make sense to have `blockQuote` & `list` margins (if they are different)
- // todo, maybe move defaults to configuration classes?
+ public Builder syntaxHighlight(SyntaxHighlight syntaxHighlight) {
+ this.syntaxHighlight = syntaxHighlight;
+ return this;
+ }
+
+ public Builder linkResolver(LinkSpan.Resolver linkResolver) {
+ this.linkResolver = linkResolver;
+ return this;
+ }
+
public SpannableConfiguration build() {
- if (blockQuoteConfig == null) {
- blockQuoteConfig = new BlockQuoteSpan.Config(
- px(24),
- 0,
- 0
- );
- }
- if (codeConfig == null) {
- codeConfig = CodeSpan.Config.builder()
- .setMultilineMargin(px(8))
- .build();
- }
- if (bulletListConfig == null) {
- bulletListConfig = new BulletListItemSpan.Config(px(24), 0, px(8), px(1));
- }
- if (headingConfig == null) {
- headingConfig = new HeadingSpan.Config(px(1), 0);
- }
- if (thematicConfig == null) {
- thematicConfig = new ThematicBreakSpan.Config(0, px(2));
- }
- if (orderedListConfig == null) {
- orderedListConfig = new OrderedListItemSpan.Config(px(24), 0);
+ if (theme == null) {
+ theme = SpannableTheme.create(context);
}
if (asyncDrawableLoader == null) {
asyncDrawableLoader = new AsyncDrawableLoaderNoOp();
}
+ if (syntaxHighlight == null) {
+ syntaxHighlight = new SyntaxHighlightNoOp();
+ }
+ if (linkResolver == null) {
+ linkResolver = new LinkResolverDef();
+ }
return new SpannableConfiguration(this);
}
-
- private int px(int dp) {
- return (int) (context.getResources().getDisplayMetrics().density * dp + .5F);
- }
}
}
diff --git a/library-renderer/src/main/java/ru/noties/markwon/renderer/SpannableMarkdownVisitor.java b/library-renderer/src/main/java/ru/noties/markwon/renderer/SpannableMarkdownVisitor.java
index 589dc337..d13fcbca 100644
--- a/library-renderer/src/main/java/ru/noties/markwon/renderer/SpannableMarkdownVisitor.java
+++ b/library-renderer/src/main/java/ru/noties/markwon/renderer/SpannableMarkdownVisitor.java
@@ -3,7 +3,6 @@ package ru.noties.markwon.renderer;
import android.support.annotation.NonNull;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
-import android.text.TextUtils;
import android.text.style.StrikethroughSpan;
import android.text.style.URLSpan;
@@ -38,6 +37,7 @@ import ru.noties.markwon.spans.BulletListItemSpan;
import ru.noties.markwon.spans.CodeSpan;
import ru.noties.markwon.spans.EmphasisSpan;
import ru.noties.markwon.spans.HeadingSpan;
+import ru.noties.markwon.spans.LinkSpan;
import ru.noties.markwon.spans.OrderedListItemSpan;
import ru.noties.markwon.spans.StrongEmphasisSpan;
import ru.noties.markwon.spans.ThematicBreakSpan;
@@ -97,7 +97,7 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
visitChildren(blockQuote);
setSpan(length, new BlockQuoteSpan(
- configuration.getBlockQuoteConfig(),
+ configuration.theme(),
blockQuoteIndent
));
@@ -123,7 +123,7 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
builder.append('\u00a0');
setSpan(length, new CodeSpan(
- configuration.getCodeConfig(),
+ configuration.theme(),
false
));
}
@@ -131,17 +131,20 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
@Override
public void visit(FencedCodeBlock fencedCodeBlock) {
-// Debug.i(fencedCodeBlock);
-
newLine();
final int length = builder.length();
+ // empty lines on top & bottom
builder.append('\u00a0').append('\n');
- builder.append(fencedCodeBlock.getLiteral());
+ builder.append(
+ configuration.syntaxHighlight()
+ .highlight(fencedCodeBlock.getInfo(), fencedCodeBlock.getLiteral())
+ );
builder.append('\u00a0').append('\n');
+
setSpan(length, new CodeSpan(
- configuration.getCodeConfig(),
+ configuration.theme(),
true
));
@@ -189,7 +192,7 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
visitChildren(listItem);
setSpan(length, new OrderedListItemSpan(
- configuration.getOrderedListConfig(),
+ configuration.theme(),
String.valueOf(start) + "." + '\u00a0',
blockQuoteIndent,
length
@@ -204,7 +207,7 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
visitChildren(listItem);
setSpan(length, new BulletListItemSpan(
- configuration.getBulletListConfig(),
+ configuration.theme(),
blockQuoteIndent,
listLevel - 1,
length
@@ -226,7 +229,7 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
final int length = builder.length();
builder.append(' '); // without space it won't render
- setSpan(length, new ThematicBreakSpan(configuration.getThematicConfig()));
+ setSpan(length, new ThematicBreakSpan(configuration.theme()));
newLine();
builder.append('\n');
@@ -242,7 +245,7 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
final int length = builder.length();
visitChildren(heading);
setSpan(length, new HeadingSpan(
- configuration.getHeadingConfig(),
+ configuration.theme(),
heading.getLevel(),
builder.length())
);
@@ -315,7 +318,18 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
builder.append(' '); // breakable space
}
- setSpan(length, new AsyncDrawableSpan(new AsyncDrawable(image.getDestination(), configuration.getAsyncDrawableLoader())));
+ final Node parent = image.getParent();
+ final boolean link = parent != null && parent instanceof Link;
+
+ setSpan(length, new AsyncDrawableSpan(
+ configuration.theme(),
+ new AsyncDrawable(
+ image.getDestination(),
+ configuration.asyncDrawableLoader()
+ ),
+ AsyncDrawableSpan.ALIGN_BOTTOM,
+ link)
+ );
}
@Override
@@ -329,7 +343,7 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
public void visit(Link link) {
final int length = builder.length();
visitChildren(link);
- setSpan(length, new URLSpan(link.getDestination()));
+ setSpan(length, new LinkSpan(configuration.theme(), link.getDestination(), configuration.linkResolver()));
}
private void setSpan(int start, @NonNull Object span) {
diff --git a/library-renderer/src/main/java/ru/noties/markwon/renderer/SpannableRenderer.java b/library-renderer/src/main/java/ru/noties/markwon/renderer/SpannableRenderer.java
index 69f78dcb..88265eeb 100644
--- a/library-renderer/src/main/java/ru/noties/markwon/renderer/SpannableRenderer.java
+++ b/library-renderer/src/main/java/ru/noties/markwon/renderer/SpannableRenderer.java
@@ -14,6 +14,7 @@ public class SpannableRenderer {
// * Common interface for images (in markdown & inline-html)
// * util method to properly copy markdown (with lists/links, etc)
// * util to apply empty line height
+ // * transform relative urls to absolute ones...
public CharSequence render(@NonNull SpannableConfiguration configuration, @Nullable Node node) {
final CharSequence out;
diff --git a/library-renderer/src/main/java/ru/noties/markwon/renderer/SyntaxHighlight.java b/library-renderer/src/main/java/ru/noties/markwon/renderer/SyntaxHighlight.java
new file mode 100644
index 00000000..4ab0b1dd
--- /dev/null
+++ b/library-renderer/src/main/java/ru/noties/markwon/renderer/SyntaxHighlight.java
@@ -0,0 +1,10 @@
+package ru.noties.markwon.renderer;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+public interface SyntaxHighlight {
+
+ @NonNull
+ CharSequence highlight(@Nullable String info, @NonNull String code);
+}
diff --git a/library-renderer/src/main/java/ru/noties/markwon/renderer/SyntaxHighlightNoOp.java b/library-renderer/src/main/java/ru/noties/markwon/renderer/SyntaxHighlightNoOp.java
new file mode 100644
index 00000000..4df3b68e
--- /dev/null
+++ b/library-renderer/src/main/java/ru/noties/markwon/renderer/SyntaxHighlightNoOp.java
@@ -0,0 +1,12 @@
+package ru.noties.markwon.renderer;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+class SyntaxHighlightNoOp implements SyntaxHighlight {
+ @NonNull
+ @Override
+ public CharSequence highlight(@Nullable String info, @NonNull String code) {
+ return code;
+ }
+}
diff --git a/library-spans/src/main/java/ru/noties/markwon/spans/AsyncDrawable.java b/library-renderer/src/main/java/ru/noties/markwon/spans/AsyncDrawable.java
similarity index 100%
rename from library-spans/src/main/java/ru/noties/markwon/spans/AsyncDrawable.java
rename to library-renderer/src/main/java/ru/noties/markwon/spans/AsyncDrawable.java
diff --git a/library-spans/src/main/java/ru/noties/markwon/spans/AsyncDrawableSpan.java b/library-renderer/src/main/java/ru/noties/markwon/spans/AsyncDrawableSpan.java
similarity index 67%
rename from library-spans/src/main/java/ru/noties/markwon/spans/AsyncDrawableSpan.java
rename to library-renderer/src/main/java/ru/noties/markwon/spans/AsyncDrawableSpan.java
index d81da309..637c0e95 100644
--- a/library-spans/src/main/java/ru/noties/markwon/spans/AsyncDrawableSpan.java
+++ b/library-renderer/src/main/java/ru/noties/markwon/spans/AsyncDrawableSpan.java
@@ -3,7 +3,6 @@ package ru.noties.markwon.spans;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
import android.support.annotation.IntDef;
import android.support.annotation.IntRange;
import android.support.annotation.NonNull;
@@ -13,23 +12,39 @@ import android.text.style.ReplacementSpan;
@SuppressWarnings("WeakerAccess")
public class AsyncDrawableSpan extends ReplacementSpan {
- @IntDef({ ALIGN_BOTTOM, ALIGN_BASELINE, ALIGN_CENTER })
- @interface Alignment {}
+ @IntDef({ALIGN_BOTTOM, ALIGN_BASELINE, ALIGN_CENTER})
+ @interface Alignment {
+ }
public static final int ALIGN_BOTTOM = 0;
public static final int ALIGN_BASELINE = 1;
public static final int ALIGN_CENTER = 2; // will only center if drawable height is less than text line height
+ private final SpannableTheme theme;
private final AsyncDrawable drawable;
private final int alignment;
+ private final boolean replacementTextIsLink;
- public AsyncDrawableSpan(@NonNull AsyncDrawable drawable) {
- this(drawable, ALIGN_BOTTOM);
+ public AsyncDrawableSpan(@NonNull SpannableTheme theme, @NonNull AsyncDrawable drawable) {
+ this(theme, drawable, ALIGN_BOTTOM);
}
- public AsyncDrawableSpan(@NonNull AsyncDrawable drawable, @Alignment int alignment) {
+ public AsyncDrawableSpan(
+ @NonNull SpannableTheme theme,
+ @NonNull AsyncDrawable drawable,
+ @Alignment int alignment) {
+ this(theme, drawable, alignment, false);
+ }
+
+ public AsyncDrawableSpan(
+ @NonNull SpannableTheme theme,
+ @NonNull AsyncDrawable drawable,
+ @Alignment int alignment,
+ boolean replacementTextIsLink) {
+ this.theme = theme;
this.drawable = drawable;
this.alignment = alignment;
+ this.replacementTextIsLink = replacementTextIsLink;
// additionally set intrinsic bounds if empty
final Rect rect = drawable.getBounds();
@@ -66,8 +81,13 @@ public class AsyncDrawableSpan extends ReplacementSpan {
} else {
- size = (int) (paint.measureText(text, start, end) + .5F);
+ // we will apply style here in case if theme modifies textSize or style (affects metrics)
+ if (replacementTextIsLink) {
+ theme.applyLinkStyle(paint);
+ }
+ // NB, no specific text handling (no new lines, etc)
+ size = (int) (paint.measureText(text, start, end) + .5F);
}
return size;
@@ -108,7 +128,15 @@ public class AsyncDrawableSpan extends ReplacementSpan {
}
} else {
- final int textY = (int) (bottom - ((bottom - top) / 2) - ((paint.descent() + paint.ascent()) / 2.F + .5F));
+ // will it make sense to have additional background/borders for an image replacement?
+ // let's focus on main functionality and then think of it
+
+ final float textY = CanvasUtils.textCenterY(top, bottom, paint);
+ if (replacementTextIsLink) {
+ theme.applyLinkStyle(paint);
+ }
+
+ // NB, no specific text handling (no new lines, etc)
canvas.drawText(text, start, end, x, textY, paint);
}
}
diff --git a/library-spans/src/main/java/ru/noties/markwon/spans/DrawableSpanUtils.java b/library-renderer/src/main/java/ru/noties/markwon/spans/AsyncDrawableSpanUtils.java
similarity index 98%
rename from library-spans/src/main/java/ru/noties/markwon/spans/DrawableSpanUtils.java
rename to library-renderer/src/main/java/ru/noties/markwon/spans/AsyncDrawableSpanUtils.java
index b528d66b..872183e1 100644
--- a/library-spans/src/main/java/ru/noties/markwon/spans/DrawableSpanUtils.java
+++ b/library-renderer/src/main/java/ru/noties/markwon/spans/AsyncDrawableSpanUtils.java
@@ -11,7 +11,7 @@ import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
-public class DrawableSpanUtils {
+public class AsyncDrawableSpanUtils {
// todo, add `unschedule` method (to be used when new text is set, so
// drawables are removed from callbacks)
@@ -66,7 +66,7 @@ public class DrawableSpanUtils {
}
}
- private DrawableSpanUtils() {}
+ private AsyncDrawableSpanUtils() {}
private static class DrawableCallbackImpl implements Drawable.Callback {
diff --git a/library-renderer/src/main/java/ru/noties/markwon/spans/BlockQuoteSpan.java b/library-renderer/src/main/java/ru/noties/markwon/spans/BlockQuoteSpan.java
new file mode 100644
index 00000000..865f9cd2
--- /dev/null
+++ b/library-renderer/src/main/java/ru/noties/markwon/spans/BlockQuoteSpan.java
@@ -0,0 +1,51 @@
+package ru.noties.markwon.spans;
+
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.support.annotation.NonNull;
+import android.text.Layout;
+import android.text.style.LeadingMarginSpan;
+
+public class BlockQuoteSpan implements LeadingMarginSpan {
+
+ private final SpannableTheme theme;
+ private final Rect rect = ObjectsPool.rect();
+ private final Paint paint = ObjectsPool.paint();
+ private final int indent;
+
+ public BlockQuoteSpan(@NonNull SpannableTheme theme, int indent) {
+ this.theme = theme;
+ this.indent = indent;
+ }
+
+ @Override
+ public int getLeadingMargin(boolean first) {
+ return theme.getBlockMargin();
+ }
+
+ @Override
+ public void drawLeadingMargin(
+ Canvas c,
+ Paint p,
+ int x,
+ int dir,
+ int top,
+ int baseline,
+ int bottom,
+ CharSequence text,
+ int start,
+ int end,
+ boolean first,
+ Layout layout) {
+
+ final int width = theme.getBlockQuoteWidth();
+
+ theme.applyBlockQuoteStyle(paint);
+
+ final int left = theme.getBlockMargin() * (indent - 1);
+ rect.set(left, top, left + width, bottom);
+
+ c.drawRect(rect, paint);
+ }
+}
diff --git a/library-spans/src/main/java/ru/noties/markwon/spans/BulletListItemSpan.java b/library-renderer/src/main/java/ru/noties/markwon/spans/BulletListItemSpan.java
similarity index 54%
rename from library-spans/src/main/java/ru/noties/markwon/spans/BulletListItemSpan.java
rename to library-renderer/src/main/java/ru/noties/markwon/spans/BulletListItemSpan.java
index 1aa6b89a..d8058f25 100644
--- a/library-spans/src/main/java/ru/noties/markwon/spans/BulletListItemSpan.java
+++ b/library-renderer/src/main/java/ru/noties/markwon/spans/BulletListItemSpan.java
@@ -4,7 +4,6 @@ import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
-import android.support.annotation.ColorInt;
import android.support.annotation.IntRange;
import android.support.annotation.NonNull;
import android.text.Layout;
@@ -12,30 +11,7 @@ import android.text.style.LeadingMarginSpan;
public class BulletListItemSpan implements LeadingMarginSpan {
- // todo, there are 3 types of bullets: filled circle, stroke circle & filled rectangle
- // also, there are ordered lists
-
- public static class Config {
-
- final int marginWidth;
- final int bulletColor; // by default uses text color
- final int bulletSide;
- final int bulletStrokeWidth;
-
- // from 0 but it makes sense to provide something wider
- public Config(
- @IntRange(from = 0) int marginWidth,
- @ColorInt int bulletColor,
- @IntRange(from = 0) int bulletSide,
- @IntRange(from = 0) int bulletStrokeWidth) {
- this.marginWidth = marginWidth;
- this.bulletColor = bulletColor;
- this.bulletSide = bulletSide;
- this.bulletStrokeWidth = bulletStrokeWidth;
- }
- }
-
- private final Config config;
+ private SpannableTheme theme;
private final Paint paint = ObjectsPool.paint();
private final RectF circle = ObjectsPool.rectF();
@@ -46,11 +22,11 @@ public class BulletListItemSpan implements LeadingMarginSpan {
private final int start;
public BulletListItemSpan(
- @NonNull Config config,
+ @NonNull SpannableTheme theme,
@IntRange(from = 0) int blockIndent,
@IntRange(from = 0) int level,
@IntRange(from = 0) int start) {
- this.config = config;
+ this.theme = theme;
this.blockIndent = blockIndent;
this.level = level;
this.start = start;
@@ -58,7 +34,7 @@ public class BulletListItemSpan implements LeadingMarginSpan {
@Override
public int getLeadingMargin(boolean first) {
- return config.marginWidth;
+ return theme.getBlockMargin();
}
@Override
@@ -69,39 +45,17 @@ public class BulletListItemSpan implements LeadingMarginSpan {
return;
}
- final int color;
- final float stroke;
+ paint.set(p);
- if (config.bulletColor == 0) {
- color = p.getColor();
- } else {
- color = config.bulletColor;
- }
-
- if (config.bulletStrokeWidth == 0) {
- stroke = p.getStrokeWidth();
- } else {
- stroke = config.bulletStrokeWidth;
- }
-
- paint.setColor(color);
- paint.setStrokeWidth(stroke);
+ theme.applyListItemStyle(paint);
final int save = c.save();
try {
- // by default we use half of margin width, but if height is less than width, we calculate from it
- final int width = config.marginWidth;
+ final int width = theme.getBlockMargin();
final int height = bottom - top;
- final int min = Math.min(config.marginWidth, height) / 2;
- final int side;
- if (config.bulletSide == 0
- || config.bulletSide > min) {
- side = min;
- } else {
- side = config.bulletSide;
- }
+ final int side = theme.getBulletWidth(bottom - top);
final int marginLeft = (width - side) / 2;
final int marginTop = (height - side) / 2;
diff --git a/library-renderer/src/main/java/ru/noties/markwon/spans/CanvasUtils.java b/library-renderer/src/main/java/ru/noties/markwon/spans/CanvasUtils.java
new file mode 100644
index 00000000..b55783b8
--- /dev/null
+++ b/library-renderer/src/main/java/ru/noties/markwon/spans/CanvasUtils.java
@@ -0,0 +1,14 @@
+package ru.noties.markwon.spans;
+
+import android.graphics.Paint;
+import android.support.annotation.NonNull;
+
+abstract class CanvasUtils {
+
+ static float textCenterY(int top, int bottom, @NonNull Paint paint) {
+ return (int) (bottom - ((bottom - top) / 2) - ((paint.descent() + paint.ascent()) / 2.F + .5F));
+ }
+
+ private CanvasUtils() {
+ }
+}
diff --git a/library-renderer/src/main/java/ru/noties/markwon/spans/CodeSpan.java b/library-renderer/src/main/java/ru/noties/markwon/spans/CodeSpan.java
new file mode 100644
index 00000000..db4e0553
--- /dev/null
+++ b/library-renderer/src/main/java/ru/noties/markwon/spans/CodeSpan.java
@@ -0,0 +1,60 @@
+package ru.noties.markwon.spans;
+
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.support.annotation.NonNull;
+import android.text.Layout;
+import android.text.TextPaint;
+import android.text.style.LeadingMarginSpan;
+import android.text.style.MetricAffectingSpan;
+
+public class CodeSpan extends MetricAffectingSpan implements LeadingMarginSpan {
+
+ private final SpannableTheme theme;
+ private final Rect rect = ObjectsPool.rect();
+ private final Paint paint = ObjectsPool.paint();
+
+ private final boolean multiline;
+
+ public CodeSpan(@NonNull SpannableTheme theme, boolean multiline) {
+ this.theme = theme;
+ this.multiline = multiline;
+ }
+
+ @Override
+ public void updateMeasureState(TextPaint p) {
+ apply(p);
+ }
+
+ @Override
+ public void updateDrawState(TextPaint ds) {
+ apply(ds);
+ if (!multiline) {
+ ds.bgColor = theme.getCodeBackgroundColor(ds);
+ }
+ }
+
+ private void apply(TextPaint p) {
+ theme.applyCodeTextStyle(p);
+ }
+
+ @Override
+ public int getLeadingMargin(boolean first) {
+ return multiline ? theme.getCodeMultilineMargin() : 0;
+ }
+
+ @Override
+ public void drawLeadingMargin(Canvas c, Paint p, int x, int dir, int top, int baseline, int bottom, CharSequence text, int start, int end, boolean first, Layout layout) {
+
+ if (multiline) {
+
+ paint.setStyle(Paint.Style.FILL);
+ paint.setColor(theme.getCodeBackgroundColor(p));
+
+ rect.set(x, top, c.getWidth(), bottom);
+
+ c.drawRect(rect, paint);
+ }
+ }
+}
diff --git a/library-spans/src/main/java/ru/noties/markwon/spans/ColorUtils.java b/library-renderer/src/main/java/ru/noties/markwon/spans/ColorUtils.java
similarity index 86%
rename from library-spans/src/main/java/ru/noties/markwon/spans/ColorUtils.java
rename to library-renderer/src/main/java/ru/noties/markwon/spans/ColorUtils.java
index c59b01fd..4739d531 100644
--- a/library-spans/src/main/java/ru/noties/markwon/spans/ColorUtils.java
+++ b/library-renderer/src/main/java/ru/noties/markwon/spans/ColorUtils.java
@@ -1,6 +1,6 @@
package ru.noties.markwon.spans;
-class ColorUtils {
+abstract class ColorUtils {
static int applyAlpha(int color, int alpha) {
return (color & 0x00FFFFFF) | (alpha << 24);
diff --git a/library-spans/src/main/java/ru/noties/markwon/spans/EmphasisSpan.java b/library-renderer/src/main/java/ru/noties/markwon/spans/EmphasisSpan.java
similarity index 100%
rename from library-spans/src/main/java/ru/noties/markwon/spans/EmphasisSpan.java
rename to library-renderer/src/main/java/ru/noties/markwon/spans/EmphasisSpan.java
diff --git a/library-renderer/src/main/java/ru/noties/markwon/spans/HeadingSpan.java b/library-renderer/src/main/java/ru/noties/markwon/spans/HeadingSpan.java
new file mode 100644
index 00000000..7ec9c10a
--- /dev/null
+++ b/library-renderer/src/main/java/ru/noties/markwon/spans/HeadingSpan.java
@@ -0,0 +1,67 @@
+package ru.noties.markwon.spans;
+
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.support.annotation.IntRange;
+import android.support.annotation.NonNull;
+import android.text.Layout;
+import android.text.TextPaint;
+import android.text.style.LeadingMarginSpan;
+import android.text.style.MetricAffectingSpan;
+
+public class HeadingSpan extends MetricAffectingSpan implements LeadingMarginSpan {
+
+ private final SpannableTheme theme;
+ private final Rect rect = ObjectsPool.rect();
+ private final Paint paint = ObjectsPool.paint();
+ private final int level;
+ private final int end;
+
+ public HeadingSpan(@NonNull SpannableTheme theme, @IntRange(from = 1, to = 6) int level, @IntRange(from = 0) int end) {
+ this.theme = theme;
+ this.level = level;
+ this.end = end;
+ }
+
+ @Override
+ public void updateMeasureState(TextPaint p) {
+ apply(p);
+ }
+
+ @Override
+ public void updateDrawState(TextPaint tp) {
+ apply(tp);
+ }
+
+ private void apply(TextPaint paint) {
+ theme.applyHeadingTextStyle(paint, level);
+ }
+
+ @Override
+ public int getLeadingMargin(boolean first) {
+ // no margin actually, but we need to access Canvas to draw break
+ return 0;
+ }
+
+ @Override
+ public void drawLeadingMargin(Canvas c, Paint p, int x, int dir, int top, int baseline, int bottom, CharSequence text, int start, int end, boolean first, Layout layout) {
+
+ if (level == 1
+ || level == 2) {
+
+ if (this.end == end) {
+
+ paint.set(p);
+
+ theme.applyHeadingBreakStyle(paint);
+
+ final float height = paint.getStrokeWidth();
+ final int b = (int) (bottom - height + .5F);
+
+ rect.set(x, b, c.getWidth(), bottom);
+ c.drawRect(rect, paint);
+ }
+ }
+ }
+}
diff --git a/library-renderer/src/main/java/ru/noties/markwon/spans/LinkSpan.java b/library-renderer/src/main/java/ru/noties/markwon/spans/LinkSpan.java
new file mode 100644
index 00000000..b96f4681
--- /dev/null
+++ b/library-renderer/src/main/java/ru/noties/markwon/spans/LinkSpan.java
@@ -0,0 +1,33 @@
+package ru.noties.markwon.spans;
+
+import android.support.annotation.NonNull;
+import android.text.TextPaint;
+import android.text.style.ClickableSpan;
+import android.view.View;
+
+public class LinkSpan extends ClickableSpan {
+
+ public interface Resolver {
+ void resolve(View view, @NonNull String link);
+ }
+
+ private final SpannableTheme theme;
+ private final String link;
+ private final Resolver resolver;
+
+ public LinkSpan(@NonNull SpannableTheme theme, @NonNull String link, @NonNull Resolver resolver) {
+ this.theme = theme;
+ this.link = link;
+ this.resolver = resolver;
+ }
+
+ @Override
+ public void onClick(View widget) {
+ resolver.resolve(widget, link);
+ }
+
+ @Override
+ public void updateDrawState(TextPaint ds) {
+ theme.applyLinkStyle(ds);
+ }
+}
diff --git a/library-spans/src/main/java/ru/noties/markwon/spans/ObjectsPool.java b/library-renderer/src/main/java/ru/noties/markwon/spans/ObjectsPool.java
similarity index 100%
rename from library-spans/src/main/java/ru/noties/markwon/spans/ObjectsPool.java
rename to library-renderer/src/main/java/ru/noties/markwon/spans/ObjectsPool.java
diff --git a/library-spans/src/main/java/ru/noties/markwon/spans/OrderedListItemSpan.java b/library-renderer/src/main/java/ru/noties/markwon/spans/OrderedListItemSpan.java
similarity index 62%
rename from library-spans/src/main/java/ru/noties/markwon/spans/OrderedListItemSpan.java
rename to library-renderer/src/main/java/ru/noties/markwon/spans/OrderedListItemSpan.java
index 4d1e0451..0cbd1fac 100644
--- a/library-spans/src/main/java/ru/noties/markwon/spans/OrderedListItemSpan.java
+++ b/library-renderer/src/main/java/ru/noties/markwon/spans/OrderedListItemSpan.java
@@ -2,7 +2,6 @@ package ru.noties.markwon.spans;
import android.graphics.Canvas;
import android.graphics.Paint;
-import android.support.annotation.ColorInt;
import android.support.annotation.IntRange;
import android.support.annotation.NonNull;
import android.text.Layout;
@@ -10,29 +9,18 @@ import android.text.style.LeadingMarginSpan;
public class OrderedListItemSpan implements LeadingMarginSpan {
- public static class Config {
-
- final int marginWidth; // by default 0
- final int numberColor; // by default color of the main text
-
- public Config(@IntRange(from = 0) int marginWidth, @ColorInt int numberColor) {
- this.marginWidth = marginWidth;
- this.numberColor = numberColor;
- }
- }
-
- private final Config config;
+ private final SpannableTheme theme;
private final String number;
private final int blockIndent;
private final int start;
public OrderedListItemSpan(
- @NonNull Config config,
+ @NonNull SpannableTheme theme,
@NonNull String number,
@IntRange(from = 0) int blockIndent,
@IntRange(from = 0) int start
) {
- this.config = config;
+ this.theme = theme;
this.number = number;
this.blockIndent = blockIndent;
this.start = start;
@@ -40,7 +28,7 @@ public class OrderedListItemSpan implements LeadingMarginSpan {
@Override
public int getLeadingMargin(boolean first) {
- return config.marginWidth;
+ return theme.getBlockMargin();
}
@Override
@@ -51,15 +39,13 @@ public class OrderedListItemSpan implements LeadingMarginSpan {
return;
}
- if (config.numberColor != 0) {
- p.setColor(config.numberColor);
- }
+ theme.applyListItemStyle(p);
- final int width = config.marginWidth;
+ final int width = theme.getBlockMargin();
final int numberWidth = (int) (p.measureText(number) + .5F);
final int numberX = (width * blockIndent) - numberWidth;
- final int numberY = bottom - ((bottom - top) / 2) - (int) ((p.descent() + p.ascent()) / 2);
+ final float numberY = CanvasUtils.textCenterY(top, bottom, p);
c.drawText(number, numberX, numberY, p);
}
diff --git a/library-renderer/src/main/java/ru/noties/markwon/spans/SpannableTheme.java b/library-renderer/src/main/java/ru/noties/markwon/spans/SpannableTheme.java
new file mode 100644
index 00000000..c25878ce
--- /dev/null
+++ b/library-renderer/src/main/java/ru/noties/markwon/spans/SpannableTheme.java
@@ -0,0 +1,456 @@
+package ru.noties.markwon.spans;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Paint;
+import android.graphics.Typeface;
+import android.support.annotation.AttrRes;
+import android.support.annotation.IntRange;
+import android.support.annotation.NonNull;
+import android.text.TextPaint;
+import android.util.TypedValue;
+import android.widget.TextView;
+
+@SuppressWarnings("WeakerAccess")
+public class SpannableTheme {
+
+ // this method should be used if TextView is known beforehand
+ // it will correctly measure the `space` char and set it as `codeMultilineMargin`
+ // otherwise this value must be set explicitly (
+ public static SpannableTheme create(@NonNull TextView textView) {
+ return builderWithDefaults(textView.getContext())
+ .codeMultilineMargin((int) (textView.getPaint().measureText("\u00a0") + .5F))
+ .build();
+ }
+
+ // this create default theme (except for `codeMultilineMargin` property)
+ public static SpannableTheme create(@NonNull Context context) {
+ return builderWithDefaults(context).build();
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static Builder builder(@NonNull SpannableTheme copyFrom) {
+ return new Builder(copyFrom);
+ }
+
+ public static Builder builderWithDefaults(@NonNull Context context) {
+ final Px px = new Px(context);
+ return new Builder()
+ .linkColor(resolve(context, android.R.attr.textColorLink))
+ .codeMultilineMargin(px.px(8))
+ .blockMargin(px.px(24))
+ .bulletListItemStrokeWidth(px.px(1))
+ .headingBreakHeight(px.px(1))
+ .thematicBreakHeight(px.px(2));
+ }
+
+ private static int resolve(Context context, @AttrRes int attr) {
+ final TypedValue typedValue = new TypedValue();
+ final int attrs[] = new int[]{attr};
+ final TypedArray typedArray = context.obtainStyledAttributes(typedValue.data, attrs);
+ try {
+ return typedArray.getColor(0, 0);
+ } finally {
+ typedArray.recycle();
+ }
+ }
+
+ protected static final int BLOCK_QUOTE_DEF_COLOR_ALPHA = 50;
+
+ protected static final int CODE_DEF_BACKGROUND_COLOR_ALPHA = 25;
+ protected static final float CODE_DEF_TEXT_SIZE_RATIO = .87F;
+
+ protected static final int HEADING_DEF_BREAK_COLOR_ALPHA = 75;
+
+ // taken from html spec (most browsers render headings like that)
+ // is not exposed via protected modifier in order to disallow modification
+ private static final float[] HEADING_SIZES = {
+ 2.F, 1.5F, 1.17F, 1.F, .83F, .67F,
+ };
+
+ protected static final float SCRIPT_DEF_TEXT_SIZE_RATIO = .75F;
+
+ protected static final int THEMATIC_BREAK_DEF_ALPHA = 75;
+
+ protected final int linkColor;
+
+ // used in quote, lists
+ protected final int blockMargin;
+
+ // by default it's 1/4th of `blockMargin`
+ protected final int blockQuoteWidth;
+
+ // by default it's text color with `BLOCK_QUOTE_DEF_COLOR_ALPHA` applied alpha
+ protected final int blockQuoteColor;
+
+ // by default uses text color (applied for un-ordered lists & ordered (bullets & numbers)
+ protected final int listItemColor;
+
+ // by default the stroke color of a paint object
+ protected final int bulletListItemStrokeWidth;
+
+ // width of bullet, by default min(blockMargin, height) / 2
+ protected final int bulletWidth;
+
+ // by default - main text color
+ protected final int codeTextColor;
+
+ // by default 0.1 alpha of textColor/codeTextColor
+ protected final int codeBackgroundColor;
+
+ // by default `width` of a space char... it's fun and games, but span doesn't have access to paint in `getLeadingMargin`
+ // so, we need to set this value explicitly (think of an utility method, that takes TextView/TextPaint and measures space char)
+ protected final int codeMultilineMargin;
+
+ // by default Typeface.MONOSPACE
+ protected final Typeface codeTypeface;
+
+ // by default a bit (how much?!) smaller than normal text
+ // applied ONLY if default typeface was used, otherwise, not applied
+ protected final int codeTextSize;
+
+ // by default paint.getStrokeWidth
+ protected final int headingBreakHeight;
+
+ // by default, text color with `HEADING_DEF_BREAK_COLOR_ALPHA` applied alpha
+ protected final int headingBreakColor;
+
+ // by default `SCRIPT_DEF_TEXT_SIZE_RATIO`
+ protected final float scriptTextSizeRatio;
+
+ // by default textColor with `THEMATIC_BREAK_DEF_ALPHA` applied alpha
+ protected final int thematicBreakColor;
+
+ // by default paint.strokeWidth
+ protected final int thematicBreakHeight;
+
+ protected SpannableTheme(@NonNull Builder builder) {
+ this.linkColor = builder.linkColor;
+ this.blockMargin = builder.blockMargin;
+ this.blockQuoteWidth = builder.blockQuoteWidth;
+ this.blockQuoteColor = builder.blockQuoteColor;
+ this.listItemColor = builder.listItemColor;
+ this.bulletListItemStrokeWidth = builder.bulletListItemStrokeWidth;
+ this.bulletWidth = builder.bulletWidth;
+ this.codeTextColor = builder.codeTextColor;
+ this.codeBackgroundColor = builder.codeBackgroundColor;
+ this.codeMultilineMargin = builder.codeMultilineMargin;
+ this.codeTypeface = builder.codeTypeface;
+ this.codeTextSize = builder.codeTextSize;
+ this.headingBreakHeight = builder.headingBreakHeight;
+ this.headingBreakColor = builder.headingBreakColor;
+ this.scriptTextSizeRatio = builder.scriptTextSizeRatio;
+ this.thematicBreakColor = builder.thematicBreakColor;
+ this.thematicBreakHeight = builder.thematicBreakHeight;
+ }
+
+
+ public void applyLinkStyle(@NonNull Paint paint) {
+ paint.setUnderlineText(true);
+ if (linkColor != 0) {
+ // by default we will be using text color
+ paint.setColor(linkColor);
+ }
+ }
+
+ public void applyBlockQuoteStyle(@NonNull Paint paint) {
+ final int color;
+ if (blockQuoteColor == 0) {
+ color = ColorUtils.applyAlpha(paint.getColor(), BLOCK_QUOTE_DEF_COLOR_ALPHA);
+ } else {
+ color = blockQuoteColor;
+ }
+ paint.setStyle(Paint.Style.FILL);
+ paint.setColor(color);
+ }
+
+ public int getBlockMargin() {
+ return blockMargin;
+ }
+
+ public int getBlockQuoteWidth() {
+ final int out;
+ if (blockQuoteWidth == 0) {
+ out = (int) (blockMargin * .25F + .5F);
+ } else {
+ out = blockQuoteWidth;
+ }
+ return out;
+ }
+
+ public void applyListItemStyle(@NonNull Paint paint) {
+
+ final int color;
+ if (listItemColor != 0) {
+ color = listItemColor;
+ } else {
+ color = paint.getColor();
+ }
+ paint.setColor(color);
+
+ if (bulletListItemStrokeWidth != 0) {
+ paint.setStrokeWidth(bulletListItemStrokeWidth);
+ }
+ }
+
+ public int getBulletWidth(int height) {
+
+ final int min = Math.min(blockMargin, height) / 2;
+
+ final int width;
+ if (bulletWidth == 0
+ || bulletWidth > min) {
+ width = min;
+ } else {
+ width = bulletWidth;
+ }
+
+ return width;
+ }
+
+ public void applyCodeTextStyle(@NonNull Paint paint) {
+
+ if (codeTextColor != 0) {
+ paint.setColor(codeTextColor);
+ }
+
+ // custom typeface was set
+ if (codeTypeface != null) {
+ paint.setTypeface(codeTypeface);
+ if (codeTextSize != 0) {
+ paint.setTextSize(codeTextSize);
+ }
+ } else {
+ paint.setTypeface(Typeface.MONOSPACE);
+ final float textSize;
+ if (codeTextSize != 0) {
+ textSize = codeTextSize;
+ } else {
+ textSize = paint.getTextSize() * CODE_DEF_TEXT_SIZE_RATIO;
+ }
+ paint.setTextSize(textSize);
+ }
+ }
+
+ public int getCodeMultilineMargin() {
+ return codeMultilineMargin;
+ }
+
+ public int getCodeBackgroundColor(@NonNull Paint paint) {
+ final int color;
+ if (codeBackgroundColor != 0) {
+ color = codeBackgroundColor;
+ } else {
+ color = ColorUtils.applyAlpha(paint.getColor(), CODE_DEF_BACKGROUND_COLOR_ALPHA);
+ }
+ return color;
+ }
+
+ public void applyHeadingTextStyle(@NonNull Paint paint, @IntRange(from = 1, to = 6) int level) {
+ paint.setFakeBoldText(true);
+ paint.setTextSize(paint.getTextSize() * HEADING_SIZES[level - 1]);
+ }
+
+ public void applyHeadingBreakStyle(@NonNull Paint paint) {
+ final int color;
+ if (headingBreakColor != 0) {
+ color = headingBreakColor;
+ } else {
+ color = ColorUtils.applyAlpha(paint.getColor(), HEADING_DEF_BREAK_COLOR_ALPHA);
+ }
+ paint.setColor(color);
+ paint.setStyle(Paint.Style.FILL);
+ if (headingBreakHeight != 0) {
+ //noinspection SuspiciousNameCombination
+ paint.setStrokeWidth(headingBreakHeight);
+ }
+ }
+
+ public void applySuperScriptStyle(@NonNull TextPaint paint) {
+ final float ratio;
+ if (Float.compare(scriptTextSizeRatio, .0F) == 0) {
+ ratio = SCRIPT_DEF_TEXT_SIZE_RATIO;
+ } else {
+ ratio = scriptTextSizeRatio;
+ }
+ paint.setTextSize(paint.getTextSize() * ratio);
+ paint.baselineShift += (int) (paint.ascent() / 2);
+ }
+
+ public void applySubScriptStyle(@NonNull TextPaint paint) {
+ final float ratio;
+ if (Float.compare(scriptTextSizeRatio, .0F) == 0) {
+ ratio = SCRIPT_DEF_TEXT_SIZE_RATIO;
+ } else {
+ ratio = scriptTextSizeRatio;
+ }
+ paint.setTextSize(paint.getTextSize() * ratio);
+ paint.baselineShift -= (int) (paint.ascent() / 2);
+ }
+
+ public void applyThematicBreakStyle(@NonNull Paint paint) {
+ final int color;
+ if (thematicBreakColor != 0) {
+ color = thematicBreakColor;
+ } else {
+ color = ColorUtils.applyAlpha(paint.getColor(), THEMATIC_BREAK_DEF_ALPHA);
+ }
+ paint.setColor(color);
+ paint.setStyle(Paint.Style.FILL);
+
+ if (thematicBreakHeight != 0) {
+ //noinspection SuspiciousNameCombination
+ paint.setStrokeWidth(thematicBreakHeight);
+ }
+ }
+
+ public static class Builder {
+
+ private int linkColor;
+ private int blockMargin;
+ private int blockQuoteWidth;
+ private int blockQuoteColor;
+ private int listItemColor;
+ private int bulletListItemStrokeWidth;
+ private int bulletWidth;
+ private int codeTextColor;
+ private int codeBackgroundColor;
+ private int codeMultilineMargin;
+ private Typeface codeTypeface;
+ private int codeTextSize;
+ private int headingBreakHeight;
+ private int headingBreakColor;
+ private float scriptTextSizeRatio;
+ private int thematicBreakColor;
+ private int thematicBreakHeight;
+
+ Builder() {
+
+ }
+
+ Builder(@NonNull SpannableTheme theme) {
+
+ this.linkColor = theme.linkColor;
+ this.blockMargin = theme.blockMargin;
+ this.blockQuoteWidth = theme.blockQuoteWidth;
+ this.blockQuoteColor = theme.blockQuoteColor;
+ this.listItemColor = theme.listItemColor;
+ this.bulletListItemStrokeWidth = theme.bulletListItemStrokeWidth;
+ this.bulletWidth = theme.bulletWidth;
+ this.codeTextColor = theme.codeTextColor;
+ this.codeBackgroundColor = theme.codeBackgroundColor;
+ this.codeMultilineMargin = theme.codeMultilineMargin;
+ this.codeTypeface = theme.codeTypeface;
+ this.codeTextSize = theme.codeTextSize;
+ this.headingBreakHeight = theme.headingBreakHeight;
+ this.headingBreakColor = theme.headingBreakColor;
+ this.scriptTextSizeRatio = theme.scriptTextSizeRatio;
+ this.thematicBreakColor = theme.thematicBreakColor;
+ this.thematicBreakHeight = theme.thematicBreakHeight;
+ }
+
+ public Builder linkColor(int linkColor) {
+ this.linkColor = linkColor;
+ return this;
+ }
+
+ public Builder blockMargin(int blockMargin) {
+ this.blockMargin = blockMargin;
+ return this;
+ }
+
+ public Builder blockQuoteWidth(int blockQuoteWidth) {
+ this.blockQuoteWidth = blockQuoteWidth;
+ return this;
+ }
+
+ public Builder blockQuoteColor(int blockQuoteColor) {
+ this.blockQuoteColor = blockQuoteColor;
+ return this;
+ }
+
+ public Builder listItemColor(int listItemColor) {
+ this.listItemColor = listItemColor;
+ return this;
+ }
+
+ public Builder bulletListItemStrokeWidth(int bulletListItemStrokeWidth) {
+ this.bulletListItemStrokeWidth = bulletListItemStrokeWidth;
+ return this;
+ }
+
+ public Builder bulletWidth(int bulletWidth) {
+ this.bulletWidth = bulletWidth;
+ return this;
+ }
+
+ public Builder codeTextColor(int codeTextColor) {
+ this.codeTextColor = codeTextColor;
+ return this;
+ }
+
+ public Builder codeBackgroundColor(int codeBackgroundColor) {
+ this.codeBackgroundColor = codeBackgroundColor;
+ return this;
+ }
+
+ public Builder codeMultilineMargin(int codeMultilineMargin) {
+ this.codeMultilineMargin = codeMultilineMargin;
+ return this;
+ }
+
+ public Builder codeTypeface(Typeface codeTypeface) {
+ this.codeTypeface = codeTypeface;
+ return this;
+ }
+
+ public Builder codeTextSize(int codeTextSize) {
+ this.codeTextSize = codeTextSize;
+ return this;
+ }
+
+ public Builder headingBreakHeight(int headingBreakHeight) {
+ this.headingBreakHeight = headingBreakHeight;
+ return this;
+ }
+
+ public Builder headingBreakColor(int headingBreakColor) {
+ this.headingBreakColor = headingBreakColor;
+ return this;
+ }
+
+ public Builder scriptTextSizeRatio(float scriptTextSizeRatio) {
+ this.scriptTextSizeRatio = scriptTextSizeRatio;
+ return this;
+ }
+
+ public Builder thematicBreakColor(int thematicBreakColor) {
+ this.thematicBreakColor = thematicBreakColor;
+ return this;
+ }
+
+ public Builder thematicBreakHeight(int thematicBreakHeight) {
+ this.thematicBreakHeight = thematicBreakHeight;
+ return this;
+ }
+
+ public SpannableTheme build() {
+ return new SpannableTheme(this);
+ }
+ }
+
+ private static class Px {
+ private final float density;
+
+ Px(@NonNull Context context) {
+ this.density = context.getResources().getDisplayMetrics().density;
+ }
+
+ int px(int dp) {
+ return (int) (dp * density + .5F);
+ }
+ }
+}
diff --git a/library-spans/src/main/java/ru/noties/markwon/spans/StrongEmphasisSpan.java b/library-renderer/src/main/java/ru/noties/markwon/spans/StrongEmphasisSpan.java
similarity index 100%
rename from library-spans/src/main/java/ru/noties/markwon/spans/StrongEmphasisSpan.java
rename to library-renderer/src/main/java/ru/noties/markwon/spans/StrongEmphasisSpan.java
diff --git a/library-renderer/src/main/java/ru/noties/markwon/spans/SubScriptSpan.java b/library-renderer/src/main/java/ru/noties/markwon/spans/SubScriptSpan.java
new file mode 100644
index 00000000..4386613d
--- /dev/null
+++ b/library-renderer/src/main/java/ru/noties/markwon/spans/SubScriptSpan.java
@@ -0,0 +1,28 @@
+package ru.noties.markwon.spans;
+
+import android.support.annotation.NonNull;
+import android.text.TextPaint;
+import android.text.style.MetricAffectingSpan;
+
+public class SubScriptSpan extends MetricAffectingSpan {
+
+ private final SpannableTheme theme;
+
+ public SubScriptSpan(@NonNull SpannableTheme theme) {
+ this.theme = theme;
+ }
+
+ @Override
+ public void updateDrawState(TextPaint tp) {
+ apply(tp);
+ }
+
+ @Override
+ public void updateMeasureState(TextPaint tp) {
+ apply(tp);
+ }
+
+ private void apply(TextPaint paint) {
+ theme.applySubScriptStyle(paint);
+ }
+}
diff --git a/library-renderer/src/main/java/ru/noties/markwon/spans/SuperScriptSpan.java b/library-renderer/src/main/java/ru/noties/markwon/spans/SuperScriptSpan.java
new file mode 100644
index 00000000..4b8151ec
--- /dev/null
+++ b/library-renderer/src/main/java/ru/noties/markwon/spans/SuperScriptSpan.java
@@ -0,0 +1,28 @@
+package ru.noties.markwon.spans;
+
+import android.support.annotation.NonNull;
+import android.text.TextPaint;
+import android.text.style.MetricAffectingSpan;
+
+public class SuperScriptSpan extends MetricAffectingSpan {
+
+ private final SpannableTheme theme;
+
+ public SuperScriptSpan(@NonNull SpannableTheme theme) {
+ this.theme = theme;
+ }
+
+ @Override
+ public void updateDrawState(TextPaint tp) {
+ apply(tp);
+ }
+
+ @Override
+ public void updateMeasureState(TextPaint tp) {
+ apply(tp);
+ }
+
+ private void apply(TextPaint paint) {
+ theme.applySuperScriptStyle(paint);
+ }
+}
diff --git a/library-renderer/src/main/java/ru/noties/markwon/spans/ThematicBreakSpan.java b/library-renderer/src/main/java/ru/noties/markwon/spans/ThematicBreakSpan.java
new file mode 100644
index 00000000..1c5355af
--- /dev/null
+++ b/library-renderer/src/main/java/ru/noties/markwon/spans/ThematicBreakSpan.java
@@ -0,0 +1,39 @@
+package ru.noties.markwon.spans;
+
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.support.annotation.NonNull;
+import android.text.Layout;
+import android.text.style.LeadingMarginSpan;
+
+public class ThematicBreakSpan implements LeadingMarginSpan {
+
+ private final SpannableTheme theme;
+ private final Rect rect = ObjectsPool.rect();
+ private final Paint paint = ObjectsPool.paint();
+
+ public ThematicBreakSpan(@NonNull SpannableTheme theme) {
+ this.theme = theme;
+ }
+
+ @Override
+ public int getLeadingMargin(boolean first) {
+ return 0;
+ }
+
+ @Override
+ public void drawLeadingMargin(Canvas c, Paint p, int x, int dir, int top, int baseline, int bottom, CharSequence text, int start, int end, boolean first, Layout layout) {
+
+ final int middle = top + ((bottom - top) / 2);
+
+ paint.set(p);
+ theme.applyThematicBreakStyle(paint);
+
+ final int height = (int) (paint.getStrokeWidth() + .5F);
+ final int halfHeight = (int) (height / 2.F + .5F);
+
+ rect.set(x, middle - halfHeight, c.getWidth(), middle + halfHeight);
+ c.drawRect(rect, paint);
+ }
+}
diff --git a/library-spans/build.gradle b/library-spans/build.gradle
deleted file mode 100644
index c07ebc94..00000000
--- a/library-spans/build.gradle
+++ /dev/null
@@ -1,18 +0,0 @@
-apply plugin: 'com.android.library'
-
-android {
-
- compileSdkVersion TARGET_SDK
- buildToolsVersion BUILD_TOOLS
-
- defaultConfig {
- minSdkVersion MIN_SDK
- targetSdkVersion TARGET_SDK
- versionCode 1
- versionName version
- }
-}
-
-dependencies {
- compile SUPPORT_ANNOTATIONS
-}
diff --git a/library-spans/src/main/AndroidManifest.xml b/library-spans/src/main/AndroidManifest.xml
deleted file mode 100644
index 84de88b7..00000000
--- a/library-spans/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/library-spans/src/main/java/ru/noties/markwon/spans/BlockQuoteSpan.java b/library-spans/src/main/java/ru/noties/markwon/spans/BlockQuoteSpan.java
deleted file mode 100644
index 81a82b59..00000000
--- a/library-spans/src/main/java/ru/noties/markwon/spans/BlockQuoteSpan.java
+++ /dev/null
@@ -1,84 +0,0 @@
-package ru.noties.markwon.spans;
-
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.support.annotation.ColorInt;
-import android.support.annotation.IntRange;
-import android.support.annotation.NonNull;
-import android.text.Layout;
-import android.text.style.LeadingMarginSpan;
-
-public class BlockQuoteSpan implements LeadingMarginSpan {
-
- private static final int DEF_COLOR_ALPHA = 50;
-
- @SuppressWarnings("WeakerAccess")
- public static class Config {
-
- final int totalWidth;
- final int quoteWidth; // by default 1/4 of width
- final int quoteColor; // by default textColor with 0.2 alpha
-
- public Config(
- @IntRange(from = 1) int totalWidth,
- @IntRange(from = 0) int quoteWidth,
- @ColorInt int quoteColor) {
- this.totalWidth = totalWidth;
- this.quoteWidth = quoteWidth;
- this.quoteColor = quoteColor;
- }
- }
-
- private final Config config;
- private final Rect rect = ObjectsPool.rect();
- private final Paint paint = ObjectsPool.paint();
- private final int indent;
-
- public BlockQuoteSpan(@NonNull Config config, int indent) {
- this.config = config;
- this.indent = indent;
- }
-
- @Override
- public int getLeadingMargin(boolean first) {
- return config.totalWidth;
- }
-
- @Override
- public void drawLeadingMargin(
- Canvas c,
- Paint p,
- int x,
- int dir,
- int top,
- int baseline,
- int bottom,
- CharSequence text,
- int start,
- int end,
- boolean first,
- Layout layout) {
-
- final int width;
- if (config.quoteWidth == 0) {
- width = (int) (config.totalWidth / 4.F + .5F);
- } else {
- width = config.quoteWidth;
- }
-
- final int color;
- if (config.quoteColor != 0) {
- color = config.quoteColor;
- } else {
- color = ColorUtils.applyAlpha(p.getColor(), DEF_COLOR_ALPHA);
- }
- paint.setStyle(Paint.Style.FILL);
- paint.setColor(color);
-
- final int left = config.totalWidth * (indent - 1);
- rect.set(left, top, left + width, bottom);
-
- c.drawRect(rect, paint);
- }
-}
diff --git a/library-spans/src/main/java/ru/noties/markwon/spans/CodeSpan.java b/library-spans/src/main/java/ru/noties/markwon/spans/CodeSpan.java
deleted file mode 100644
index 7bb29632..00000000
--- a/library-spans/src/main/java/ru/noties/markwon/spans/CodeSpan.java
+++ /dev/null
@@ -1,146 +0,0 @@
-package ru.noties.markwon.spans;
-
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.graphics.Typeface;
-import android.support.annotation.ColorInt;
-import android.support.annotation.IntRange;
-import android.support.annotation.NonNull;
-import android.text.Layout;
-import android.text.TextPaint;
-import android.text.style.LeadingMarginSpan;
-import android.text.style.MetricAffectingSpan;
-
-public class CodeSpan extends MetricAffectingSpan implements LeadingMarginSpan {
-
- private static final int DEF_COLOR_ALPHA = 25;
-
- @SuppressWarnings("WeakerAccess")
- public static class Config {
-
- public static Builder builder() {
- return new Builder();
- }
-
- final int textColor; // by default the same as main text
- final int backgroundColor; // by default textColor with 0.1 alpha
- final int multilineMargin; // by default 0
- final int textSize; // by default the same as main text
- final Typeface typeface; // by default Typeface.MONOSPACE
-
- private Config(Builder builder) {
- this.textColor = builder.textColor;
- this.backgroundColor = builder.backgroundColor;
- this.multilineMargin = builder.multilineMargin;
- this.textSize = builder.textSize;
- this.typeface = builder.typeface;
- }
-
- public static class Builder {
-
- int textColor;
- int backgroundColor;
- int multilineMargin;
- int textSize;
- Typeface typeface;
-
- public Builder setTextColor(@ColorInt int textColor) {
- this.textColor = textColor;
- return this;
- }
-
- public Builder setBackgroundColor(@ColorInt int backgroundColor) {
- this.backgroundColor = backgroundColor;
- return this;
- }
-
- public Builder setMultilineMargin(int multilineMargin) {
- this.multilineMargin = multilineMargin;
- return this;
- }
-
- public Builder setTextSize(@IntRange(from = 0) int textSize) {
- this.textSize = textSize;
- return this;
- }
-
- public Builder setTypeface(@NonNull Typeface typeface) {
- this.typeface = typeface;
- return this;
- }
-
- public Config build() {
- if (typeface == null) {
- typeface = Typeface.MONOSPACE;
- }
- return new Config(this);
- }
- }
- }
-
- private final Config config;
- private final Rect rect = ObjectsPool.rect();
- private final Paint paint = ObjectsPool.paint();
-
- private final boolean multiline;
-
- public CodeSpan(@NonNull Config config, boolean multiline) {
- this.config = config;
- this.multiline = multiline;
- }
-
- @Override
- public void updateMeasureState(TextPaint p) {
- apply(p);
- }
-
- @Override
- public void updateDrawState(TextPaint ds) {
- apply(ds);
- if (!multiline) {
- final int color;
- if (config.backgroundColor == 0) {
- color = ColorUtils.applyAlpha(ds.getColor(), DEF_COLOR_ALPHA);
- } else {
- color = config.backgroundColor;
- }
- ds.bgColor = color;
- }
- }
-
- private void apply(TextPaint p) {
- p.setTypeface(config.typeface);
- if (config.textSize > 0) {
- p.setTextSize(config.textSize);
- }
- if (config.textColor != 0) {
- p.setColor(config.textColor);
- }
- }
-
- @Override
- public int getLeadingMargin(boolean first) {
- return multiline ? config.multilineMargin : 0;
- }
-
- @Override
- public void drawLeadingMargin(Canvas c, Paint p, int x, int dir, int top, int baseline, int bottom, CharSequence text, int start, int end, boolean first, Layout layout) {
-
- if (multiline) {
-
- final int color;
- if (config.backgroundColor == 0) {
- color = ColorUtils.applyAlpha(p.getColor(), DEF_COLOR_ALPHA);
- } else {
- color = config.backgroundColor;
- }
- paint.setStyle(Paint.Style.FILL);
- paint.setColor(color);
-
- rect.set(x, top, c.getWidth(), bottom);
-
- c.drawRect(rect, paint);
- }
- }
-}
diff --git a/library-spans/src/main/java/ru/noties/markwon/spans/HeadingSpan.java b/library-spans/src/main/java/ru/noties/markwon/spans/HeadingSpan.java
deleted file mode 100644
index c0675d8f..00000000
--- a/library-spans/src/main/java/ru/noties/markwon/spans/HeadingSpan.java
+++ /dev/null
@@ -1,97 +0,0 @@
-package ru.noties.markwon.spans;
-
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.support.annotation.ColorInt;
-import android.support.annotation.IntRange;
-import android.support.annotation.NonNull;
-import android.text.Layout;
-import android.text.TextPaint;
-import android.text.style.LeadingMarginSpan;
-import android.text.style.MetricAffectingSpan;
-
-public class HeadingSpan extends MetricAffectingSpan implements LeadingMarginSpan {
-
- // taken from html spec (most browsers render headings like that)
- private static final float[] HEADING_SIZES = {
- 2.F, 1.5F, 1.17F, 1.F, .83F, .67F,
- };
-
- private static final int DEF_BREAK_COLOR_ALPHA = 127;
-
- public static class Config {
-
- final int breakHeight; // by default stroke width
- final int breakColor; // by default -> textColor with 0.5 alpha
-
- public Config(@IntRange(from = 0) int breakHeight, @ColorInt int breakColor) {
- this.breakHeight = breakHeight;
- this.breakColor = breakColor;
- }
- }
-
- private final Config config;
- private final Rect rect = ObjectsPool.rect();
- private final Paint paint = ObjectsPool.paint();
- private final int level;
- private final int end;
-
- public HeadingSpan(@NonNull Config config, @IntRange(from = 1, to = 6) int level, @IntRange(from = 0) int end) {
- this.config = config;
- this.level = level - 1;
- this.end = end;
- }
-
- @Override
- public void updateMeasureState(TextPaint p) {
- apply(p);
- }
-
- @Override
- public void updateDrawState(TextPaint tp) {
- apply(tp);
- }
-
- private void apply(TextPaint paint) {
- paint.setTextSize(paint.getTextSize() * HEADING_SIZES[level]);
- paint.setFakeBoldText(true);
- }
-
- @Override
- public int getLeadingMargin(boolean first) {
- // no margin actually, but we need to access Canvas to draw break
- return 0;
- }
-
- @Override
- public void drawLeadingMargin(Canvas c, Paint p, int x, int dir, int top, int baseline, int bottom, CharSequence text, int start, int end, boolean first, Layout layout) {
-
- // if we are configured to draw underlines, draw them here
-
- if (level == 0
- || level == 1) {
-
- if (this.end == end) {
-
- final int color;
- final int breakHeight;
- if (config.breakColor == 0) {
- color = ColorUtils.applyAlpha(p.getColor(), DEF_BREAK_COLOR_ALPHA);
- } else {
- color = config.breakColor;
- }
- if (config.breakHeight == 0) {
- breakHeight = (int) (p.getStrokeWidth() + .5F);
- } else {
- breakHeight = config.breakHeight;
- }
- paint.setStyle(Paint.Style.FILL);
- paint.setColor(color);
-
- rect.set(x, bottom - breakHeight, c.getWidth(), bottom);
- c.drawRect(rect, paint);
- }
- }
- }
-}
diff --git a/library-spans/src/main/java/ru/noties/markwon/spans/SubSpan.java b/library-spans/src/main/java/ru/noties/markwon/spans/SubSpan.java
deleted file mode 100644
index d38f75da..00000000
--- a/library-spans/src/main/java/ru/noties/markwon/spans/SubSpan.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package ru.noties.markwon.spans;
-
-import android.text.TextPaint;
-import android.text.style.MetricAffectingSpan;
-
-public class SubSpan extends MetricAffectingSpan {
-
- @Override
- public void updateDrawState(TextPaint tp) {
- tp.setTextSize(tp.getTextSize() * .75F);
- tp.baselineShift -= (int) (tp.ascent() / 2);
- }
-
- @Override
- public void updateMeasureState(TextPaint tp) {
- tp.setTextSize(tp.getTextSize() * .75F);
- tp.baselineShift -= (int) (tp.ascent() / 2);
- }
-}
diff --git a/library-spans/src/main/java/ru/noties/markwon/spans/SupSpan.java b/library-spans/src/main/java/ru/noties/markwon/spans/SupSpan.java
deleted file mode 100644
index 4fddd44d..00000000
--- a/library-spans/src/main/java/ru/noties/markwon/spans/SupSpan.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package ru.noties.markwon.spans;
-
-import android.text.TextPaint;
-import android.text.style.MetricAffectingSpan;
-
-public class SupSpan extends MetricAffectingSpan {
-
- @Override
- public void updateDrawState(TextPaint tp) {
- tp.setTextSize(tp.getTextSize() * .75F);
- tp.baselineShift += (int) (tp.ascent() / 2);
- }
-
- @Override
- public void updateMeasureState(TextPaint tp) {
- tp.setTextSize(tp.getTextSize() * .75F);
- tp.baselineShift += (int) (tp.ascent() / 2);
- }
-}
diff --git a/library-spans/src/main/java/ru/noties/markwon/spans/ThematicBreakSpan.java b/library-spans/src/main/java/ru/noties/markwon/spans/ThematicBreakSpan.java
deleted file mode 100644
index 27e99271..00000000
--- a/library-spans/src/main/java/ru/noties/markwon/spans/ThematicBreakSpan.java
+++ /dev/null
@@ -1,64 +0,0 @@
-package ru.noties.markwon.spans;
-
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.support.annotation.ColorInt;
-import android.support.annotation.IntRange;
-import android.text.Layout;
-import android.text.style.LeadingMarginSpan;
-
-public class ThematicBreakSpan implements LeadingMarginSpan {
-
- private static final int DEF_COLOR_ALPHA = 127;
-
- public static class Config {
-
- final int color; // by default textColor with 0.5 alpha
- final int height; // by default strokeWidth of paint
-
- public Config(@ColorInt int color, @IntRange(from = 0) int height) {
- this.color = color;
- this.height = height;
- }
- }
-
- private final Config config;
- private final Rect rect = ObjectsPool.rect();
- private final Paint paint = ObjectsPool.paint();
-
- public ThematicBreakSpan(Config config) {
- this.config = config;
- }
-
- @Override
- public int getLeadingMargin(boolean first) {
- return 0;
- }
-
- @Override
- public void drawLeadingMargin(Canvas c, Paint p, int x, int dir, int top, int baseline, int bottom, CharSequence text, int start, int end, boolean first, Layout layout) {
-
- final int middle = top + ((bottom - top) / 2);
-
- final int color;
- if (config.color == 0) {
- color = ColorUtils.applyAlpha(p.getColor(), DEF_COLOR_ALPHA);
- } else {
- color = config.color;
- }
- paint.setColor(color);
- paint.setStyle(Paint.Style.FILL);
-
- final int height;
- if (config.height == 0) {
- height = (int) (p.getStrokeWidth() + .5F);
- } else {
- height = config.height;
- }
- final int halfHeight = (int) (height / 2.F + .5F);
-
- rect.set(x, middle - halfHeight, c.getWidth(), middle + halfHeight);
- c.drawRect(rect, paint);
- }
-}
diff --git a/settings.gradle b/settings.gradle
index dce89cfc..330339ba 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1 +1 @@
-include ':app', ':library-spans', ':library-renderer', ':library-view'
+include ':app', ':library-renderer', ':library-view'