Bullet & ordered lists
This commit is contained in:
		
							parent
							
								
									c3b6c1ce39
								
							
						
					
					
						commit
						7f5db84bbe
					
				| @ -13,9 +13,15 @@ | |||||||
| <h1>Yo! | <h1>Yo! | ||||||
| Omg | Omg | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| ddffdg | ddffdg | ||||||
| </h1> | </h1> | ||||||
| 
 | 
 | ||||||
|  | 1. First | ||||||
|  | 2. Second | ||||||
|  | 3. Third | ||||||
|  | * Interesting | ||||||
|  | 4. Forth | ||||||
| 
 | 
 | ||||||
| ## Unordered list | ## Unordered list | ||||||
| 
 | 
 | ||||||
| @ -35,6 +41,41 @@ ddffdg | |||||||
|    * it's also here |    * it's also here | ||||||
|    2. and this |    2. and this | ||||||
|    3. and that |    3. and that | ||||||
|  |       1. Another one nested this time and a lot of text here, well, at least some to check how multiline will be handled | ||||||
|  |          1. And it goes on and on | ||||||
|  |          2. And it goes on and on | ||||||
|  |          3. And it goes on and on | ||||||
|  |          4. And it goes on and on | ||||||
|  |          5. And it goes on and on | ||||||
|  |          6. And it goes on and on | ||||||
|  |          7. And it goes on and on | ||||||
|  |          8. And it goes on and on | ||||||
|  |          9. And it goes on and on | ||||||
|  |          10. And it goes on and on | ||||||
|  |          11. And it goes on and on | ||||||
|  |          12. And it goes on and on | ||||||
|  |          13. And it goes on and on | ||||||
|  |          14. And it goes on and on | ||||||
|  |          15. And it goes on and on | ||||||
|  |          16. And it goes on and on | ||||||
|  |          17. And it goes on and on | ||||||
|  |          18. And it goes on and on | ||||||
|  |          19. And it goes on and on | ||||||
|  |          20. And it goes on and on | ||||||
|  |          21. And it goes on and on | ||||||
|  |          22. And it goes on and on | ||||||
|  |          23. And it goes on and on | ||||||
|  |          24. And it goes on and on | ||||||
|  |          25. And it goes on and on | ||||||
|  |          26. And it goes on and on | ||||||
|  |          27. And it goes on and on | ||||||
|  |          28. And it goes on and on | ||||||
|  |          29. And it goes on and on | ||||||
|  |          30. And it goes on and on | ||||||
|  |          31. And it goes on and on | ||||||
|  |          32. And it goes on and on | ||||||
|  |          33. And it goes on and on | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| ### Quoted list | ### Quoted list | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -7,6 +7,7 @@ import ru.noties.markwon.spans.BlockQuoteSpan; | |||||||
| import ru.noties.markwon.spans.BulletListItemSpan; | import ru.noties.markwon.spans.BulletListItemSpan; | ||||||
| import ru.noties.markwon.spans.CodeSpan; | import ru.noties.markwon.spans.CodeSpan; | ||||||
| import ru.noties.markwon.spans.HeadingSpan; | import ru.noties.markwon.spans.HeadingSpan; | ||||||
|  | import ru.noties.markwon.spans.OrderedListItemSpan; | ||||||
| import ru.noties.markwon.spans.ThematicBreakSpan; | import ru.noties.markwon.spans.ThematicBreakSpan; | ||||||
| 
 | 
 | ||||||
