Table parsing and improvements for recycler artifact

This commit is contained in:
Dimitry Ivanov 2018-12-25 15:08:28 +03:00
parent f6ac3fde68
commit 24b95e2ffb
11 changed files with 315 additions and 274 deletions

View File

@ -0,0 +1,220 @@
package ru.noties.markwon.ext.tables;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.Spanned;
import org.commonmark.ext.gfm.tables.TableBlock;
import org.commonmark.ext.gfm.tables.TableCell;
import org.commonmark.ext.gfm.tables.TableHead;
import org.commonmark.ext.gfm.tables.TableRow;
import org.commonmark.node.AbstractVisitor;
import org.commonmark.node.CustomNode;
import org.commonmark.node.Node;
import java.util.ArrayList;
import java.util.List;
import ru.noties.markwon.Markwon;
/**
* A class to parse <code>TableBlock</code> and return a data-structure that is not dependent
* on commonmark-java table extension. Can be useful when rendering tables require special
* handling (multiple views, specific table view) for example when used with `markwon-recycler` artifact
*
* @see #parse(Markwon, TableBlock)
* @since 3.0.0
*/
public class Table {
/**
* Factory method to obtain an instance of {@link Table}
*
* @param markwon Markwon
* @param tableBlock TableBlock to parse
* @return parsed {@link Table} or null
*/
@Nullable
public static Table parse(@NonNull Markwon markwon, @NonNull TableBlock tableBlock) {
final Table table;
final ParseVisitor visitor = new ParseVisitor(markwon);
tableBlock.accept(visitor);
final List<Row> rows = visitor.rows();
if (rows == null) {
table = null;
} else {
table = new Table(rows);
}
return table;
}
public static class Row {
private final boolean isHeader;
private final List<Column> columns;
public Row(
boolean isHeader,
@NonNull List<Column> columns) {
this.isHeader = isHeader;
this.columns = columns;
}
public boolean header() {
return isHeader;
}
@NonNull
public List<Column> columns() {
return columns;
}
@Override
public String toString() {
return "Row{" +
"isHeader=" + isHeader +
", columns=" + columns +
'}';
}
}
public static class Column {
private final Alignment alignment;
private final Spanned content;
public Column(@NonNull Alignment alignment, @NonNull Spanned content) {
this.alignment = alignment;
this.content = content;
}
@NonNull
public Alignment alignment() {
return alignment;
}
@NonNull
public Spanned content() {
return content;
}
@Override
public String toString() {
return "Column{" +
"alignment=" + alignment +
", content=" + content +
'}';
}
}
public enum Alignment {
LEFT,
CENTER,
RIGHT
}
private final List<Row> rows;
public Table(@NonNull List<Row> rows) {
this.rows = rows;
}
@NonNull
public List<Row> rows() {
return rows;
}
@Override
public String toString() {
return "Table{" +
"rows=" + rows +
'}';
}
static class ParseVisitor extends AbstractVisitor {
private final Markwon markwon;
private List<Row> rows;
private List<Column> pendingRow;
private boolean pendingRowIsHeader;
ParseVisitor(@NonNull Markwon markwon) {
this.markwon = markwon;
}
@Nullable
public List<Row> rows() {
return rows;
}
@Override
public void visit(CustomNode customNode) {
if (customNode instanceof TableCell) {
final TableCell cell = (TableCell) customNode;
final Node firstChild = cell.getFirstChild();
// need to investigate why... (most likely initial node is modified by someone)
if (firstChild != null) {
if (pendingRow == null) {
pendingRow = new ArrayList<>(2);
}
// let's TRY to not visit this node but instead try to render its first child
pendingRow.add(new Table.Column(alignment(cell.getAlignment()), markwon.render(firstChild)));
pendingRowIsHeader = cell.isHeader();
}
return;
}
if (customNode instanceof TableHead
|| customNode instanceof TableRow) {
visitChildren(customNode);
// this can happen, ignore such row
if (pendingRow != null && pendingRow.size() > 0) {
if (rows == null) {
rows = new ArrayList<>(2);
}
rows.add(new Table.Row(pendingRowIsHeader, pendingRow));
}
pendingRow = null;
pendingRowIsHeader = false;
return;
}
visitChildren(customNode);
}
@NonNull
private static Table.Alignment alignment(@NonNull TableCell.Alignment alignment) {
final Table.Alignment out;
if (TableCell.Alignment.RIGHT == alignment) {
out = Table.Alignment.RIGHT;
} else if (TableCell.Alignment.CENTER == alignment) {
out = Table.Alignment.CENTER;
} else {
out = Table.Alignment.LEFT;
}
return out;
}
}
}

