130 lines
4.3 KiB
Java
130 lines
4.3 KiB
Java
/* Copyright 2017 Andrew Dawson
|
|
*
|
|
* This file is a part of Tusky.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
|
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
|
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
|
* Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along with Tusky; if not,
|
|
* see <http://www.gnu.org/licenses>. */
|
|
|
|
package com.keylesspalace.tusky.util;
|
|
|
|
import android.text.Spannable;
|
|
import android.text.Spanned;
|
|
import android.text.style.ForegroundColorSpan;
|
|
|
|
public class SpanUtils {
|
|
private static class FindCharsResult {
|
|
int charIndex;
|
|
int stringIndex;
|
|
|
|
FindCharsResult() {
|
|
charIndex = -1;
|
|
stringIndex = -1;
|
|
}
|
|
}
|
|
|
|
private static FindCharsResult findChars(String string, int fromIndex, char[] chars) {
|
|
FindCharsResult result = new FindCharsResult();
|
|
final int length = string.length();
|
|
for (int i = fromIndex; i < length; i++) {
|
|
char c = string.charAt(i);
|
|
for (int j = 0; j < chars.length; j++) {
|
|
if (chars[j] == c) {
|
|
result.charIndex = j;
|
|
result.stringIndex = i;
|
|
return result;
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private static FindCharsResult findStart(String string, int fromIndex, char[] chars) {
|
|
final int length = string.length();
|
|
while (fromIndex < length) {
|
|
FindCharsResult found = findChars(string, fromIndex, chars);
|
|
int i = found.stringIndex;
|
|
if (i < 0) {
|
|
break;
|
|
} else if (i == 0 || i >= 1 && Character.isWhitespace(string.codePointBefore(i))) {
|
|
return found;
|
|
} else {
|
|
fromIndex = i + 1;
|
|
}
|
|
}
|
|
return new FindCharsResult();
|
|
}
|
|
|
|
private static int findEndOfHashtag(String string, int fromIndex) {
|
|
final int length = string.length();
|
|
for (int i = fromIndex + 1; i < length;) {
|
|
int codepoint = string.codePointAt(i);
|
|
if (Character.isWhitespace(codepoint)) {
|
|
return i;
|
|
} else if (codepoint == '#') {
|
|
return -1;
|
|
}
|
|
i += Character.charCount(codepoint);
|
|
}
|
|
return length;
|
|
}
|
|
|
|
private static int findEndOfMention(String string, int fromIndex) {
|
|
int atCount = 0;
|
|
final int length = string.length();
|
|
for (int i = fromIndex + 1; i < length;) {
|
|
int codepoint = string.codePointAt(i);
|
|
if (Character.isWhitespace(codepoint)) {
|
|
return i;
|
|
} else if (codepoint == '@') {
|
|
atCount += 1;
|
|
if (atCount >= 2) {
|
|
return -1;
|
|
}
|
|
}
|
|
i += Character.charCount(codepoint);
|
|
}
|
|
return length;
|
|
}
|
|
|
|
public static void highlightSpans(Spannable text, int colour) {
|
|
// Strip all existing colour spans.
|
|
int n = text.length();
|
|
ForegroundColorSpan[] oldSpans = text.getSpans(0, n, ForegroundColorSpan.class);
|
|
for (int i = oldSpans.length - 1; i >= 0; i--) {
|
|
text.removeSpan(oldSpans[i]);
|
|
}
|
|
// Colour the mentions and hashtags.
|
|
String string = text.toString();
|
|
int start;
|
|
int end = 0;
|
|
while (end < n) {
|
|
char[] chars = { '#', '@' };
|
|
FindCharsResult found = findStart(string, end, chars);
|
|
start = found.stringIndex;
|
|
if (start < 0) {
|
|
break;
|
|
}
|
|
if (found.charIndex == 0) {
|
|
end = findEndOfHashtag(string, start);
|
|
} else if (found.charIndex == 1) {
|
|
end = findEndOfMention(string, start);
|
|
} else {
|
|
break;
|
|
}
|
|
if (end < 0) {
|
|
break;
|
|
}
|
|
text.setSpan(new ForegroundColorSpan(colour), start, end,
|
|
Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
|
}
|
|
}
|
|
}
|