@Override protected Object[] getReplaces(final Editable text, final int indentation) { // Nested BulletSpans increases distance between BULLET_SPAN and text, so we must prevent it. int bulletMargin = INDENT_PX; if (indentation > 1) { bulletMargin = INDENT_PX - BULLET_SPAN.getLeadingMargin(true); if (indentation > 2) { // This get's more complicated when we add a LeadingMarginSpan into the same line: // we have also counter it's effect to BulletSpan bulletMargin -= (indentation - 2) * LIST_ITEM_INDENT_PX; } } return new Object[]{ new LeadingMarginSpan.Standard(LIST_ITEM_INDENT_PX * (indentation - 1)), new BulletSpan(bulletMargin) }; }
@Test public void testSubList() throws Exception { String content = "* item 1\n" + "* item 2\n" + " * sublist item 1\n" + " * sublist item 2\n"; Spanned result = Markdown.fromMarkdown(content); printSpans(result); Object[] spans = result.getSpans(0, result.length(), Object.class); assertEquals(8, spans.length); assertEquals(LeadingMarginSpan.Standard.class, spans[0].getClass()); assertEquals(BulletSpan.class, spans[1].getClass()); assertEquals(LeadingMarginSpan.Standard.class, spans[2].getClass()); assertEquals(BulletSpan.class, spans[3].getClass()); assertEquals(LeadingMarginSpan.Standard.class, spans[4].getClass()); assertEquals(BulletSpan.class, spans[5].getClass()); assertEquals(LeadingMarginSpan.Standard.class, spans[6].getClass()); assertEquals(BulletSpan.class, spans[7].getClass()); }
protected boolean containBullet(int index) { String[] lines = TextUtils.split(getEditableText().toString(), "\n"); if (index < 0 || index >= lines.length) { return false; } int start = 0; for (int i = 0; i < index; i++) { start = start + lines[i].length() + 1; } int end = start + lines[index].length(); if (start >= end) { return false; } BulletSpan[] spans = getEditableText().getSpans(start, end, BulletSpan.class); return spans.length > 0; }
@Override public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader) { if (opening) { if (tag.equalsIgnoreCase(BULLET_LI)) { if (output.length() > 0 && output.charAt(output.length() - 1) != '\n') { output.append("\n"); } start(output, new Li()); } else if (tag.equalsIgnoreCase(STRIKETHROUGH_S) || tag.equalsIgnoreCase(STRIKETHROUGH_STRIKE) || tag.equalsIgnoreCase(STRIKETHROUGH_DEL)) { start(output, new Strike()); } } else { if (tag.equalsIgnoreCase(BULLET_LI)) { if (output.length() > 0 && output.charAt(output.length() - 1) != '\n') { output.append("\n"); } end(output, Li.class, new BulletSpan()); } else if (tag.equalsIgnoreCase(STRIKETHROUGH_S) || tag.equalsIgnoreCase(STRIKETHROUGH_STRIKE) || tag.equalsIgnoreCase(STRIKETHROUGH_DEL)) { end(output, Strike.class, new StrikethroughSpan()); } } }
private CharSequence buildDialogText(@NonNull Context context, @StringRes int intro, @StringRes int bullet1, @StringRes int bullet2, @StringRes int bullet3, @ColorInt int color) { SpannableStringBuilder ssb = new SpannableStringBuilder(context.getString(intro)); int padding = context.getResources().getDimensionPixelSize(R.dimen.padding_normal); ssb.append("\n\n"); ssb.append(context.getString(bullet1), new BulletSpan(padding, color), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); ssb.append("\n\n"); ssb.append(context.getString(bullet2), new BulletSpan(padding, color), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); ssb.append("\n\n"); ssb.append(context.getString(bullet3), new BulletSpan(padding, color), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); return ssb; }
@Override public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader) { switch (tag) { case "pre": case "PRE": ensureParagraphBoundary(output); break; // Unfortunately the following code will be ignored in API 24+ and the native rendering is inferior case "li": case "LI": if (opening) { liStarts.addLast(ensureParagraphBoundary(output)); } else if (!liStarts.isEmpty()) { int start = liStarts.popLast(); trimStart(output, start); int end = ensureParagraphBoundary(output); // Add leading margin to ensure the bullet is not cut off output.setSpan(new LeadingMarginSpan.Standard(leadingMargin), start, end, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); output.setSpan(new BulletSpan(bulletGapWidth), start, end, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); } break; } }
@SuppressWarnings("checkstyle:magicnumber") private void init(@NonNull String qNumber) { inflate(getContext(), R.layout.view_description_edit_revert_help, this); ButterKnife.bind(this); helpText.setMovementMethod(new LinkMovementMethod()); Spanned helpStr = StringUtil.fromHtml(getString(R.string.description_edit_revert_help_body) .replaceAll(":revertSubtitle", getString(R.string.description_edit_revert_subtitle)) .replaceAll(":revertIntro", getString(R.string.description_edit_revert_intro)) .replaceAll(":revertHistory", String.format(getString(R.string.description_edit_revert_history), getHistoryUri(qNumber)))); int gapWidth = DimenUtil.roundedDpToPx(8); SpannableString revertReason1 = new SpannableString(StringUtil.fromHtml(String.format(getString(R.string.description_edit_revert_reason1), getString(R.string.wikidata_description_guide_url)))); SpannableString revertReason2 = new SpannableString(StringUtil.fromHtml(getString(R.string.description_edit_revert_reason2))); revertReason1.setSpan(new BulletSpan(gapWidth), 0, revertReason1.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); revertReason2.setSpan(new BulletSpan(gapWidth), 0, revertReason2.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); SpannableString helpSpan = new SpannableString(TextUtils.expandTemplate(helpStr, revertReason1, revertReason2)); helpText.setText(helpSpan); }
private void handleULTag(Editable output) { if(output.length() > 0 && output.charAt(output.length() - 1) != '\n') { output.append("\n"); } if(mLists.peek().second) { //Check for checkboxes if(output.length() > 2 && ((output.charAt(0) >= '\u2610' && output.charAt(0) <= '\u2612') || (output.charAt(1) >= '\u2610' && output .charAt(1) <= '\u2612') )) { end(output, Ul.class, false, new LeadingMarginSpan.Standard( mListIndent * (mLists.size() - 1)) ); } else { end(output, Ul.class, false, new LeadingMarginSpan.Standard( mListIndent * (mLists.size() - 1)), new BulletSpan(mSingleIndent) ); } } else { end(output, Ul.class, false, new LeadingMarginSpan.Standard(mListIndent * (mLists.size() - 1)) ); } }
public TextDecorator insertBullet(final int gapWidth, @ColorRes final int colorResId, final int start, final int end) { checkIndexOutOfBoundsException(start, end); decoratedContent.setSpan(new BulletSpan(gapWidth, ContextCompat.getColor(textView.getContext(), colorResId)), start, end, flags); return this; }
@Test public void testListAsterisk() throws Exception { String content = " * item1\n" + " * item2"; Spanned result = Markdown.fromMarkdown(content); printSpans(result); Object[] spans = result.getSpans(0, result.length(), Object.class); assertEquals(4, spans.length); assertEquals(LeadingMarginSpan.Standard.class, spans[0].getClass()); assertEquals(BulletSpan.class, spans[1].getClass()); assertEquals(LeadingMarginSpan.Standard.class, spans[2].getClass()); assertEquals(BulletSpan.class, spans[3].getClass()); }
@Test public void testListMinus() throws Exception { String content = " * item1\n" + " * item2"; Spanned result = Markdown.fromMarkdown(content); printSpans(result); Object[] spans = result.getSpans(0, result.length(), Object.class); assertEquals(4, spans.length); assertEquals(LeadingMarginSpan.Standard.class, spans[0].getClass()); assertEquals(BulletSpan.class, spans[1].getClass()); assertEquals(LeadingMarginSpan.Standard.class, spans[2].getClass()); assertEquals(BulletSpan.class, spans[3].getClass()); }
@Test public void testListPlus() throws Exception { String content = " * item1\n" + " * item2"; Spanned result = Markdown.fromMarkdown(content); printSpans(result); Object[] spans = result.getSpans(0, result.length(), Object.class); assertEquals(4, spans.length); assertEquals(LeadingMarginSpan.Standard.class, spans[0].getClass()); assertEquals(BulletSpan.class, spans[1].getClass()); assertEquals(LeadingMarginSpan.Standard.class, spans[2].getClass()); assertEquals(BulletSpan.class, spans[3].getClass()); }
@Override public SpannableStringBuilder ul(CharSequence charSequence, int level) { SpannableStringBuilder spannableStringBuilder = SpannableStringBuilder.valueOf(charSequence); BulletSpan bulletSpan = new MarkDownBulletSpan(level, h1_text_color, 0); spannableStringBuilder.setSpan(bulletSpan, 0, spannableStringBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); return spannableStringBuilder; }
@Override public SpannableStringBuilder ol(CharSequence charSequence, int level, int index) { SpannableStringBuilder spannableStringBuilder = SpannableStringBuilder.valueOf(charSequence); BulletSpan bulletSpan = new MarkDownBulletSpan(level, h1_text_color, index); spannableStringBuilder.setSpan(bulletSpan, 0, spannableStringBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); return spannableStringBuilder; }
/** * Parse any bulleted lists in the text and apply a bulleted list formatting to the list items */ private void parseBulletLists(){ for (int start = indexOf(builder, BULLET_LIST), end = indexOf(builder, "\n", start); start != -1; start = indexOf(builder, BULLET_LIST, end), end = indexOf(builder, "\n", start)){ //If the last thing in the text is a list item then go to the end if (end == -1){ end = builder.length() - 1; } builder.setSpan(new BulletSpan(BulletSpan.STANDARD_GAP_WIDTH), start + BULLET_LIST.length(), end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); builder.delete(start, start + BULLET_LIST.length()); //Account for the shorter length of the text with the tag removed end -= BULLET_LIST.length(); } }
private void writeSingleParagraphStyle(ParagraphStyle style, DataOutputStream dos) throws IOException { Class clazz = style.getClass(); dos.writeInt(mString.getSpanStart(style)); dos.writeInt(mString.getSpanEnd(style)); dos.writeInt(mString.getSpanFlags(style)); if (mCharacterStylesTags.containsKey(clazz.getSimpleName())) { int tag = mCharacterStylesTags.get(clazz.getSimpleName()); if (mCharacterStylesTags.containsKey(clazz.getSimpleName())) { dos.writeInt(tag); } switch (tag) { case 24: // AligmentSpan.Standard AlignmentSpan.Standard as2 = (AlignmentSpan.Standard)style; dos.writeInt(as2.getAlignment().ordinal()); break; case 25: // BulletSpan BulletSpan bs = (BulletSpan)style; dos.writeInt(bs.getLeadingMargin(true)); dos.writeInt(bs.getLeadingMargin(false)); break; case 30: // LeadingMarginSpan.Sandard LeadingMarginSpan.Standard lms = (LeadingMarginSpan.Standard)style; dos.writeInt(lms.getLeadingMargin(true)); dos.writeInt(lms.getLeadingMargin(false)); break; case 34: // QuoteSpan QuoteSpan qs = (QuoteSpan)style; dos.writeInt(qs.getColor()); break; case 36: // TabStopSpan.Standard TabStopSpan.Standard tss = (TabStopSpan.Standard)style; dos.writeInt(tss.getTabStop()); break; default: } } else { write(style,dos); } }
private SpanPlacementInfo readSingleParagraph(DataInputStream dis) throws IOException { SpanPlacementInfo spi = new SpanPlacementInfo(); spi.start = dis.readInt(); spi.end = dis.readInt(); spi.mode = dis.readInt(); int tag = dis.readInt(); // mCharacterStylesTags.get(clazz.getSimpleName()); switch (tag) { case 24: // AligmentSpan.Standard spi.span = new AlignmentSpan.Standard(Alignment.values()[dis.readInt()]); break; case 25: // BulletSpan spi.span = new BulletSpan(dis.readInt()); dis.readInt(); // skip gap width for other lines break; case 30: // LeadingMarginSpan.Sandard spi.span = new LeadingMarginSpan.Standard(dis.readInt(),dis.readInt()); break; case 34: // QuoteSpan spi.span = new QuoteSpan(dis.readInt()); break; case 36: // TabStopSpan.Standard spi.span = new TabStopSpan.Standard(dis.readInt()); break; case 80: // RemoteDrawableSpan break; default: spi.span = read(tag,dis); } return spi; }
/** * @param element Resource ID of the element to be populated with the bulletpoints. * @param content String ID to serve as the text of |element|. Must contain an <em></em> span, * which will be emphasized, and three <li> items, which will be converted to * bulletpoints. * Populates |element| with |content|. */ private void populateBulletpoints(@IdRes int element, @StringRes int content) { TextView view = (TextView) findViewById(element); String text = mContext.getResources().getString(content); // TODO(msramek): Unfortunately, our strings are missing the closing "</li>" tag, which // is not a problem when they're used in the Desktop WebUI (omitting the tag is valid in // HTML5), but it is a problem for SpanApplier. Update the strings and remove this regex. // Note that modifying the strings is a non-trivial operation as they went through a special // translation process. text = text.replaceAll("<li>([^<]+)\n", "<li>$1</li>\n"); // Disambiguate the <li><li> spans for SpanApplier. text = text.replaceFirst("<li>(.*)</li>", "<li1>$1</li1>"); text = text.replaceFirst("<li>(.*)</li>", "<li2>$1</li2>"); text = text.replaceFirst("<li>(.*)</li>", "<li3>$1</li3>"); // Remove the <ul></ul> tags which serve no purpose here. text = text.replaceAll("</?ul>", ""); view.setText(SpanApplier.applySpans(text, new SpanApplier.SpanInfo("<em>", "</em>", new ForegroundColorSpan(ApiCompatibilityUtils.getColor( mContext.getResources(), R.color.incognito_emphasis))), new SpanApplier.SpanInfo("<li1>", "</li1>", new BulletSpan()), new SpanApplier.SpanInfo("<li2>", "</li2>", new BulletSpan()), new SpanApplier.SpanInfo("<li3>", "</li3>", new BulletSpan()))); }
protected void bulletInvalid() { String[] lines = TextUtils.split(getEditableText().toString(), "\n"); for (int i = 0; i < lines.length; i++) { if (!containBullet(i)) { continue; } int lineStart = 0; for (int j = 0; j < i; j++) { lineStart = lineStart + lines[j].length() + 1; } int lineEnd = lineStart + lines[i].length(); if (lineStart >= lineEnd) { continue; } int bulletStart = 0; int bulletEnd = 0; if (lineStart <= getSelectionStart() && getSelectionEnd() <= lineEnd) { bulletStart = lineStart; bulletEnd = lineEnd; } else if (getSelectionStart() <= lineStart && lineEnd <= getSelectionEnd()) { bulletStart = lineStart; bulletEnd = lineEnd; } if (bulletStart < bulletEnd) { BulletSpan[] spans = getEditableText().getSpans(bulletStart, bulletEnd, BulletSpan.class); for (BulletSpan span : spans) { getEditableText().removeSpan(span); } } } }
private static void withinHtml(StringBuilder out, Spanned text) { int next; for (int i = 0; i < text.length(); i = next) { next = text.nextSpanTransition(i, text.length(), ParagraphStyle.class); ParagraphStyle[] styles = text.getSpans(i, next, ParagraphStyle.class); if (styles.length == 2) { if (styles[0] instanceof BulletSpan && styles[1] instanceof QuoteSpan) { // Let a <br> follow the BulletSpan or QuoteSpan end, so next++ withinBulletThenQuote(out, text, i, next++); } else if (styles[0] instanceof QuoteSpan && styles[1] instanceof BulletSpan) { withinQuoteThenBullet(out, text, i, next++); } else { withinContent(out, text, i, next); } } else if (styles.length == 1) { if (styles[0] instanceof BulletSpan) { withinBullet(out, text, i, next++); } else if (styles[0] instanceof QuoteSpan) { withinQuote(out, text, i, next++); } else { withinContent(out, text, i, next); } } else { withinContent(out, text, i, next); } } }
public void appendList(String header, String[] items) { sb.append("\n\n"); appendSpan(header + ":", new StyleSpan(Typeface.BOLD)); //Log.v("FTB-list-header", header); for (String item : items) { //Log.v("FTB-list-item", item); sb.append("\n"); appendSpan(item, new BulletSpan()); } }
private CharSequence getBulletSpanMessage(String[] subMessageArray) { CharSequence subMessage = ""; for(String subMessageItem: subMessageArray){ SpannableString spannableString = new SpannableString(subMessageItem+"\n"); spannableString.setSpan(new BulletSpan(15), 0, subMessageItem.length(), 0); subMessage = TextUtils.concat(subMessage, spannableString); } return subMessage; }
public static Node bullet(Object... nodes) { return new SpanNode(new BulletSpan(), nodes); }
public static Node bullet(@Px Integer gapWidth, Object... nodes) { return new SpanNode(new BulletSpan(gapWidth), nodes); }
public static Node bullet(Integer gapWidth, @ColorInt Integer color, Object... nodes) { return new SpanNode(new BulletSpan(gapWidth, color), nodes); }
private static void withinBlockquoteIndividual(Context context, StringBuilder out, Spanned text, int start, int end) { boolean isInList = false; int next; for (int i = start; i <= end; i = next) { next = TextUtils.indexOf(text, '\n', i, end); if (next < 0) { next = end; } if (next == i) { if (isInList) { // Current paragraph is no longer a list item; close the previously opened list isInList = false; out.append("</ul>\n"); } out.append("<br>\n"); } else { boolean isListItem = false; ParagraphStyle[] paragraphStyles = text.getSpans(i, next, ParagraphStyle.class); for (ParagraphStyle paragraphStyle : paragraphStyles) { final int spanFlags = text.getSpanFlags(paragraphStyle); if ((spanFlags & Spanned.SPAN_PARAGRAPH) == Spanned.SPAN_PARAGRAPH && paragraphStyle instanceof BulletSpan) { isListItem = true; break; } } if (isListItem && !isInList) { // Current paragraph is the first item in a list isInList = true; out.append("<ul") .append(getTextStyles(text, i, next, true, false)) .append(">\n"); } if (isInList && !isListItem) { // Current paragraph is no longer a list item; close the previously opened list isInList = false; out.append("</ul>\n"); } String tagType = isListItem ? "li" : "p"; out.append("<").append(tagType) .append(getTextDirection(text, i, next)) .append(getTextStyles(text, i, next, !isListItem, true)) .append(">"); withinParagraph(context, out, text, i, next); out.append("</"); out.append(tagType); out.append(">\n"); if (next == end && isInList) { isInList = false; out.append("</ul>\n"); } } next++; } }
private void endLi(String tag, Editable text) { endCssStyle(tag, text); endBlockElement(tag, text); end(tag, text, Bullet.class, new BulletSpan()); }
public StyledText setBulletSymbol(int color,int start,int end){ setSpan(new BulletSpan(BulletSpan.STANDARD_GAP_WIDTH,color), start,end,SPAN_EXCLUSIVE_EXCLUSIVE); return this; }
private static void withinBlockquoteIndividual(StringBuilder out, Spanned text, int start, int end) { boolean isInList = false; int next; for (int i = start; i <= end; i = next) { next = TextUtils.indexOf(text, '\n', i, end); if (next < 0) { next = end; } if (next == i) { if (isInList) { // Current paragraph is no longer a list item; close the previously opened list isInList = false; out.append("</ul>\n"); } out.append("<br>\n"); } else { boolean isListItem = false; ParagraphStyle[] paragraphStyles = text.getSpans(i, next, ParagraphStyle.class); for (ParagraphStyle paragraphStyle : paragraphStyles) { final int spanFlags = text.getSpanFlags(paragraphStyle); if ((spanFlags & Spanned.SPAN_PARAGRAPH) == Spanned.SPAN_PARAGRAPH && paragraphStyle instanceof BulletSpan) { isListItem = true; break; } } if (isListItem && !isInList) { // Current paragraph is the first item in a list isInList = true; out.append("<ul") .append(getTextStyles(text, i, next, true, false)) .append(">\n"); } if (isInList && !isListItem) { // Current paragraph is no longer a list item; close the previously opened list isInList = false; out.append("</ul>\n"); } String tagType = isListItem ? "li" : "p"; out.append("<").append(tagType) .append(getTextDirection(text, i, next)) .append(getTextStyles(text, i, next, !isListItem, true)) .append(">"); withinParagraph(out, text, i, next); out.append("</"); out.append(tagType); out.append(">\n"); if (next == end && isInList) { isInList = false; out.append("</ul>\n"); } } next++; } }
private static void endLi(Editable text) { endCssStyle(text); endBlockElement(text); end(text, Bullet.class, new BulletSpan()); }
public TextDecorator insertBullet(final int start, final int end) { checkIndexOutOfBoundsException(start, end); decoratedContent.setSpan(new BulletSpan(), start, end, flags); return this; }
public TextDecorator insertBullet(final int gapWidth, final int start, final int end) { checkIndexOutOfBoundsException(start, end); decoratedContent.setSpan(new BulletSpan(gapWidth), start, end, flags); return this; }
public void setBulletText(TextView textView, String text) { SpannableString spannable = new SpannableString(text); spannable.setSpan(new BulletSpan(16), 0, text.length(), 0); textView.setText(spannable); }
@Override public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader){ if (tag.equalsIgnoreCase("ul")){ if (opening){ lists.push(tag); } else { lists.pop(); } } else if (tag.equalsIgnoreCase("ol")){ if (opening){ lists.push(tag); olNextIndex.push(1); } else { lists.pop(); olNextIndex.pop(); } } else if (tag.equalsIgnoreCase("li")){ if (opening){ if (output.length() > 0 && output.charAt(output.length() - 1) != '\n'){ output.append("\n"); } String parentList = lists.peek(); if (parentList.equalsIgnoreCase("ol")){ start(output, new Ol()); output.append(olNextIndex.peek().toString()).append(". "); olNextIndex.push(olNextIndex.pop() + 1); } else if (parentList.equalsIgnoreCase("ul")){ start(output, new Ul()); } } else { if (lists.peek().equalsIgnoreCase("ul")){ if (output.charAt(output.length() - 1) != '\n'){ output.append("\n"); } // Nested BulletSpans increases distance between bullet and text, so we must prevent it. int bulletMargin = indent; if (lists.size() > 1){ bulletMargin = indent - bullet.getLeadingMargin(true); if (lists.size() > 2){ // This gets more complicated when we add a LeadingMarginSpan into the same line: // we have also counter it's effect to BulletSpan bulletMargin -= (lists.size() - 2) * listItemIndent; } } BulletSpan newBullet = new BulletSpan(bulletMargin); end(output, Ul.class, new LeadingMarginSpan.Standard(listItemIndent * (lists.size() - 1)), newBullet); } else if (lists.peek().equalsIgnoreCase("ol")){ if (output.charAt(output.length() - 1) != '\n'){ output.append("\n"); } int numberMargin = listItemIndent * (lists.size() - 1); if (lists.size() > 2){ // Same as in ordered lists: counter the effect of nested Spans numberMargin -= (lists.size() - 2) * listItemIndent; } end(output, Ol.class, new LeadingMarginSpan.Standard(numberMargin)); } } } else { if (opening){ Log.d("TagHandler", "Found an unsupported tag " + tag); } } }
@Override public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader) { if (tag.equalsIgnoreCase("ul")) { if (opening) { lists.push(tag); } else { lists.pop(); } } else if (tag.equalsIgnoreCase("ol")) { if (opening) { lists.push(tag); olNextIndex.push(Integer.valueOf(1)).toString();//TODO: add support for lists starting other index than 1 } else { lists.pop(); olNextIndex.pop().toString(); } } else if (tag.equalsIgnoreCase("li")) { if (opening) { if (output.length() > 0 && output.charAt(output.length() - 1) != '\n') { output.append("\n"); } String parentList = lists.peek(); if (parentList.equalsIgnoreCase("ol")) { start(output, new Ol()); output.append(olNextIndex.peek().toString() + ". "); olNextIndex.push(Integer.valueOf(olNextIndex.pop().intValue() + 1)); } else if (parentList.equalsIgnoreCase("ul")) { start(output, new Ul()); } } else { if (lists.peek().equalsIgnoreCase("ul")) { if ( output.length() > 0 && output.charAt(output.length() - 1) != '\n' ) { output.append("\n"); } // Nested BulletSpans increases distance between bullet and text, so we must prevent it. int bulletMargin = indent; if (lists.size() > 1) { bulletMargin = indent-bullet.getLeadingMargin(true); if (lists.size() > 2) { // This get's more complicated when we add a LeadingMarginSpan into the same line: // we have also counter it's effect to BulletSpan bulletMargin -= (lists.size() - 2) * listItemIndent; } } BulletSpan newBullet = new BulletSpan(bulletMargin); end(output, Ul.class, new LeadingMarginSpan.Standard(listItemIndent * (lists.size() - 1)), newBullet); } else if (lists.peek().equalsIgnoreCase("ol")) { if ( output.length() > 0 && output.charAt(output.length() - 1) != '\n' ) { output.append("\n"); } int numberMargin = listItemIndent * (lists.size() - 1); if (lists.size() > 2) { // Same as in ordered lists: counter the effect of nested Spans numberMargin -= (lists.size() - 2) * listItemIndent; } end(output, Ol.class, new LeadingMarginSpan.Standard(numberMargin)); } } } else { if (opening) Log.d("TagHandler", "Found an unsupported tag " + tag); } }
/** * Processes a single list item. * * @param opening is this the opening tag? * @see <a href="https://bitbucket.org/Kuitsi/android-textview-html-list">Kuitsi/android-textview-html-list</a> */ private void processListItem(boolean opening, Editable output) { if (opening) { if (output.length() > 0 && output.charAt(output.length() - 1) != '\n') { output.append("\n"); } String parentList = lists.peek(); if (parentList.equalsIgnoreCase("ol")) { start(output, new Ol()); output.append(olNextIndex.peek().toString()).append(". "); olNextIndex.push(olNextIndex.pop() + 1); } else if (parentList.equalsIgnoreCase("ul")) { start(output, new Ul()); } } else { if (lists.peek().equalsIgnoreCase("ul")) { if (output.length() > 0 && output.charAt(output.length() - 1) != '\n') { output.append("\n"); } // Nested BulletSpans increases distance between bullet and text, so we must prevent it. int bulletMargin = indent; if (lists.size() > 1) { bulletMargin = indent - bullet.getLeadingMargin(true); if (lists.size() > 2) { // This get's more complicated when we add a LeadingMarginSpan into the same line: // we have also counter it's effect to BulletSpan bulletMargin -= (lists.size() - 2) * listItemIndent; } } BulletSpan newBullet = new BulletSpan(bulletMargin); end(output, Ul.class, new LeadingMarginSpan.Standard(listItemIndent * (lists.size() - 1)), newBullet); } else if (lists.peek().equalsIgnoreCase("ol")) { if (output.length() > 0 && output.charAt(output.length() - 1) != '\n') { output.append("\n"); } int numberMargin = listItemIndent * (lists.size() - 1); if (lists.size() > 2) { // Same as in ordered lists: counter the effect of nested Spans numberMargin -= (lists.size() - 2) * listItemIndent; } end(output, Ol.class, new LeadingMarginSpan.Standard(numberMargin)); } } }
@Override protected void onCreate(Bundle savedInstanceState) { getTheme().applyStyle(SharedPrefs.getFontSize().getResId(), true); super.onCreate(savedInstanceState); setContentView(R.layout.activity_about_page); UtilFunctions.applyReadingMode(); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); toolbar.setNavigationIcon(R.drawable.ic_arrow_back_white); toolbar.setContentInsetStartWithNavigation(0); setSupportActionBar(toolbar); getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setDisplayShowHomeEnabled(true); getSupportActionBar().setDisplayShowTitleEnabled(true); tvAboutUs = (TextView) findViewById(R.id.tv_about_us); SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(); Spannable spannable1 = new SpannableString(getResources().getString(R.string.autographa)); Spannable spannable2 = new SpannableString(getResources().getString(R.string.text_1)); Spannable spannable3 = new SpannableString(getResources().getString(R.string.text_2)); Spannable spannable4 = new SpannableString(getResources().getString(R.string.text_3)); Spannable spannable5 = new SpannableString(getResources().getString(R.string.points_heading)); Spannable spannable6 = new SpannableString(getResources().getString(R.string.bullet_1)); Spannable spannable7 = new SpannableString(getResources().getString(R.string.bullet_2)); Spannable spannable8 = new SpannableString(getResources().getString(R.string.bullet_3)); Spannable spannable9 = new SpannableString(getResources().getString(R.string.bullet_4)); Spannable spannable10 = new SpannableString(getResources().getString(R.string.bullet_5)); Spannable spannable11 = new SpannableString(getResources().getString(R.string.publishing)); Spannable spannable12 = new SpannableString(getResources().getString(R.string.repo_link)); spannable1.setSpan(new StyleSpan(Typeface.BOLD_ITALIC), 0, spannable1.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); spannable3.setSpan(new StyleSpan(Typeface.BOLD), 0, spannable3.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); spannable5.setSpan(new StyleSpan(Typeface.BOLD), 0, spannable5.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); spannable6.setSpan(new BulletSpan(4), 0, spannable6.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); spannable7.setSpan(new BulletSpan(4), 0, spannable7.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); spannable8.setSpan(new BulletSpan(4), 0, spannable8.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); spannable9.setSpan(new BulletSpan(4), 0, spannable9.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); spannable10.setSpan(new BulletSpan(4), 0, spannable10.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); spannableStringBuilder.append(getResources().getString(R.string.version) + " "); spannableStringBuilder.append(BuildConfig.VERSION_NAME); spannableStringBuilder.append("\n\n"); spannableStringBuilder.append(spannable1); spannableStringBuilder.append(" "); spannableStringBuilder.append(spannable2); spannableStringBuilder.append(" "); spannableStringBuilder.append(spannable3); spannableStringBuilder.append(" "); spannableStringBuilder.append(spannable4); spannableStringBuilder.append(spannable5); spannableStringBuilder.append(spannable6); spannableStringBuilder.append(spannable7); spannableStringBuilder.append(spannable8); spannableStringBuilder.append(spannable9); spannableStringBuilder.append(spannable10); spannableStringBuilder.append(spannable11); spannableStringBuilder.append(spannable12); tvAboutUs.setText(spannableStringBuilder); }