1
0
Fork 0
mirror of https://github.com/MatomoCamp/matomocamp-companion-android.git synced 2024-09-19 16:13:46 +02:00

Improved code to handle HTML lists

This commit is contained in:
Christophe Beyls 2016-12-12 19:32:05 +01:00
parent d24a9dd5a9
commit 1c7f29d17c
2 changed files with 47 additions and 38 deletions

View file

@ -174,7 +174,7 @@ public class EventDetailsFragment extends Fragment {
if (TextUtils.isEmpty(text)) { if (TextUtils.isEmpty(text)) {
textView.setVisibility(View.GONE); textView.setVisibility(View.GONE);
} else { } else {
textView.setText(StringUtils.parseHtml(text)); textView.setText(StringUtils.parseHtml(text, getResources()));
textView.setMovementMethod(linkMovementMethod); textView.setMovementMethod(linkMovementMethod);
} }
textView = (TextView) view.findViewById(R.id.description); textView = (TextView) view.findViewById(R.id.description);
@ -182,7 +182,7 @@ public class EventDetailsFragment extends Fragment {
if (TextUtils.isEmpty(text)) { if (TextUtils.isEmpty(text)) {
textView.setVisibility(View.GONE); textView.setVisibility(View.GONE);
} else { } else {
textView.setText(StringUtils.parseHtml(text)); textView.setText(StringUtils.parseHtml(text, getResources()));
textView.setMovementMethod(linkMovementMethod); textView.setMovementMethod(linkMovementMethod);
} }

View file

@ -1,7 +1,12 @@
package be.digitalia.fosdem.utils; package be.digitalia.fosdem.utils;
import android.content.res.Resources;
import android.support.v4.util.CircularIntArray;
import android.text.Editable; import android.text.Editable;
import android.text.Html; import android.text.Html;
import android.text.Spanned;
import android.text.style.BulletSpan;
import android.text.style.LeadingMarginSpan;
import org.xml.sax.XMLReader; import org.xml.sax.XMLReader;
@ -94,8 +99,8 @@ public class StringUtils {
return trimEnd(Html.fromHtml(html)).toString(); return trimEnd(Html.fromHtml(html)).toString();
} }
public static CharSequence parseHtml(String html) { public static CharSequence parseHtml(String html, Resources res) {
return trimEnd(Html.fromHtml(html, null, new ListsTagHandler())); return trimEnd(Html.fromHtml(html, null, new ListsTagHandler(res)));
} }
public static CharSequence trimEnd(CharSequence source) { public static CharSequence trimEnd(CharSequence source) {
@ -133,10 +138,32 @@ public class StringUtils {
static class ListsTagHandler implements Html.TagHandler { static class ListsTagHandler implements Html.TagHandler {
private int level = 0; private static final float LEADING_MARGIN_DIPS = 2f;
private int liStart = -1; private static final float BULLET_GAP_WIDTH_DIPS = 8f;
private static void trimStart(final int start, Editable output) { private final CircularIntArray liStarts = new CircularIntArray(4);
private final int leadingMargin;
private final int bulletGapWidth;
public ListsTagHandler(Resources res) {
final float density = res.getDisplayMetrics().density;
leadingMargin = (int) (density * LEADING_MARGIN_DIPS + 0.5f);
bulletGapWidth = (int) (density * BULLET_GAP_WIDTH_DIPS + 0.5f);
}
/**
* @return final output length
*/
private static int ensureParagraphBoundary(Editable output) {
int length = output.length();
if ((length != 0) && output.charAt(length - 1) != '\n') {
output.insert(length, "\n");
length++;
}
return length;
}
private static void trimStart(Editable output, final int start) {
int end = start; int end = start;
final int length = output.length(); final int length = output.length();
while ((end < length) && Character.isWhitespace(output.charAt(end))) { while ((end < length) && Character.isWhitespace(output.charAt(end))) {
@ -147,43 +174,25 @@ public class StringUtils {
} }
} }
private static void trimEnd(Editable output) {
final int end = output.length();
int start = end - 1;
while ((start >= 0) && Character.isWhitespace(output.charAt(start))) {
start--;
}
start++;
if (start < end) {
output.delete(start, end);
}
}
@Override @Override
public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader) { public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader) {
switch (tag) { 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":
case "LI": case "LI":
if (liStart != -1) {
trimStart(liStart, output);
}
if (opening) { if (opening) {
level++; liStarts.addLast(ensureParagraphBoundary(output));
for (int i = 0; i < level; ++i) { } else if (!liStarts.isEmpty()) {
output.append('\t'); int start = liStarts.popLast();
} trimStart(output, start);
output.append(""); int end = ensureParagraphBoundary(output);
liStart = output.length(); // Add leading margin to ensure the bullet is not cut off
} else { output.setSpan(new LeadingMarginSpan.Standard(leadingMargin), start, end, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
level--; output.setSpan(new BulletSpan(bulletGapWidth), start, end, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
trimEnd(output);
output.append('\n');
if (liStart == -1) {
// End of list; moving one level up
output.append('\n');
} else {
liStart = -1;
}
} }
break; break;
} }