package ru.noties.markwon.recycler; import android.support.annotation.NonNull; import android.util.SparseArray; import android.view.LayoutInflater; import android.view.ViewGroup; import org.commonmark.node.Node; import java.util.Collections; import java.util.List; import ru.noties.markwon.Markwon; import ru.noties.markwon.MarkwonReducer; class MarkwonAdapterImpl extends MarkwonAdapter { private final SparseArray> entries; private final Entry defaultEntry; private final MarkwonReducer reducer; private LayoutInflater layoutInflater; private Markwon markwon; private List nodes; @SuppressWarnings("WeakerAccess") MarkwonAdapterImpl( @NonNull SparseArray> entries, @NonNull Entry defaultEntry, @NonNull MarkwonReducer reducer) { this.entries = entries; this.defaultEntry = defaultEntry; this.reducer = reducer; setHasStableIds(true); } @Override public void setMarkdown(@NonNull Markwon markwon, @NonNull String markdown) { setParsedMarkdown(markwon, markwon.parse(markdown)); } @Override public void setParsedMarkdown(@NonNull Markwon markwon, @NonNull Node document) { setParsedMarkdown(markwon, reducer.reduce(document)); } @Override public void setParsedMarkdown(@NonNull Markwon markwon, @NonNull List nodes) { // clear all entries before applying defaultEntry.clear(); for (int i = 0, size = entries.size(); i < size; i++) { entries.valueAt(i).clear(); } this.markwon = markwon; this.nodes = nodes; } @NonNull @Override public Holder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { if (layoutInflater == null) { layoutInflater = LayoutInflater.from(parent.getContext()); } final Entry entry = getEntry(viewType); return entry.createHolder(layoutInflater, parent); } @Override public void onBindViewHolder(@NonNull Holder holder, int position) { final Node node = nodes.get(position); final int viewType = getNodeViewType(node.getClass()); final Entry entry = getEntry(viewType); entry.bindHolder(markwon, holder, node); } @Override public int getItemCount() { return nodes != null ? nodes.size() : 0; } @Override public void onViewRecycled(@NonNull Holder holder) { super.onViewRecycled(holder); final Entry entry = getEntry(holder.getItemViewType()); entry.onViewRecycled(holder); } @SuppressWarnings("unused") @NonNull public List getItems() { return nodes != null ? Collections.unmodifiableList(nodes) : Collections.emptyList(); } @Override public int getItemViewType(int position) { return getNodeViewType(nodes.get(position).getClass()); } @Override public long getItemId(int position) { final Node node = nodes.get(position); final int type = getNodeViewType(node.getClass()); final Entry entry = getEntry(type); return entry.id(node); } @Override public int getNodeViewType(@NonNull Class node) { // if has registered -> then return it, else 0 final int hash = node.hashCode(); if (entries.indexOfKey(hash) > -1) { return hash; } return 0; } @NonNull private Entry getEntry(int viewType) { return viewType == 0 ? defaultEntry : entries.get(viewType); } static class BuilderImpl implements Builder { private final SparseArray> entries = new SparseArray<>(3); private final Entry defaultEntry; private MarkwonReducer reducer; BuilderImpl(@NonNull Entry defaultEntry) { this.defaultEntry = defaultEntry; } @NonNull @Override public Builder include( @NonNull Class node, @NonNull Entry entry) { //noinspection unchecked entries.append(node.hashCode(), (Entry) entry); return this; } @NonNull @Override public Builder reducer(@NonNull MarkwonReducer reducer) { this.reducer = reducer; return this; } @NonNull @Override public MarkwonAdapter build() { if (reducer == null) { reducer = MarkwonReducer.directChildren(); } return new MarkwonAdapterImpl(entries, defaultEntry, reducer); } } }