Working on new sample application
This commit is contained in:
parent
0505845e4c
commit
e01787982f
@ -68,6 +68,7 @@ ext {
|
|||||||
'okhttp' : 'com.squareup.okhttp3:okhttp:3.9.0',
|
'okhttp' : 'com.squareup.okhttp3:okhttp:3.9.0',
|
||||||
'prism4j' : 'ru.noties:prism4j:1.1.0',
|
'prism4j' : 'ru.noties:prism4j:1.1.0',
|
||||||
'debug' : 'ru.noties:debug:3.0.0@jar',
|
'debug' : 'ru.noties:debug:3.0.0@jar',
|
||||||
|
'adapt' : 'ru.noties:adapt:1.1.0',
|
||||||
'dagger' : "com.google.dagger:dagger:$daggerVersion"
|
'dagger' : "com.google.dagger:dagger:$daggerVersion"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -12,11 +12,23 @@ android {
|
|||||||
versionCode 1
|
versionCode 1
|
||||||
versionName version
|
versionName version
|
||||||
setProperty("archivesBaseName", "markwon-sample-$versionName")
|
setProperty("archivesBaseName", "markwon-sample-$versionName")
|
||||||
|
|
||||||
|
resConfig 'en'
|
||||||
}
|
}
|
||||||
|
|
||||||
lintOptions {
|
lintOptions {
|
||||||
abortOnError false
|
abortOnError false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dexOptions {
|
||||||
|
preDexLibraries true
|
||||||
|
javaMaxHeapSize '5g'
|
||||||
|
}
|
||||||
|
|
||||||
|
compileOptions {
|
||||||
|
targetCompatibility JavaVersion.VERSION_1_8
|
||||||
|
sourceCompatibility JavaVersion.VERSION_1_8
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
@ -31,12 +43,20 @@ dependencies {
|
|||||||
implementation project(':markwon-syntax-highlight')
|
implementation project(':markwon-syntax-highlight')
|
||||||
|
|
||||||
deps.with {
|
deps.with {
|
||||||
|
implementation it['support-recycler-view']
|
||||||
implementation it['okhttp']
|
implementation it['okhttp']
|
||||||
implementation it['prism4j']
|
implementation it['prism4j']
|
||||||
implementation it['debug']
|
implementation it['debug']
|
||||||
|
implementation it['adapt']
|
||||||
}
|
}
|
||||||
|
|
||||||
deps['annotationProcessor'].with {
|
deps['annotationProcessor'].with {
|
||||||
annotationProcessor it['prism4j-bundler']
|
annotationProcessor it['prism4j-bundler']
|
||||||
}
|
}
|
||||||
|
|
||||||
|
deps['test'].with {
|
||||||
|
testImplementation it['junit']
|
||||||
|
testImplementation it['robolectric']
|
||||||
|
testImplementation it['mockito']
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,10 @@
|
|||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
<activity android:name=".core.CoreActivity" />
|
||||||
|
<activity android:name=".latex.LatexActivity" />
|
||||||
|
<activity android:name=".customextension.CustomExtensionActivity" />
|
||||||
|
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
@ -1,12 +1,96 @@
|
|||||||
package ru.noties.markwon.sample;
|
package ru.noties.markwon.sample;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.VisibleForTesting;
|
||||||
|
import android.support.v7.widget.LinearLayoutManager;
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import ru.noties.adapt.Adapt;
|
||||||
|
import ru.noties.adapt.OnClickViewProcessor;
|
||||||
|
import ru.noties.debug.AndroidLogDebugOutput;
|
||||||
|
import ru.noties.debug.Debug;
|
||||||
|
import ru.noties.markwon.Markwon;
|
||||||
|
import ru.noties.markwon.sample.core.CoreActivity;
|
||||||
|
import ru.noties.markwon.sample.customextension.CustomExtensionActivity;
|
||||||
|
import ru.noties.markwon.sample.latex.LatexActivity;
|
||||||
|
|
||||||
public class MainActivity extends Activity {
|
public class MainActivity extends Activity {
|
||||||
|
|
||||||
|
static {
|
||||||
|
Debug.init(new AndroidLogDebugOutput(true));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.activity_main);
|
||||||
|
|
||||||
|
// obtain an instance of Markwon
|
||||||
|
// here we are creating as core markwon (no additional plugins are registered)
|
||||||
|
final Markwon markwon = Markwon.create(this);
|
||||||
|
|
||||||
|
final Adapt<SampleItem> adapt = Adapt.builder(SampleItem.class)
|
||||||
|
.include(SampleItem.class, new SampleItemView(markwon), new OnClickViewProcessor<SampleItem>() {
|
||||||
|
@Override
|
||||||
|
public void onClick(@NonNull SampleItem item, @NonNull View view) {
|
||||||
|
showSample(item);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.build();
|
||||||
|
adapt.setItems(Arrays.asList(SampleItem.values()));
|
||||||
|
|
||||||
|
final RecyclerView recyclerView = findViewById(R.id.recycler_view);
|
||||||
|
recyclerView.setLayoutManager(new LinearLayoutManager(this));
|
||||||
|
recyclerView.setHasFixedSize(true);
|
||||||
|
recyclerView.addItemDecoration(createSampleItemDecoration());
|
||||||
|
recyclerView.setAdapter(adapt.recyclerViewAdapter());
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private SampleItemDecoration createSampleItemDecoration() {
|
||||||
|
final float density = getResources().getDisplayMetrics().density;
|
||||||
|
return new SampleItemDecoration(
|
||||||
|
0xffeeeeee,
|
||||||
|
(int) (24 * density + .5F),
|
||||||
|
(int) (1 * density + .5F),
|
||||||
|
0xFFBDBDBD
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showSample(@NonNull SampleItem item) {
|
||||||
|
startActivity(sampleItemIntent(this, item));
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
static Intent sampleItemIntent(@NonNull Context context, @NonNull SampleItem item) {
|
||||||
|
|
||||||
|
final Class<? extends Activity> activity;
|
||||||
|
|
||||||
|
switch (item) {
|
||||||
|
|
||||||
|
case CORE:
|
||||||
|
activity = CoreActivity.class;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LATEX:
|
||||||
|
activity = LatexActivity.class;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CUSTOM_EXTENSION:
|
||||||
|
activity = CustomExtensionActivity.class;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException("No Activity is associated with sample-item: " + item);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Intent(context, activity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,26 @@
|
|||||||
|
package ru.noties.markwon.sample;
|
||||||
|
|
||||||
|
import android.support.annotation.StringRes;
|
||||||
|
|
||||||
|
public enum SampleItem {
|
||||||
|
|
||||||
|
// all usages of markwon without plugins (parse, render, setMarkwon, etc)
|
||||||
|
CORE(R.string.sample_core),
|
||||||
|
|
||||||
|
LATEX(R.string.sample_latex),
|
||||||
|
|
||||||
|
CUSTOM_EXTENSION(R.string.sample_custom_extension),
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
|
private final int textResId;
|
||||||
|
|
||||||
|
SampleItem(@StringRes int textResId) {
|
||||||
|
this.textResId = textResId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@StringRes
|
||||||
|
public int textResId() {
|
||||||
|
return textResId;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,97 @@
|
|||||||
|
package ru.noties.markwon.sample;
|
||||||
|
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.support.annotation.ColorInt;
|
||||||
|
import android.support.annotation.Px;
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
class SampleItemDecoration extends RecyclerView.ItemDecoration {
|
||||||
|
|
||||||
|
private final Rect rect = new Rect();
|
||||||
|
private final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||||
|
|
||||||
|
private final int oddItemBackgroundColor;
|
||||||
|
|
||||||
|
private final int bottomPadding;
|
||||||
|
|
||||||
|
private final int dividerHeight;
|
||||||
|
private final int dividerColor;
|
||||||
|
|
||||||
|
SampleItemDecoration(
|
||||||
|
@ColorInt int oddItemBackgroundColor,
|
||||||
|
@Px int bottomPadding,
|
||||||
|
@Px int dividerHeight,
|
||||||
|
@ColorInt int dividerColor) {
|
||||||
|
this.oddItemBackgroundColor = oddItemBackgroundColor;
|
||||||
|
this.bottomPadding = bottomPadding;
|
||||||
|
this.dividerHeight = dividerHeight;
|
||||||
|
this.dividerColor = dividerColor;
|
||||||
|
|
||||||
|
paint.setStyle(Paint.Style.FILL);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
|
||||||
|
|
||||||
|
// if bottom < parent.getBottom() -> draw bottom background
|
||||||
|
|
||||||
|
paint.setColor(dividerColor);
|
||||||
|
|
||||||
|
View view;
|
||||||
|
|
||||||
|
// we will use this flag afterwards (if we will have to draw bottom background)
|
||||||
|
// so, if last item is even (no background) -> draw odd
|
||||||
|
// if last item is odd -> draw no background
|
||||||
|
//
|
||||||
|
// let's start with true, so if we have no items no background will be drawn
|
||||||
|
boolean isOdd = true;
|
||||||
|
|
||||||
|
for (int i = 0, count = parent.getChildCount(); i < count; i++) {
|
||||||
|
|
||||||
|
view = parent.getChildAt(i);
|
||||||
|
isOdd = parent.getChildAdapterPosition(view) % 2 != 0;
|
||||||
|
|
||||||
|
// odd
|
||||||
|
if (isOdd) {
|
||||||
|
rect.set(view.getLeft(), view.getTop(), view.getRight(), view.getBottom());
|
||||||
|
paint.setColor(oddItemBackgroundColor);
|
||||||
|
c.drawRect(rect, paint);
|
||||||
|
|
||||||
|
// set divider color back
|
||||||
|
paint.setColor(dividerColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
rect.set(0, view.getBottom(), c.getWidth(), view.getBottom() + dividerHeight);
|
||||||
|
c.drawRect(rect, paint);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isOdd && rect.bottom < parent.getBottom()) {
|
||||||
|
|
||||||
|
paint.setColor(oddItemBackgroundColor);
|
||||||
|
|
||||||
|
rect.set(0, rect.bottom, c.getWidth(), parent.getBottom());
|
||||||
|
c.drawRect(rect, paint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
|
||||||
|
|
||||||
|
// divider to bottom
|
||||||
|
// + {if last} -> bottomPadding
|
||||||
|
|
||||||
|
final int position = parent.getChildAdapterPosition(view);
|
||||||
|
|
||||||
|
final RecyclerView.Adapter<?> adapter = parent.getAdapter();
|
||||||
|
final boolean isLast = adapter != null && position == adapter.getItemCount() - 1;
|
||||||
|
|
||||||
|
final int bottom = isLast
|
||||||
|
? bottomPadding + dividerHeight
|
||||||
|
: dividerHeight;
|
||||||
|
|
||||||
|
outRect.set(0, 0, 0, bottom);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,84 @@
|
|||||||
|
package ru.noties.markwon.sample;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.text.Spannable;
|
||||||
|
import android.text.SpannableString;
|
||||||
|
import android.text.Spanned;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import java.util.EnumMap;
|
||||||
|
|
||||||
|
import ru.noties.adapt.Holder;
|
||||||
|
import ru.noties.adapt.ItemView;
|
||||||
|
import ru.noties.markwon.Markwon;
|
||||||
|
|
||||||
|
class SampleItemView extends ItemView<SampleItem, SampleItemView.SampleHolder> {
|
||||||
|
|
||||||
|
private final Markwon markwon;
|
||||||
|
|
||||||
|
// instance specific factory
|
||||||
|
private final NoCopySpannableFactory factory;
|
||||||
|
|
||||||
|
// instance specific cache
|
||||||
|
private final EnumMap<SampleItem, Spanned> cache;
|
||||||
|
|
||||||
|
SampleItemView(@NonNull Markwon markwon) {
|
||||||
|
this.markwon = markwon;
|
||||||
|
this.factory = new NoCopySpannableFactory();
|
||||||
|
this.cache = new EnumMap<>(SampleItem.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public SampleHolder createHolder(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) {
|
||||||
|
|
||||||
|
final SampleHolder holder = new SampleHolder(inflater.inflate(
|
||||||
|
R.layout.adapt_sample_item,
|
||||||
|
parent,
|
||||||
|
false));
|
||||||
|
|
||||||
|
// set Spannable.Factory so when TextView will receive a new content
|
||||||
|
// it won't create new Spannable and copy all the spans but instead
|
||||||
|
// re-use existing Spannable thus improving performance
|
||||||
|
holder.textView.setSpannableFactory(factory);
|
||||||
|
|
||||||
|
return holder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bindHolder(@NonNull SampleHolder holder, @NonNull SampleItem item) {
|
||||||
|
|
||||||
|
// retrieve an item from cache or create new one
|
||||||
|
// simple lazy loading pattern (cache on first call then re-use)
|
||||||
|
Spanned spanned = cache.get(item);
|
||||||
|
if (spanned == null) {
|
||||||
|
spanned = markwon.toMarkdown(context(holder).getString(item.textResId()));
|
||||||
|
cache.put(item, spanned);
|
||||||
|
}
|
||||||
|
|
||||||
|
holder.textView.setText(spanned);
|
||||||
|
}
|
||||||
|
|
||||||
|
static class SampleHolder extends Holder {
|
||||||
|
|
||||||
|
final TextView textView;
|
||||||
|
|
||||||
|
SampleHolder(@NonNull View view) {
|
||||||
|
super(view);
|
||||||
|
|
||||||
|
this.textView = requireView(R.id.text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class NoCopySpannableFactory extends Spannable.Factory {
|
||||||
|
@Override
|
||||||
|
public Spannable newSpannable(CharSequence source) {
|
||||||
|
return source instanceof Spannable
|
||||||
|
? (Spannable) source
|
||||||
|
: new SpannableString(source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,208 @@
|
|||||||
|
package ru.noties.markwon.sample.core;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import android.text.Spanned;
|
||||||
|
import android.text.style.ForegroundColorSpan;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import org.commonmark.node.Heading;
|
||||||
|
import org.commonmark.node.Node;
|
||||||
|
import org.commonmark.node.Paragraph;
|
||||||
|
|
||||||
|
import ru.noties.markwon.AbstractMarkwonPlugin;
|
||||||
|
import ru.noties.markwon.Markwon;
|
||||||
|
import ru.noties.markwon.MarkwonPlugin;
|
||||||
|
import ru.noties.markwon.MarkwonSpansFactory;
|
||||||
|
import ru.noties.markwon.MarkwonVisitor;
|
||||||
|
import ru.noties.markwon.core.CorePlugin;
|
||||||
|
import ru.noties.markwon.core.MarkwonTheme;
|
||||||
|
|
||||||
|
public class CoreActivity extends Activity {
|
||||||
|
|
||||||
|
private TextView textView;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
textView = new TextView(this);
|
||||||
|
setContentView(textView);
|
||||||
|
|
||||||
|
step_1();
|
||||||
|
|
||||||
|
step_2();
|
||||||
|
|
||||||
|
step_3();
|
||||||
|
|
||||||
|
step_4();
|
||||||
|
|
||||||
|
step_5();
|
||||||
|
|
||||||
|
step_6();
|
||||||
|
|
||||||
|
step_7();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a simple instance of Markwon with only Core plugin registered
|
||||||
|
* this will handle all _natively_ supported by commonmark-java nodes:
|
||||||
|
* <ul>
|
||||||
|
* <li>StrongEmphasis</li>
|
||||||
|
* <li>Emphasis</li>
|
||||||
|
* <li>BlockQuote</li>
|
||||||
|
* <li>Code</li>
|
||||||
|
* <li>FencedCodeBlock</li>
|
||||||
|
* <li>IndentedCodeBlock</li>
|
||||||
|
* <li>ListItem (bullet-list and ordered list</li>
|
||||||
|
* <li>Heading</li>
|
||||||
|
* <li>Link</li>
|
||||||
|
* <li>ThematicBreak</li>
|
||||||
|
* <li>Paragraph (please note that there is no default span for a paragraph registered)</li>
|
||||||
|
* </ul>
|
||||||
|
* <p>
|
||||||
|
* and basic core functionality:
|
||||||
|
* <ul>
|
||||||
|
* <li>Append text</li>
|
||||||
|
* <li>Insert new lines (soft and hard breaks)</li>
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
|
private void step_1() {
|
||||||
|
|
||||||
|
// short call
|
||||||
|
final Markwon markwon = Markwon.create(this);
|
||||||
|
|
||||||
|
// this is the same as calling
|
||||||
|
final Markwon markwon2 = Markwon.builder(this)
|
||||||
|
.usePlugin(CorePlugin.create())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To simply apply raw (non-parsed) markdown call {@link Markwon#setMarkdown(TextView, String)}
|
||||||
|
*/
|
||||||
|
private void step_2() {
|
||||||
|
|
||||||
|
// this is raw markdown
|
||||||
|
final String markdown = "Hello **markdown**!";
|
||||||
|
|
||||||
|
final Markwon markwon = Markwon.create(this);
|
||||||
|
|
||||||
|
// this will parse raw markdown and set parsed content to specified TextView
|
||||||
|
markwon.setMarkdown(textView, markdown);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To apply markdown in a different context (other than textView) use {@link Markwon#toMarkdown(String)}
|
||||||
|
* <p>
|
||||||
|
* Please note that some features won't work unless they are used in a TextView context. For example
|
||||||
|
* there might be misplaced ordered lists (ordered list must have TextPaint in order to properly measure
|
||||||
|
* its number). But also images and tables (they belong to independent modules now). Images and tables
|
||||||
|
* are using some work-arounds in order to be displayed in relatively limited context without proper way
|
||||||
|
* of invalidation. But if a Toast for example is created with a custom view
|
||||||
|
* ({@code new Toast(this).setView(...) }) and has access to a TextView everything <em>should</em> work.
|
||||||
|
*/
|
||||||
|
private void step_3() {
|
||||||
|
|
||||||
|
final String markdown = "*Toast* __here__!\n\n> And a quote!";
|
||||||
|
|
||||||
|
final Markwon markwon = Markwon.create(this);
|
||||||
|
|
||||||
|
final Spanned spanned = markwon.toMarkdown(markdown);
|
||||||
|
|
||||||
|
Toast.makeText(this, spanned, Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To apply already parsed markdown use {@link Markwon#setParsedMarkdown(TextView, Spanned)}
|
||||||
|
*/
|
||||||
|
private void step_4() {
|
||||||
|
|
||||||
|
final String markdown = "This **is** pre-parsed [markdown](#)";
|
||||||
|
|
||||||
|
final Markwon markwon = Markwon.create(this);
|
||||||
|
|
||||||
|
// parse markdown to obtain a Node
|
||||||
|
final Node node = markwon.parse(markdown);
|
||||||
|
|
||||||
|
// create a spanned content from parsed node
|
||||||
|
final Spanned spanned = markwon.render(node);
|
||||||
|
|
||||||
|
// apply parsed markdown
|
||||||
|
markwon.setParsedMarkdown(textView, spanned);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In order to apply paragraph spans a custom plugin should be created (CorePlugin will take care
|
||||||
|
* of everything else).
|
||||||
|
* <p>
|
||||||
|
* Please note that when a plugin is registered and it <em>depends</em> on CorePlugin, there is no
|
||||||
|
* need to explicitly specify it. By default all plugins that extend AbstractMarkwonPlugin do declare
|
||||||
|
* it\'s dependency on CorePlugin ({@link MarkwonPlugin#priority()}).
|
||||||
|
* <p>
|
||||||
|
* Order in which plugins are specified to the builder is of little importance as long as each
|
||||||
|
* plugin clearly states what dependencies it has
|
||||||
|
*/
|
||||||
|
private void step_5() {
|
||||||
|
|
||||||
|
final String markdown = "# Hello!\n\nA paragraph?\n\nIt should be!";
|
||||||
|
|
||||||
|
final Markwon markwon = Markwon.builder(this)
|
||||||
|
.usePlugin(new AbstractMarkwonPlugin() {
|
||||||
|
@Override
|
||||||
|
public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) {
|
||||||
|
builder.setFactory(Paragraph.class, (configuration, props) ->
|
||||||
|
new ForegroundColorSpan(Color.GREEN));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.build();
|
||||||
|
|
||||||
|
markwon.setMarkdown(textView, markdown);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To disable some nodes from rendering another custom plugin can be used
|
||||||
|
*/
|
||||||
|
private void step_6() {
|
||||||
|
|
||||||
|
final String markdown = "# Heading 1\n\n## Heading 2\n\n**other** content [here](#)";
|
||||||
|
|
||||||
|
final Markwon markwon = Markwon.builder(this)
|
||||||
|
.usePlugin(new AbstractMarkwonPlugin() {
|
||||||
|
@Override
|
||||||
|
public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) {
|
||||||
|
// for example to disable rendering of heading:
|
||||||
|
// try commenting this out to see that otherwise headings will be rendered
|
||||||
|
builder.on(Heading.class, null);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.build();
|
||||||
|
|
||||||
|
markwon.setMarkdown(textView, markdown);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To customize core theme plugins can be used again
|
||||||
|
*/
|
||||||
|
private void step_7() {
|
||||||
|
|
||||||
|
final String markdown = "`A code` that is rendered differently\n\n```\nHello!\n```";
|
||||||
|
|
||||||
|
final Markwon markwon = Markwon.builder(this)
|
||||||
|
.usePlugin(new AbstractMarkwonPlugin() {
|
||||||
|
@Override
|
||||||
|
public void configureTheme(@NonNull MarkwonTheme.Builder builder) {
|
||||||
|
builder
|
||||||
|
.codeBackgroundColor(Color.BLACK)
|
||||||
|
.codeTextColor(Color.RED);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.build();
|
||||||
|
|
||||||
|
markwon.setMarkdown(textView, markdown);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
package ru.noties.markwon.sample.customextension;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
|
||||||
|
public class CustomExtensionActivity extends Activity {
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package ru.noties.markwon.sample.latex;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
|
public class LatexActivity extends Activity {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
15
sample/src/main/res/layout/activity_main.xml
Normal file
15
sample/src/main/res/layout/activity_main.xml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<android.support.v7.widget.RecyclerView
|
||||||
|
android:id="@+id/recycler_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:clipChildren="false"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:overScrollMode="never"
|
||||||
|
android:scrollbars="vertical" />
|
||||||
|
|
||||||
|
</FrameLayout>
|
13
sample/src/main/res/layout/adapt_sample_item.xml
Normal file
13
sample/src/main/res/layout/adapt_sample_item.xml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/text"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?android:attr/selectableItemBackground"
|
||||||
|
android:lineSpacingExtra="2dip"
|
||||||
|
android:padding="16dip"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||||
|
android:textColor="#212121"
|
||||||
|
android:textSize="17sp"
|
||||||
|
tools:text="# This is text" />
|
6
sample/src/main/res/values-v21/styles.xml
Normal file
6
sample/src/main/res/values-v21/styles.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<resources>
|
||||||
|
|
||||||
|
|
||||||
|
<style name="BaseAppTheme" parent="android:Theme.Material.Light.DarkActionBar" />
|
||||||
|
|
||||||
|
</resources>
|
10
sample/src/main/res/values/strings-samples.xml
Normal file
10
sample/src/main/res/values/strings-samples.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
|
||||||
|
<!--Ignore missing translation warning-->
|
||||||
|
|
||||||
|
<string name="sample_core"># \# Core\n\nSimple usage example</string>
|
||||||
|
<string name="sample_latex"># \# LaTeX\n\nShows how to display a **LaTeX** formula in a Markwon powered application</string>
|
||||||
|
<string name="sample_custom_extension"># \# Custom extension\n\nShows how to create a custom extension to display an icon referenced in markdown as `@ic-android-black-24`</string>
|
||||||
|
|
||||||
|
</resources>
|
@ -1,8 +1,7 @@
|
|||||||
<resources>
|
<resources>
|
||||||
|
|
||||||
<!-- Base application theme. -->
|
<style name="BaseAppTheme" parent="android:Theme.Holo.Light.DarkActionBar" />
|
||||||
<style name="AppTheme" parent="android:Theme.Material.Light.DarkActionBar">
|
|
||||||
<!-- Customize your theme here. -->
|
<style name="AppTheme" parent="BaseAppTheme" />
|
||||||
</style>
|
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
package ru.noties.markwon.sample;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.robolectric.RobolectricTestRunner;
|
||||||
|
import org.robolectric.RuntimeEnvironment;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
|
||||||
|
@RunWith(RobolectricTestRunner.class)
|
||||||
|
@Config(manifest = Config.NONE)
|
||||||
|
public class MainActivityTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void all_sample_items_have_activity_associated() {
|
||||||
|
final Context context = RuntimeEnvironment.application;
|
||||||
|
for (SampleItem item : SampleItem.values()) {
|
||||||
|
// we assert as not null, but in case of an error this method should throw
|
||||||
|
assertNotNull(MainActivity.sampleItemIntent(context, item));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user