View File

@ -33,10 +33,11 @@ public class TablePlugin extends AbstractMarkwonPlugin {
return new TablePlugin(tableTheme); return new TablePlugin(tableTheme);
} }
private final TableTheme tableTheme; private final TableVisitor visitor;
@SuppressWarnings("WeakerAccess")
TablePlugin(@NonNull TableTheme tableTheme) { TablePlugin(@NonNull TableTheme tableTheme) {
this.tableTheme = tableTheme; this.visitor = new TableVisitor(tableTheme);
} }
@Override @Override
@ -46,7 +47,12 @@ public class TablePlugin extends AbstractMarkwonPlugin {
@Override @Override
public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) { public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) {
TableVisitor.configure(tableTheme, builder); visitor.configure(builder);
}
@Override
public void beforeRender(@NonNull Node node) {
visitor.clear();
} }
@Override @Override
@ -61,18 +67,23 @@ public class TablePlugin extends AbstractMarkwonPlugin {
private static class TableVisitor { private static class TableVisitor {
static void configure(@NonNull TableTheme tableTheme, @NonNull MarkwonVisitor.Builder builder) {
new TableVisitor(tableTheme, builder);
}
private final TableTheme tableTheme; private final TableTheme tableTheme;
private List<TableRowSpan.Cell> pendingTableRow; private List<TableRowSpan.Cell> pendingTableRow;
private boolean tableRowIsHeader; private boolean tableRowIsHeader;
private int tableRows; private int tableRows;
private TableVisitor(@NonNull TableTheme tableTheme, @NonNull MarkwonVisitor.Builder builder) { TableVisitor(@NonNull TableTheme tableTheme) {
this.tableTheme = tableTheme; this.tableTheme = tableTheme;
}
void clear() {
pendingTableRow = null;
tableRowIsHeader = false;
tableRows = 0;
}
void configure(@NonNull MarkwonVisitor.Builder builder) {
builder builder
.on(TableBody.class, new MarkwonVisitor.NodeVisitor<TableBody>() { .on(TableBody.class, new MarkwonVisitor.NodeVisitor<TableBody>() {
@Override @Override

View File

@ -15,7 +15,25 @@ import java.util.List;
import ru.noties.markwon.Markwon; import ru.noties.markwon.Markwon;
// each node block will be rendered by a simple TextView, but we can provide own entries for each block /**
* Class to display markdown in a RecyclerView. It is done by extracting root blocks from a
* parsed markdown document and rendering each block in a standalone RecyclerView entry. Provides
* ability to customize rendering of blocks. For example display certain blocks in a horizontal
* scrolling container or display tables in a specific widget designed for it ({@link Builder#include(Class, Entry)}).
* <p>
* By default each node will be rendered in a TextView provided by this artifact. It has no styling
* information and thus must be replaced with your own layout ({@link Builder#defaultEntry(int)} or
* {@link Builder#defaultEntry(Entry)}).
*
* @see #builder()
* @see #create()
* @see #create(int)
* @see #create(Entry)
* @see #setMarkdown(Markwon, String)
* @see #setParsedMarkdown(Markwon, Node)
* @see #setParsedMarkdown(Markwon, List)
* @since 3.0.0
*/
public abstract class MarkwonAdapter extends RecyclerView.Adapter<MarkwonAdapter.Holder> { public abstract class MarkwonAdapter extends RecyclerView.Adapter<MarkwonAdapter.Holder> {
@NonNull @NonNull
@ -59,6 +77,9 @@ public abstract class MarkwonAdapter extends RecyclerView.Adapter<MarkwonAdapter
MarkwonAdapter build(); MarkwonAdapter build();
} }
/**
* @see SimpleEntry
*/
public interface Entry<H extends Holder, N extends Node> { public interface Entry<H extends Holder, N extends Node> {
@NonNull @NonNull

View File

@ -1,7 +1,6 @@
package ru.noties.markwon.recycler; package ru.noties.markwon.recycler;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.util.Log;
import android.util.SparseArray; import android.util.SparseArray;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.ViewGroup; import android.view.ViewGroup;
@ -25,6 +24,7 @@ class MarkwonAdapterImpl extends MarkwonAdapter {
private Markwon markwon; private Markwon markwon;
private List<Node> nodes; private List<Node> nodes;
@SuppressWarnings("WeakerAccess")
MarkwonAdapterImpl( MarkwonAdapterImpl(
@NonNull SparseArray<Entry<Holder, Node>> entries, @NonNull SparseArray<Entry<Holder, Node>> entries,
@NonNull Entry<Holder, Node> defaultEntry, @NonNull Entry<Holder, Node> defaultEntry,
@ -67,9 +67,7 @@ class MarkwonAdapterImpl extends MarkwonAdapter {
layoutInflater = LayoutInflater.from(parent.getContext()); layoutInflater = LayoutInflater.from(parent.getContext());
} }
final Entry<Holder, Node> entry = viewType == 0 final Entry<Holder, Node> entry = getEntry(viewType);
? defaultEntry
: entries.get(viewType);
return entry.createHolder(layoutInflater, parent); return entry.createHolder(layoutInflater, parent);
} }
@ -80,9 +78,7 @@ class MarkwonAdapterImpl extends MarkwonAdapter {
final Node node = nodes.get(position); final Node node = nodes.get(position);
final int viewType = getNodeViewType(node.getClass()); final int viewType = getNodeViewType(node.getClass());
final Entry<Holder, Node> entry = viewType == 0 final Entry<Holder, Node> entry = getEntry(viewType);
? defaultEntry
: entries.get(viewType);
entry.bindHolder(markwon, holder, node); entry.bindHolder(markwon, holder, node);
} }
@ -94,6 +90,7 @@ class MarkwonAdapterImpl extends MarkwonAdapter {
: 0; : 0;
} }
@SuppressWarnings("unused")
@NonNull @NonNull
public List<Node> getItems() { public List<Node> getItems() {
return nodes != null return nodes != null
@ -110,12 +107,11 @@ class MarkwonAdapterImpl extends MarkwonAdapter {
public long getItemId(int position) { public long getItemId(int position) {
final Node node = nodes.get(position); final Node node = nodes.get(position);
final int type = getNodeViewType(node.getClass()); final int type = getNodeViewType(node.getClass());
final Entry<Holder, Node> entry = type == 0 final Entry<Holder, Node> entry = getEntry(type);
? defaultEntry
: entries.get(type);
return entry.id(node); return entry.id(node);
} }
@SuppressWarnings("WeakerAccess")
public int getNodeViewType(@NonNull Class<? extends Node> node) { public int getNodeViewType(@NonNull Class<? extends Node> node) {
// if has registered -> then return it, else 0 // if has registered -> then return it, else 0
final int hash = node.hashCode(); final int hash = node.hashCode();
@ -125,6 +121,13 @@ class MarkwonAdapterImpl extends MarkwonAdapter {
return 0; return 0;
} }
@NonNull
private Entry<Holder, Node> getEntry(int viewType) {
return viewType == 0
? defaultEntry
: entries.get(viewType);
}
static class BuilderImpl implements Builder { static class BuilderImpl implements Builder {
private final SparseArray<Entry<Holder, Node>> entries = new SparseArray<>(3); private final SparseArray<Entry<Holder, Node>> entries = new SparseArray<>(3);
@ -154,7 +157,7 @@ class MarkwonAdapterImpl extends MarkwonAdapter {
@Override @Override
public Builder defaultEntry(int layoutResId) { public Builder defaultEntry(int layoutResId) {
//noinspection unchecked //noinspection unchecked
this.defaultEntry = (Entry<Holder, Node>) (Entry) new SimpleNodeEntry(layoutResId); this.defaultEntry = (Entry<Holder, Node>) (Entry) new SimpleEntry(layoutResId);
return this; return this;
} }
@ -171,7 +174,7 @@ class MarkwonAdapterImpl extends MarkwonAdapter {
if (defaultEntry == null) { if (defaultEntry == null) {
//noinspection unchecked //noinspection unchecked
defaultEntry = (Entry<Holder, Node>) (Entry) new SimpleNodeEntry(); defaultEntry = (Entry<Holder, Node>) (Entry) new SimpleEntry();
} }
if (reducer == null) { if (reducer == null) {
@ -190,7 +193,7 @@ class MarkwonAdapterImpl extends MarkwonAdapter {
final List<Node> list = new ArrayList<>(); final List<Node> list = new ArrayList<>();
// // we will extract all blocks that are direct children of Document // we will extract all blocks that are direct children of Document
Node node = root.getFirstChild(); Node node = root.getFirstChild();
Node temp; Node temp;
@ -201,8 +204,6 @@ class MarkwonAdapterImpl extends MarkwonAdapter {
node = temp; node = temp;
} }
Log.e("NODES", list.toString());
return list; return list;
} }
} }

View File

@ -1,4 +0,0 @@
package ru.noties.markwon.recycler;
public class MarkwonRecycler {
}

View File

@ -17,7 +17,7 @@ import java.util.Map;
import ru.noties.markwon.Markwon; import ru.noties.markwon.Markwon;
public class SimpleNodeEntry implements MarkwonAdapter.Entry<SimpleNodeEntry.Holder, Node> { public class SimpleEntry implements MarkwonAdapter.Entry<SimpleEntry.Holder, Node> {
private static final NoCopySpannableFactory FACTORY = new NoCopySpannableFactory(); private static final NoCopySpannableFactory FACTORY = new NoCopySpannableFactory();
@ -26,11 +26,11 @@ public class SimpleNodeEntry implements MarkwonAdapter.Entry<SimpleNodeEntry.Hol
private final int layoutResId; private final int layoutResId;
public SimpleNodeEntry() { public SimpleEntry() {
this(R.layout.adapter_simple_entry); this(R.layout.markwon_adapter_simple_entry);
} }
public SimpleNodeEntry(@LayoutRes int layoutResId) { public SimpleEntry(@LayoutRes int layoutResId) {
this.layoutResId = layoutResId; this.layoutResId = layoutResId;
} }

View File

@ -0,0 +1,9 @@
<?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:lineSpacingExtra="2dip"
android:textAppearance="?android:attr/textAppearanceMedium"
tools:text="# Hello there!" />

View File

@ -65,7 +65,7 @@ class MarkwonImpl extends Markwon {
final Spanned spanned = visitor.builder().spannableStringBuilder(); final Spanned spanned = visitor.builder().spannableStringBuilder();
// clear render props and builder after rending // clear render props and builder after rendering
visitor.clear(); visitor.clear();
return spanned; return spanned;

View File

@ -29,7 +29,7 @@ import ru.noties.markwon.html.HtmlPlugin;
import ru.noties.markwon.image.ImagesPlugin; import ru.noties.markwon.image.ImagesPlugin;
import ru.noties.markwon.image.svg.SvgPlugin; import ru.noties.markwon.image.svg.SvgPlugin;
import ru.noties.markwon.recycler.MarkwonAdapter; import ru.noties.markwon.recycler.MarkwonAdapter;
import ru.noties.markwon.recycler.SimpleNodeEntry; import ru.noties.markwon.recycler.SimpleEntry;
import ru.noties.markwon.sample.extension.R; import ru.noties.markwon.sample.extension.R;
import ru.noties.markwon.urlprocessor.UrlProcessor; import ru.noties.markwon.urlprocessor.UrlProcessor;
import ru.noties.markwon.urlprocessor.UrlProcessorRelativeToAbsolute; import ru.noties.markwon.urlprocessor.UrlProcessorRelativeToAbsolute;
@ -48,8 +48,9 @@ public class MarkwonRecyclerActivity extends Activity {
setContentView(R.layout.activity_recycler); setContentView(R.layout.activity_recycler);
final MarkwonAdapter adapter = MarkwonAdapter.builder() final MarkwonAdapter adapter = MarkwonAdapter.builder()
.include(FencedCodeBlock.class, new SimpleNodeEntry(R.layout.adapter_fenced_code_block)) .include(FencedCodeBlock.class, new SimpleEntry(R.layout.adapter_fenced_code_block))
.include(TableBlock.class, new TableNodeEntry()) .include(TableBlock.class, new TableNodeEntry())
.defaultEntry(new SimpleEntry(R.layout.adapter_default_entry))
.build(); .build();
final RecyclerView recyclerView = findViewById(R.id.recycler_view); final RecyclerView recyclerView = findViewById(R.id.recycler_view);

View File

@ -1,48 +1,26 @@
package ru.noties.markwon.sample.extension.recycler; package ru.noties.markwon.sample.extension.recycler;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.TableLayout; import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;
import org.commonmark.ext.gfm.tables.TableBlock; import org.commonmark.ext.gfm.tables.TableBlock;
import org.commonmark.node.AbstractVisitor;
import org.commonmark.node.BlockQuote;
import org.commonmark.node.BulletList;
import org.commonmark.node.Code;
import org.commonmark.node.CustomBlock;
import org.commonmark.node.CustomNode;
import org.commonmark.node.Document;
import org.commonmark.node.Emphasis;
import org.commonmark.node.FencedCodeBlock;
import org.commonmark.node.HardLineBreak;
import org.commonmark.node.Heading;
import org.commonmark.node.HtmlBlock;
import org.commonmark.node.HtmlInline;
import org.commonmark.node.Image;
import org.commonmark.node.IndentedCodeBlock;
import org.commonmark.node.Link;
import org.commonmark.node.ListItem;
import org.commonmark.node.Node;
import org.commonmark.node.OrderedList;
import org.commonmark.node.Paragraph;
import org.commonmark.node.SoftLineBreak;
import org.commonmark.node.StrongEmphasis;
import org.commonmark.node.Text;
import org.commonmark.node.ThematicBreak;
import ru.noties.debug.Debug; import java.util.HashMap;
import java.util.Map;
import ru.noties.markwon.Markwon; import ru.noties.markwon.Markwon;
import ru.noties.markwon.ext.tables.Table;
import ru.noties.markwon.recycler.MarkwonAdapter; import ru.noties.markwon.recycler.MarkwonAdapter;
import ru.noties.markwon.sample.extension.R; import ru.noties.markwon.sample.extension.R;
// do not use in real applications, this is just a showcase // do not use in real applications, this is just a showcase
public class TableNodeEntry implements MarkwonAdapter.Entry<TableNodeEntry.TableNodeHolder, TableBlock> { public class TableNodeEntry implements MarkwonAdapter.Entry<TableNodeEntry.TableNodeHolder, TableBlock> {
private final Map<TableBlock, Table> cache = new HashMap<>(2);
@NonNull @NonNull
@Override @Override
public TableNodeHolder createHolder(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) { public TableNodeHolder createHolder(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) {
@ -52,77 +30,23 @@ public class TableNodeEntry implements MarkwonAdapter.Entry<TableNodeEntry.Table
@Override @Override
public void bindHolder(@NonNull Markwon markwon, @NonNull TableNodeHolder holder, @NonNull TableBlock node) { public void bindHolder(@NonNull Markwon markwon, @NonNull TableNodeHolder holder, @NonNull TableBlock node) {
if (true) { Table table = cache.get(node);
Debug.e("###############"); if (table == null) {
Debug.e("NODE: %s", node); table = Table.parse(markwon, node);
node.accept(new PrintVisitor()); cache.put(node, table);
Debug.e("NODE: %s", node);
Debug.e("###############");
} }
final TableLayout layout = holder.layout; if (table != null) {
layout.removeAllViews(); // render table
renderTable(markwon, holder, table);
// each child represents a row (head or regular) } // we need to do something with null table...
// first direct child is TableHead or TableBody
Node child = node.getFirstChild().getFirstChild();
Node temp;
while (child != null) {
Log.e("BIND-ROWS", String.valueOf(child));
temp = child.getNext();
addRow(markwon, layout, child);
child = temp;
}
Log.e("BIND", String.valueOf(layout.getChildCount()));
if (true) {
final ViewGroup group = (ViewGroup) layout.getChildAt(0);
Log.e("BIND-GROUP", String.valueOf(group.getChildCount()));
for (int i = 0; i < group.getChildCount(); i++) {
Log.e("BIND-CHILD-" + i, String.valueOf(group.getChildAt(i)) + ", " + ((TextView) group.getChildAt(i)).getText());
}
}
layout.requestLayout();
} }
private void addRow(@NonNull Markwon markwon, @NonNull TableLayout layout, @NonNull Node node) { private void renderTable(
@NonNull Markwon markwon,
@NonNull TableNodeHolder holder,
@NonNull Table table) {
final TableRow tableRow = new TableRow(layout.getContext());
// final TableRow.LayoutParams params = new TableRow.LayoutParams(100, 100);
tableRow.setBackgroundColor(0x80ff0000);
TextView textView;
RenderNode renderNode;
Node temp;
// each child in a row represents a cell
Node child = node.getFirstChild();
while (child != null) {
Log.e("BIND-CELL", String.valueOf(child));
textView = new TextView(layout.getContext());
textView.setLayoutParams(new TableRow.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
renderNode = new RenderNode();
temp = child.getNext();
copy(child, renderNode);
tableRow.addView(textView);
markwon.setParsedMarkdown(textView, markwon.render(renderNode));
child = temp;
}
layout.addView(tableRow);
}
private static void copy(@NonNull Node from, @NonNull Node to) {
Node child = from.getFirstChild();
Node temp;
while (child != null) {
Log.e("BIND-COPY", String.valueOf(child));
temp = child.getNext();
to.appendChild(child);
child = temp;
}
} }
@Override @Override
@ -132,7 +56,7 @@ public class TableNodeEntry implements MarkwonAdapter.Entry<TableNodeEntry.Table
@Override @Override
public void clear() { public void clear() {
cache.clear();
} }
static class TableNodeHolder extends MarkwonAdapter.Holder { static class TableNodeHolder extends MarkwonAdapter.Holder {
@ -145,145 +69,4 @@ public class TableNodeEntry implements MarkwonAdapter.Entry<TableNodeEntry.Table
this.layout = requireView(R.id.table_layout); this.layout = requireView(R.id.table_layout);
} }
} }
private static class RenderNode extends CustomBlock {
}
private static class PrintVisitor extends AbstractVisitor {
private final RenderNode renderNode = new RenderNode();
@Override
public void visit(BlockQuote blockQuote) {
Debug.i("blockQuote: %s", blockQuote);
super.visit(blockQuote);
}
@Override
public void visit(BulletList bulletList) {
Debug.i("bulletList: %s", bulletList);
super.visit(bulletList);
}
@Override
public void visit(Code code) {
Debug.i("code: %s", code);
super.visit(code);
}
@Override
public void visit(Document document) {
Debug.i("document: %s", document);
super.visit(document);
}
@Override
public void visit(Emphasis emphasis) {
Debug.i("emphasis: %s", emphasis);
super.visit(emphasis);
}
@Override
public void visit(FencedCodeBlock fencedCodeBlock) {
Debug.i("fencedCodeBlock: %s", fencedCodeBlock);
super.visit(fencedCodeBlock);
}
@Override
public void visit(HardLineBreak hardLineBreak) {
Debug.i("hardLineBreak: %s", hardLineBreak);
super.visit(hardLineBreak);
}
@Override
public void visit(Heading heading) {
Debug.i("heading: %s", heading);
super.visit(heading);
}
@Override
public void visit(ThematicBreak thematicBreak) {
Debug.i("thematicBreak: %s", thematicBreak);
super.visit(thematicBreak);
}
@Override
public void visit(HtmlInline htmlInline) {
Debug.i("htmlInline: %s", htmlInline);
super.visit(htmlInline);
}
@Override
public void visit(HtmlBlock htmlBlock) {
Debug.i("htmlBlock: %s", htmlBlock);
super.visit(htmlBlock);
}
@Override
public void visit(Image image) {
Debug.i("image: %s", image);
super.visit(image);
}
@Override
public void visit(IndentedCodeBlock indentedCodeBlock) {
Debug.i("indentedCodeBlock: %s", indentedCodeBlock);
super.visit(indentedCodeBlock);
}
@Override
public void visit(Link link) {
Debug.i("link: %s", link);
super.visit(link);
}
@Override
public void visit(ListItem listItem) {
Debug.i("listItem: %s", listItem);
super.visit(listItem);
}
@Override
public void visit(OrderedList orderedList) {
Debug.i("orderedList: %s", orderedList);
super.visit(orderedList);
}
@Override
public void visit(Paragraph paragraph) {
Debug.i("paragraph: %s", paragraph);
super.visit(paragraph);
}
@Override
public void visit(SoftLineBreak softLineBreak) {
Debug.i("softLineBreak: %s", softLineBreak);
super.visit(softLineBreak);
}
@Override
public void visit(StrongEmphasis strongEmphasis) {
Debug.i("strongEmphasis: %s", strongEmphasis);
super.visit(strongEmphasis);
}
@Override
public void visit(Text text) {
Debug.i("text: %s", text);
super.visit(text);
}
@Override
public void visit(CustomBlock customBlock) {
Debug.i("customBlock: %s", customBlock);
super.visit(customBlock);
}
@Override
public void visit(CustomNode customNode) {
Debug.i("customNode: %s", customNode);
super.visit(customNode);
}
}
} }

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android" <TextView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/text" android:id="@+id/text"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -10,5 +9,5 @@
android:paddingTop="8dip" android:paddingTop="8dip"
android:paddingBottom="8dip" android:paddingBottom="8dip"
android:textAppearance="?android:attr/textAppearanceMedium" android:textAppearance="?android:attr/textAppearanceMedium"
android:textSize="16sp" android:textColor="#000"
tools:text="# Hello there!" /> android:textSize="16sp" />