Apply ToggleTaskListSpan only for areas without ClickableSpan

Signed-off-by: Stefan Niedermann <info@niedermann.it>
This commit is contained in:
Stefan Niedermann 2021-06-13 11:51:48 +02:00
parent db3513961c
commit f2c3883dfe

View file

@ -6,7 +6,13 @@ import android.util.Range;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import org.commonmark.node.AbstractVisitor;
import org.commonmark.node.Block;
import org.commonmark.node.HardLineBreak;
import org.commonmark.node.Node; import org.commonmark.node.Node;
import org.commonmark.node.Paragraph;
import org.commonmark.node.SoftLineBreak;
import org.commonmark.node.Text;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@ -46,6 +52,9 @@ public class ToggleableTaskListPlugin extends AbstractMarkwonPlugin {
this.enabled.set(enabled); this.enabled.set(enabled);
} }
/**
* Prepares {@link TaskListSpan}s and marks each one with a {@link ToggleMarkerSpan} in the first step.
*/
@Override @Override
public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) { public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) {
builder.on(TaskListItem.class, (visitor, node) -> { builder.on(TaskListItem.class, (visitor, node) -> {
@ -57,6 +66,30 @@ public class ToggleableTaskListPlugin extends AbstractMarkwonPlugin {
.get(TaskListItem.class); .get(TaskListItem.class);
final Object spans = spanFactory == null ? null : final Object spans = spanFactory == null ? null :
spanFactory.getSpans(visitor.configuration(), visitor.renderProps()); spanFactory.getSpans(visitor.configuration(), visitor.renderProps());
if (spans != null) {
final TaskListSpan taskListSpan;
if (spans instanceof TaskListSpan[]) {
if (((TaskListSpan[]) spans).length > 0) {
taskListSpan = ((TaskListSpan[]) spans)[0];
} else {
taskListSpan = null;
}
} else if (spans instanceof TaskListSpan) {
taskListSpan = (TaskListSpan) spans;
} else {
taskListSpan = null;
}
final int content = TaskListContextVisitor.contentLength(node);
if (content > 0 && taskListSpan != null) {
// maybe additionally identify this task list (for persistence)
visitor.builder().setSpan(
new ToggleMarkerSpan(taskListSpan),
length,
length + content
);
}
}
SpannableBuilder.setSpans( SpannableBuilder.setSpans(
visitor.builder(), visitor.builder(),
spans, spans,
@ -70,29 +103,31 @@ public class ToggleableTaskListPlugin extends AbstractMarkwonPlugin {
}); });
} }
/**
* Converts all {@link ToggleMarkerSpan}s to actual {@link ToggleTaskListSpan}s respecting existing {@link ClickableSpan}s.
*/
@Override @Override
public void afterRender(@NonNull Node node, @NonNull MarkwonVisitor visitor) { public void afterRender(@NonNull Node node, @NonNull MarkwonVisitor visitor) {
super.afterRender(node, visitor); super.afterRender(node, visitor);
final Spannable spanned = visitor.builder().spannableStringBuilder(); final Spannable spanned = visitor.builder().spannableStringBuilder();
final List<SpannableBuilder.Span> spans = visitor.builder().getSpans(0, visitor.builder().length()); final List<ToggleMarkerSpan> markerSpans = visitor.builder().getSpans(0, visitor.builder().length())
final List<TaskListSpan> taskListSpans = spans.stream() .stream()
.filter(span -> span.what instanceof TaskListSpan) .filter(span -> span.what instanceof ToggleMarkerSpan)
.map(span -> ((TaskListSpan) span.what)) .map(span -> ((ToggleMarkerSpan) span.what))
.sorted((o1, o2) -> spanned.getSpanStart(o1) - spanned.getSpanStart(o2)) .sorted((o1, o2) -> spanned.getSpanStart(o1) - spanned.getSpanStart(o2))
.collect(Collectors.toList()); .collect(Collectors.toList());
for (int position = 0; position < taskListSpans.size(); position++) { for (int position = 0; position < markerSpans.size(); position++) {
final TaskListSpan taskListSpan = taskListSpans.get(position); final ToggleMarkerSpan markerSpan = markerSpans.get(position);
final int start = spanned.getSpanStart(taskListSpan); final int start = spanned.getSpanStart(markerSpan);
// final int contentLength = TaskListContextVisitor.contentLength(node); final int end = spanned.getSpanEnd(markerSpan);
// final int end = start + contentLength;
final int end = spanned.getSpanEnd(taskListSpan);
final List<Range<Integer>> freeRanges = findFreeRanges(spanned, start, end); final List<Range<Integer>> freeRanges = findFreeRanges(spanned, start, end);
for (Range<Integer> freeRange : freeRanges) { for (Range<Integer> freeRange : freeRanges) {
visitor.builder().setSpan( visitor.builder().setSpan(
new ToggleTaskListSpan(enabled, toggleListener, taskListSpan, position), new ToggleTaskListSpan(enabled, toggleListener, markerSpan.getTaskListSpan(), position),
freeRange.getLower(), freeRange.getUpper()); freeRange.getLower(), freeRange.getUpper());
} }
spanned.removeSpan(markerSpan);
} }
} }
@ -133,48 +168,66 @@ public class ToggleableTaskListPlugin extends AbstractMarkwonPlugin {
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
// static class TaskListContextVisitor extends AbstractVisitor { private static final class TaskListContextVisitor extends AbstractVisitor {
// private int contentLength = 0; private int contentLength = 0;
//
// static int contentLength(Node node) { static int contentLength(Node node) {
// final TaskListContextVisitor visitor = new TaskListContextVisitor(); final TaskListContextVisitor visitor = new TaskListContextVisitor();
// visitor.visitChildren(node); visitor.visitChildren(node);
// return visitor.contentLength; return visitor.contentLength;
// } }
//
// @Override @Override
// public void visit(Text text) { public void visit(Text text) {
// super.visit(text); super.visit(text);
// contentLength += text.getLiteral().length(); contentLength += text.getLiteral().length();
// } }
//
// // NB! if count both soft and hard breaks as having length of 1 // NB! if count both soft and hard breaks as having length of 1
// @Override @Override
// public void visit(SoftLineBreak softLineBreak) { public void visit(SoftLineBreak softLineBreak) {
// super.visit(softLineBreak); super.visit(softLineBreak);
// contentLength += 1; contentLength += 1;
// } }
//
// // NB! if count both soft and hard breaks as having length of 1 // NB! if count both soft and hard breaks as having length of 1
// @Override @Override
// public void visit(HardLineBreak hardLineBreak) { public void visit(HardLineBreak hardLineBreak) {
// super.visit(hardLineBreak); super.visit(hardLineBreak);
// contentLength += 1; contentLength += 1;
// } }
//
// @Override @Override
// protected void visitChildren(Node parent) { protected void visitChildren(Node parent) {
// Node node = parent.getFirstChild(); Node node = parent.getFirstChild();
// while (node != null) { while (node != null) {
// // A subclass of this visitor might modify the node, resulting in getNext returning a different node or no // A subclass of this visitor might modify the node, resulting in getNext returning a different node or no
// // node after visiting it. So get the next node before visiting. // node after visiting it. So get the next node before visiting.
// Node next = node.getNext(); Node next = node.getNext();
// if (node instanceof Block && !(node instanceof Paragraph)) { if (node instanceof Block && !(node instanceof Paragraph)) {
// break; break;
// } }
// node.accept(this); node.accept(this);
// node = next; node = next;
// } }
// } }
// } }
/**
* Helper class which holds an {@link TaskListSpan} but does not include the range of child {@link TaskListSpan}s.
*/
private static final class ToggleMarkerSpan {
@NonNull
private final TaskListSpan taskListSpan;
private ToggleMarkerSpan(@NonNull TaskListSpan taskListSpan) {
this.taskListSpan = taskListSpan;
}
@NonNull
private TaskListSpan getTaskListSpan() {
return taskListSpan;
}
}
} }