| public class SpannableConfiguration { | public class SpannableConfiguration { | ||||||
| @ -25,6 +26,7 @@ public class SpannableConfiguration { | |||||||
|     private final BulletListItemSpan.Config bulletListConfig; |     private final BulletListItemSpan.Config bulletListConfig; | ||||||
|     private final HeadingSpan.Config headingConfig; |     private final HeadingSpan.Config headingConfig; | ||||||
|     private final ThematicBreakSpan.Config thematicConfig; |     private final ThematicBreakSpan.Config thematicConfig; | ||||||
|  |     private final OrderedListItemSpan.Config orderedListConfig; | ||||||
| 
 | 
 | ||||||
|     private SpannableConfiguration(Builder builder) { |     private SpannableConfiguration(Builder builder) { | ||||||
|         this.blockQuoteConfig = builder.blockQuoteConfig; |         this.blockQuoteConfig = builder.blockQuoteConfig; | ||||||
| @ -32,6 +34,7 @@ public class SpannableConfiguration { | |||||||
|         this.bulletListConfig = builder.bulletListConfig; |         this.bulletListConfig = builder.bulletListConfig; | ||||||
|         this.headingConfig = builder.headingConfig; |         this.headingConfig = builder.headingConfig; | ||||||
|         this.thematicConfig = builder.thematicConfig; |         this.thematicConfig = builder.thematicConfig; | ||||||
|  |         this.orderedListConfig = builder.orderedListConfig; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public BlockQuoteSpan.Config getBlockQuoteConfig() { |     public BlockQuoteSpan.Config getBlockQuoteConfig() { | ||||||
| @ -54,6 +57,10 @@ public class SpannableConfiguration { | |||||||
|         return thematicConfig; |         return thematicConfig; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     public OrderedListItemSpan.Config getOrderedListConfig() { | ||||||
|  |         return orderedListConfig; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     public static class Builder { |     public static class Builder { | ||||||
| 
 | 
 | ||||||
|         private final Context context; |         private final Context context; | ||||||
| @ -62,6 +69,7 @@ public class SpannableConfiguration { | |||||||
|         private BulletListItemSpan.Config bulletListConfig; |         private BulletListItemSpan.Config bulletListConfig; | ||||||
|         private HeadingSpan.Config headingConfig; |         private HeadingSpan.Config headingConfig; | ||||||
|         private ThematicBreakSpan.Config thematicConfig; |         private ThematicBreakSpan.Config thematicConfig; | ||||||
|  |         private OrderedListItemSpan.Config orderedListConfig; | ||||||
| 
 | 
 | ||||||
|         public Builder(Context context) { |         public Builder(Context context) { | ||||||
|             this.context = context; |             this.context = context; | ||||||
| @ -92,11 +100,17 @@ public class SpannableConfiguration { | |||||||
|             return this; |             return this; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         public Builder setOrderedListConfig(@NonNull OrderedListItemSpan.Config orderedListConfig) { | ||||||
|  |             this.orderedListConfig = orderedListConfig; | ||||||
|  |             return this; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         // todo, change to something more reliable |         // 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?) | ||||||
|         public SpannableConfiguration build() { |         public SpannableConfiguration build() { | ||||||
|             if (blockQuoteConfig == null) { |             if (blockQuoteConfig == null) { | ||||||
|                 blockQuoteConfig = new BlockQuoteSpan.Config( |                 blockQuoteConfig = new BlockQuoteSpan.Config( | ||||||
|                         px(16), |                         px(24), | ||||||
|                         0, |                         0, | ||||||
|                         0 |                         0 | ||||||
|                 ); |                 ); | ||||||
| @ -107,7 +121,7 @@ public class SpannableConfiguration { | |||||||
|                         .build(); |                         .build(); | ||||||
|             } |             } | ||||||
|             if (bulletListConfig == null) { |             if (bulletListConfig == null) { | ||||||
|                 bulletListConfig = new BulletListItemSpan.Config(0, px(16), px(1)); |                 bulletListConfig = new BulletListItemSpan.Config(px(24), 0, px(8), px(1)); | ||||||
|             } |             } | ||||||
|             if (headingConfig == null) { |             if (headingConfig == null) { | ||||||
|                 headingConfig = new HeadingSpan.Config(px(1), 0); |                 headingConfig = new HeadingSpan.Config(px(1), 0); | ||||||
| @ -115,6 +129,9 @@ public class SpannableConfiguration { | |||||||
|             if (thematicConfig == null) { |             if (thematicConfig == null) { | ||||||
|                 thematicConfig = new ThematicBreakSpan.Config(0, px(2)); |                 thematicConfig = new ThematicBreakSpan.Config(0, px(2)); | ||||||
|             } |             } | ||||||
|  |             if (orderedListConfig == null) { | ||||||
|  |                 orderedListConfig = new OrderedListItemSpan.Config(px(24), 0); | ||||||
|  |             } | ||||||
|             return new SpannableConfiguration(this); |             return new SpannableConfiguration(this); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -16,7 +16,6 @@ import org.commonmark.node.FencedCodeBlock; | |||||||
| import org.commonmark.node.HardLineBreak; | import org.commonmark.node.HardLineBreak; | ||||||
| import org.commonmark.node.Heading; | import org.commonmark.node.Heading; | ||||||
| import org.commonmark.node.HtmlBlock; | import org.commonmark.node.HtmlBlock; | ||||||
| import org.commonmark.node.Image; |  | ||||||
| import org.commonmark.node.ListBlock; | import org.commonmark.node.ListBlock; | ||||||
| import org.commonmark.node.ListItem; | import org.commonmark.node.ListItem; | ||||||
| import org.commonmark.node.Node; | import org.commonmark.node.Node; | ||||||
| @ -33,6 +32,8 @@ import ru.noties.markwon.spans.BulletListItemSpan; | |||||||
| import ru.noties.markwon.spans.CodeSpan; | import ru.noties.markwon.spans.CodeSpan; | ||||||
| import ru.noties.markwon.spans.EmphasisSpan; | import ru.noties.markwon.spans.EmphasisSpan; | ||||||
| import ru.noties.markwon.spans.HeadingSpan; | import ru.noties.markwon.spans.HeadingSpan; | ||||||
|  | import ru.noties.markwon.spans.OrderedListItemSpan; | ||||||
|  | import ru.noties.markwon.spans.SimpleLeadingMarginSpan; | ||||||
| import ru.noties.markwon.spans.StrongEmphasisSpan; | import ru.noties.markwon.spans.StrongEmphasisSpan; | ||||||
| import ru.noties.markwon.spans.ThematicBreakSpan; | import ru.noties.markwon.spans.ThematicBreakSpan; | ||||||
| 
 | 
 | ||||||
| @ -54,13 +55,13 @@ public class SpannableMarkdownVisitor extends AbstractVisitor { | |||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public void visit(Text text) { |     public void visit(Text text) { | ||||||
|         Debug.i(text); | //        Debug.i(text); | ||||||
|         builder.append(text.getLiteral()); |         builder.append(text.getLiteral()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public void visit(StrongEmphasis strongEmphasis) { |     public void visit(StrongEmphasis strongEmphasis) { | ||||||
|         Debug.i(strongEmphasis); | //        Debug.i(strongEmphasis); | ||||||
|         final int length = builder.length(); |         final int length = builder.length(); | ||||||
|         visitChildren(strongEmphasis); |         visitChildren(strongEmphasis); | ||||||
|         setSpan(length, new StrongEmphasisSpan()); |         setSpan(length, new StrongEmphasisSpan()); | ||||||
| @ -68,7 +69,7 @@ public class SpannableMarkdownVisitor extends AbstractVisitor { | |||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public void visit(Emphasis emphasis) { |     public void visit(Emphasis emphasis) { | ||||||
|         Debug.i(emphasis); | //        Debug.i(emphasis); | ||||||
|         final int length = builder.length(); |         final int length = builder.length(); | ||||||
|         visitChildren(emphasis); |         visitChildren(emphasis); | ||||||
|         setSpan(length, new EmphasisSpan()); |         setSpan(length, new EmphasisSpan()); | ||||||
| @ -77,7 +78,7 @@ public class SpannableMarkdownVisitor extends AbstractVisitor { | |||||||
|     @Override |     @Override | ||||||
|     public void visit(BlockQuote blockQuote) { |     public void visit(BlockQuote blockQuote) { | ||||||
| 
 | 
 | ||||||
|         Debug.i(blockQuote); | //        Debug.i(blockQuote); | ||||||
| 
 | 
 | ||||||
|         newLine(); |         newLine(); | ||||||
|         if (blockQuoteIndent != 0) { |         if (blockQuoteIndent != 0) { | ||||||
| @ -106,7 +107,7 @@ public class SpannableMarkdownVisitor extends AbstractVisitor { | |||||||
|     @Override |     @Override | ||||||
|     public void visit(Code code) { |     public void visit(Code code) { | ||||||
| 
 | 
 | ||||||
|         Debug.i(code); | //        Debug.i(code); | ||||||
| 
 | 
 | ||||||
|         final int length = builder.length(); |         final int length = builder.length(); | ||||||
| 
 | 
 | ||||||
| @ -125,7 +126,7 @@ public class SpannableMarkdownVisitor extends AbstractVisitor { | |||||||
|     @Override |     @Override | ||||||
|     public void visit(FencedCodeBlock fencedCodeBlock) { |     public void visit(FencedCodeBlock fencedCodeBlock) { | ||||||
| 
 | 
 | ||||||
|         Debug.i(fencedCodeBlock); | //        Debug.i(fencedCodeBlock); | ||||||
| 
 | 
 | ||||||
|         newLine(); |         newLine(); | ||||||
| 
 | 
 | ||||||
| @ -141,33 +142,35 @@ public class SpannableMarkdownVisitor extends AbstractVisitor { | |||||||
|         builder.append('\n'); |         builder.append('\n'); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override | //    @Override | ||||||
|     public void visit(Image image) { | //    public void visit(Image image) { | ||||||
| 
 | // | ||||||
|         Debug.i(image); | //        Debug.i(image); | ||||||
| 
 | // | ||||||
|         final int length = builder.length(); | ////        final int length = builder.length(); | ||||||
| 
 | // | ||||||
|         visitChildren(image); | //        visitChildren(image); | ||||||
| 
 | // | ||||||
|         if (length == builder.length()) { | ////        if (length == builder.length()) { | ||||||
|             // nothing is added, and we need at least one symbol | ////            // nothing is added, and we need at least one symbol | ||||||
|             builder.append(' '); | ////            builder.append(' '); | ||||||
|         } | ////        } | ||||||
| 
 | //    } | ||||||
| 
 |  | ||||||
| ////            final int length = builder.length(); |  | ||||||
| //        final TestDrawable drawable = new TestDrawable(); |  | ||||||
| //        final DrawableSpan span = new DrawableSpan(drawable); |  | ||||||
| //        builder.append("  "); |  | ||||||
| //        builder.setSpan(span, length, builder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public void visit(BulletList bulletList) { |     public void visit(BulletList bulletList) { | ||||||
|         Debug.i(bulletList); |         visitList(bulletList); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void visit(OrderedList orderedList) { | ||||||
|  |         visitList(orderedList); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void visitList(Node node) { | ||||||
|  |         Debug.i(node); | ||||||
|         newLine(); |         newLine(); | ||||||
|         visitChildren(bulletList); |         visitChildren(node); | ||||||
|         newLine(); |         newLine(); | ||||||
|         if (listLevel == 0 && blockQuoteIndent == 0) { |         if (listLevel == 0 && blockQuoteIndent == 0) { | ||||||
|             builder.append('\n'); |             builder.append('\n'); | ||||||
| @ -180,16 +183,67 @@ public class SpannableMarkdownVisitor extends AbstractVisitor { | |||||||
|         Debug.i(listItem); |         Debug.i(listItem); | ||||||
| 
 | 
 | ||||||
|         final int length = builder.length(); |         final int length = builder.length(); | ||||||
|  | 
 | ||||||
|         blockQuoteIndent += 1; |         blockQuoteIndent += 1; | ||||||
|         listLevel += 1; |         listLevel += 1; | ||||||
|         visitChildren(listItem); | 
 | ||||||
|         // todo, can be a bullet list & ordered list (with leading numbers... looks like we need to `draw` numbers... |         // todo, can be a bullet list & ordered list (with leading numbers... looks like we need to `draw` numbers... | ||||||
|         setSpan(length, new BulletListItemSpan( | 
 | ||||||
|                 configuration.getBulletListConfig(), |         final Node parent = listItem.getParent(); | ||||||
|                 blockQuoteIndent, |         if (parent instanceof OrderedList) { | ||||||
|                 listLevel - 1, | 
 | ||||||
|                 length | //            // let's build ordered number | ||||||
|         )); | //            final StringBuilder lead = new StringBuilder(); | ||||||
|  | //            Node p = parent; | ||||||
|  | //            while (p != null && p instanceof OrderedList) { | ||||||
|  | //                lead.insert(0, ((OrderedList) p).getDelimiter()); | ||||||
|  | //                lead.insert(0, ((OrderedList) p).getStartNumber()); | ||||||
|  | //                p = p.getParent(); | ||||||
|  | //                if (p instanceof ListItem) { | ||||||
|  | //                    p = p.getParent(); | ||||||
|  | //                } | ||||||
|  | //            } | ||||||
|  | // | ||||||
|  | //            builder.append(lead) | ||||||
|  | //                    .append('\u00a0'); | ||||||
|  | // | ||||||
|  | //            blockQuoteIndent -= 1; | ||||||
|  | 
 | ||||||
|  |             final int start = ((OrderedList) parent).getStartNumber(); | ||||||
|  | 
 | ||||||
|  |             visitChildren(listItem); | ||||||
|  | 
 | ||||||
|  |             setSpan(length, new OrderedListItemSpan( | ||||||
|  |                     configuration.getOrderedListConfig(), | ||||||
|  |                     String.valueOf(start) + "." + '\u00a0', | ||||||
|  |                     blockQuoteIndent, | ||||||
|  |                     length | ||||||
|  |             )); | ||||||
|  | 
 | ||||||
|  | //            blockQuoteIndent += 1; | ||||||
|  | 
 | ||||||
|  | //            if (listLevel != 1) { | ||||||
|  | //                setSpan(length, new SimpleLeadingMarginSpan(32)); | ||||||
|  | //            } | ||||||
|  | 
 | ||||||
|  |             // after we have visited the children increment start number | ||||||
|  |             final OrderedList orderedList = (OrderedList) parent; | ||||||
|  |             orderedList.setStartNumber(orderedList.getStartNumber() + 1); | ||||||
|  | 
 | ||||||
|  |         } else { | ||||||
|  | 
 | ||||||
|  |             visitChildren(listItem); | ||||||
|  | 
 | ||||||
|  |             // if we are inside orderedList increase the margin? | ||||||
|  | 
 | ||||||
|  |             setSpan(length, new BulletListItemSpan( | ||||||
|  |                     configuration.getBulletListConfig(), | ||||||
|  |                     blockQuoteIndent, | ||||||
|  |                     listLevel - 1, | ||||||
|  |                     length | ||||||
|  |             )); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         blockQuoteIndent -= 1; |         blockQuoteIndent -= 1; | ||||||
|         listLevel -= 1; |         listLevel -= 1; | ||||||
| 
 | 
 | ||||||
| @ -199,7 +253,7 @@ public class SpannableMarkdownVisitor extends AbstractVisitor { | |||||||
|     @Override |     @Override | ||||||
|     public void visit(ThematicBreak thematicBreak) { |     public void visit(ThematicBreak thematicBreak) { | ||||||
| 
 | 
 | ||||||
|         Debug.i(thematicBreak); | //        Debug.i(thematicBreak); | ||||||
| 
 | 
 | ||||||
|         newLine(); |         newLine(); | ||||||
| 
 | 
 | ||||||
| @ -211,27 +265,10 @@ public class SpannableMarkdownVisitor extends AbstractVisitor { | |||||||
|         builder.append('\n'); |         builder.append('\n'); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |  | ||||||
|     public void visit(OrderedList orderedList) { |  | ||||||
| 
 |  | ||||||
|         Debug.i(orderedList); |  | ||||||
| 
 |  | ||||||
|         newLine(); |  | ||||||
| 
 |  | ||||||
| //        Debug.i(orderedList, orderedList.getDelimiter(), orderedList.getStartNumber()); |  | ||||||
|         // todo, ordering numbers |  | ||||||
|         super.visit(orderedList); |  | ||||||
| 
 |  | ||||||
|         newLine(); |  | ||||||
|         if (listLevel == 0 && blockQuoteIndent == 0) { |  | ||||||
|             builder.append('\n'); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Override |     @Override | ||||||
|     public void visit(Heading heading) { |     public void visit(Heading heading) { | ||||||
| 
 | 
 | ||||||
|         Debug.i(heading); | //        Debug.i(heading); | ||||||
| 
 | 
 | ||||||
|         newLine(); |         newLine(); | ||||||
| 
 | 
 | ||||||
| @ -264,7 +301,7 @@ public class SpannableMarkdownVisitor extends AbstractVisitor { | |||||||
|     @Override |     @Override | ||||||
|     public void visit(CustomNode customNode) { |     public void visit(CustomNode customNode) { | ||||||
| 
 | 
 | ||||||
|         Debug.i(customNode); | //        Debug.i(customNode); | ||||||
| 
 | 
 | ||||||
|         if (customNode instanceof Strikethrough) { |         if (customNode instanceof Strikethrough) { | ||||||
|             final int length = builder.length(); |             final int length = builder.length(); | ||||||
| @ -280,7 +317,7 @@ public class SpannableMarkdownVisitor extends AbstractVisitor { | |||||||
| 
 | 
 | ||||||
|         final boolean inTightList = isInTightList(paragraph); |         final boolean inTightList = isInTightList(paragraph); | ||||||
| 
 | 
 | ||||||
|         Debug.i(paragraph, inTightList, listLevel); | //        Debug.i(paragraph, inTightList, listLevel); | ||||||
| 
 | 
 | ||||||
|         if (!inTightList) { |         if (!inTightList) { | ||||||
|             newLine(); |             newLine(); | ||||||
| @ -326,4 +363,23 @@ public class SpannableMarkdownVisitor extends AbstractVisitor { | |||||||
|         } |         } | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     private static String dump(Node node) { | ||||||
|  |         final StringBuilder builder = new StringBuilder(); | ||||||
|  |         node.accept(new DumpVisitor(builder)); | ||||||
|  |         return builder.toString(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private static class DumpVisitor extends AbstractVisitor { | ||||||
|  |         private final StringBuilder builder; | ||||||
|  | 
 | ||||||
|  |         DumpVisitor(StringBuilder builder) { | ||||||
|  |             this.builder = builder; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         @Override | ||||||
|  |         public void visit(Text text) { | ||||||
|  |             builder.append(text.getLiteral()); | ||||||
|  |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -17,14 +17,20 @@ public class BulletListItemSpan implements LeadingMarginSpan { | |||||||
| 
 | 
 | ||||||
|     public static class Config { |     public static class Config { | ||||||
| 
 | 
 | ||||||
|         final int bulletColor; // by default uses text color |  | ||||||
|         final int marginWidth; |         final int marginWidth; | ||||||
|  |         final int bulletColor; // by default uses text color | ||||||
|  |         final int bulletSide; | ||||||
|         final int bulletStrokeWidth; |         final int bulletStrokeWidth; | ||||||
| 
 | 
 | ||||||
|         // from 0 but it makes sense to provide something wider |         // from 0 but it makes sense to provide something wider | ||||||
|         public Config(@ColorInt int bulletColor, @IntRange(from = 0) int marginWidth, int bulletStrokeWidth) { |         public Config( | ||||||
|             this.bulletColor = bulletColor; |                 @IntRange(from = 0) int marginWidth, | ||||||
|  |                 @ColorInt int bulletColor, | ||||||
|  |                 @IntRange(from = 0) int bulletSide, | ||||||
|  |                 @IntRange(from = 0) int bulletStrokeWidth) { | ||||||
|             this.marginWidth = marginWidth; |             this.marginWidth = marginWidth; | ||||||
|  |             this.bulletColor = bulletColor; | ||||||
|  |             this.bulletSide = bulletSide; | ||||||
|             this.bulletStrokeWidth = bulletStrokeWidth; |             this.bulletStrokeWidth = bulletStrokeWidth; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -58,7 +64,7 @@ public class BulletListItemSpan implements LeadingMarginSpan { | |||||||
|     @Override |     @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) { |     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 there was a line break, we don't need to draw it |         // if there was a line break, we don't need to draw anything | ||||||
|         if (this.start != start) { |         if (this.start != start) { | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| @ -88,7 +94,14 @@ public class BulletListItemSpan implements LeadingMarginSpan { | |||||||
|             final int width = config.marginWidth; |             final int width = config.marginWidth; | ||||||
|             final int height = bottom - top; |             final int height = bottom - top; | ||||||
| 
 | 
 | ||||||
|             final int side = Math.min(config.marginWidth, height) / 2; |             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 marginLeft = (width - side) / 2; |             final int marginLeft = (width - side) / 2; | ||||||
|             final int marginTop = (height - side) / 2; |             final int marginTop = (height - side) / 2; | ||||||
|  | |||||||
| @ -0,0 +1,66 @@ | |||||||
|  | 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; | ||||||
|  | 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 String number; | ||||||
|  |     private final int blockIndent; | ||||||
|  |     private final int start; | ||||||
|  | 
 | ||||||
|  |     public OrderedListItemSpan( | ||||||
|  |             @NonNull Config config, | ||||||
|  |             @NonNull String number, | ||||||
|  |             @IntRange(from = 0) int blockIndent, | ||||||
|  |             @IntRange(from = 0) int start | ||||||
|  |     ) { | ||||||
|  |         this.config = config; | ||||||
|  |         this.number = number; | ||||||
|  |         this.blockIndent = blockIndent; | ||||||
|  |         this.start = start; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public int getLeadingMargin(boolean first) { | ||||||
|  |         return config.marginWidth; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @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 there was a line break, we don't need to draw anything | ||||||
|  |         if (this.start != start) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (config.numberColor != 0) { | ||||||
|  |             p.setColor(config.numberColor); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         final int width = config.marginWidth; | ||||||
|  |         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); | ||||||
|  | 
 | ||||||
|  |         c.drawText(number, numberX, numberY, p); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,25 @@ | |||||||
|  | package ru.noties.markwon.spans; | ||||||
|  | 
 | ||||||
|  | import android.graphics.Canvas; | ||||||
|  | import android.graphics.Paint; | ||||||
|  | import android.text.Layout; | ||||||
|  | import android.text.style.LeadingMarginSpan; | ||||||
|  | 
 | ||||||
|  | public class SimpleLeadingMarginSpan implements LeadingMarginSpan { | ||||||
|  | 
 | ||||||
|  |     private final int margin; | ||||||
|  | 
 | ||||||
|  |     public SimpleLeadingMarginSpan(int margin) { | ||||||
|  |         this.margin = margin; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public int getLeadingMargin(boolean first) { | ||||||
|  |         return margin; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @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) { | ||||||
|  |         // no op | ||||||
|  |     } | ||||||
|  | } | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Dimitry Ivanov
						Dimitry Ivanov