mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-23 10:20:25 +01:00
Update conversations list UI.
This commit is contained in:
committed by
Cody Henthorne
parent
c84de8fa60
commit
e09d162c1e
@@ -12,6 +12,7 @@ import com.annimon.stream.Stream;
|
||||
|
||||
import org.whispersystems.libsignal.util.Pair;
|
||||
|
||||
import java.security.InvalidParameterException;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
@@ -19,10 +20,14 @@ import java.util.Locale;
|
||||
|
||||
public class SearchUtil {
|
||||
|
||||
public static final int STRICT = 0;
|
||||
public static final int MATCH_ALL = 1;
|
||||
|
||||
public static Spannable getHighlightedSpan(@NonNull Locale locale,
|
||||
@NonNull StyleFactory styleFactory,
|
||||
@Nullable String text,
|
||||
@Nullable String highlight)
|
||||
@Nullable String highlight,
|
||||
int matchMode)
|
||||
{
|
||||
if (TextUtils.isEmpty(text)) {
|
||||
return new SpannableString("");
|
||||
@@ -30,13 +35,14 @@ public class SearchUtil {
|
||||
|
||||
text = text.replaceAll("\n", " ");
|
||||
|
||||
return getHighlightedSpan(locale, styleFactory, new SpannableString(text), highlight);
|
||||
return getHighlightedSpan(locale, styleFactory, new SpannableString(text), highlight, matchMode);
|
||||
}
|
||||
|
||||
public static Spannable getHighlightedSpan(@NonNull Locale locale,
|
||||
@NonNull StyleFactory styleFactory,
|
||||
@Nullable Spannable text,
|
||||
@Nullable String highlight)
|
||||
@Nullable String highlight,
|
||||
int matchMode)
|
||||
{
|
||||
if (TextUtils.isEmpty(text)) {
|
||||
return new SpannableString("");
|
||||
@@ -47,8 +53,24 @@ public class SearchUtil {
|
||||
return text;
|
||||
}
|
||||
|
||||
List<Pair<Integer, Integer>> ranges = getHighlightRanges(locale, text.toString(), highlight);
|
||||
SpannableString spanned = new SpannableString(text);
|
||||
List<Pair<Integer, Integer>> ranges;
|
||||
|
||||
switch (matchMode) {
|
||||
case STRICT:
|
||||
ranges = getStrictHighlightRanges(locale, text.toString(), highlight);
|
||||
break;
|
||||
case MATCH_ALL:
|
||||
ranges = getHighlightRanges(locale, text.toString(), highlight);
|
||||
break;
|
||||
default:
|
||||
throw new InvalidParameterException("match mode must be STRICT or MATCH_ALL: " + matchMode);
|
||||
}
|
||||
if (matchMode == STRICT) {
|
||||
ranges = getStrictHighlightRanges(locale, text.toString(), highlight);
|
||||
} else {
|
||||
ranges = getHighlightRanges(locale, text.toString(), highlight);
|
||||
}
|
||||
|
||||
for (Pair<Integer, Integer> range : ranges) {
|
||||
spanned.setSpan(styleFactory.create(), range.first(), range.second(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||
@@ -57,9 +79,9 @@ public class SearchUtil {
|
||||
return spanned;
|
||||
}
|
||||
|
||||
static List<Pair<Integer, Integer>> getHighlightRanges(@NonNull Locale locale,
|
||||
@NonNull String text,
|
||||
@NonNull String highlight)
|
||||
static List<Pair<Integer, Integer>> getStrictHighlightRanges(@NonNull Locale locale,
|
||||
@NonNull String text,
|
||||
@NonNull String highlight)
|
||||
{
|
||||
if (text.length() == 0) {
|
||||
return Collections.emptyList();
|
||||
@@ -97,6 +119,39 @@ public class SearchUtil {
|
||||
return ranges;
|
||||
}
|
||||
|
||||
static List<Pair<Integer, Integer>> getHighlightRanges(@NonNull Locale locale,
|
||||
@NonNull String text,
|
||||
@NonNull String highlight)
|
||||
{
|
||||
if (text.length() == 0) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
String normalizedText = text.toLowerCase(locale);
|
||||
String normalizedHighlight = highlight.toLowerCase(locale);
|
||||
List<String> highlightTokens = Stream.of(normalizedHighlight.split("\\s")).filter(s -> s.trim().length() > 0).toList();
|
||||
|
||||
List<Pair<Integer, Integer>> ranges = new LinkedList<>();
|
||||
|
||||
int lastHighlightEndIndex = 0;
|
||||
|
||||
for (String highlightToken : highlightTokens) {
|
||||
int index = 0;
|
||||
lastHighlightEndIndex = 0;
|
||||
|
||||
while (index != -1) {
|
||||
index = normalizedText.indexOf(highlightToken, lastHighlightEndIndex);
|
||||
if (index != -1) {
|
||||
lastHighlightEndIndex = index + highlightToken.length();
|
||||
ranges.add(new Pair<>(index, lastHighlightEndIndex));
|
||||
index = lastHighlightEndIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ranges;
|
||||
}
|
||||
|
||||
public interface StyleFactory {
|
||||
CharacterStyle create();
|
||||
}
|
||||
|
||||
@@ -13,12 +13,15 @@ import android.text.TextPaint;
|
||||
import android.text.TextUtils;
|
||||
import android.text.style.AbsoluteSizeSpan;
|
||||
import android.text.style.BulletSpan;
|
||||
import android.text.style.CharacterStyle;
|
||||
import android.text.style.ClickableSpan;
|
||||
import android.text.style.DynamicDrawableSpan;
|
||||
import android.text.style.ForegroundColorSpan;
|
||||
import android.text.style.ImageSpan;
|
||||
import android.text.style.MetricAffectingSpan;
|
||||
import android.text.style.RelativeSizeSpan;
|
||||
import android.text.style.StyleSpan;
|
||||
import android.text.style.TypefaceSpan;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.ColorInt;
|
||||
@@ -34,6 +37,9 @@ public final class SpanUtil {
|
||||
|
||||
public static final String SPAN_PLACE_HOLDER = "<<<SPAN>>>";
|
||||
|
||||
private final static Typeface BOLD_TYPEFACE = Typeface.create("sans-serif-medium", Typeface.NORMAL);
|
||||
private final static Typeface LIGHT_TYPEFACE = Typeface.create("sans-serif", Typeface.NORMAL);
|
||||
|
||||
public static CharSequence italic(CharSequence sequence) {
|
||||
return italic(sequence, sequence.length());
|
||||
}
|
||||
@@ -205,4 +211,20 @@ public final class SpanUtil {
|
||||
builder.replace(index, index + SpanUtil.SPAN_PLACE_HOLDER.length(), span);
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static CharacterStyle getBoldSpan() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
return new TypefaceSpan(BOLD_TYPEFACE);
|
||||
} else {
|
||||
return new StyleSpan(Typeface.BOLD);
|
||||
}
|
||||
}
|
||||
|
||||
public static CharacterStyle getNormalSpan() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
return new TypefaceSpan(LIGHT_TYPEFACE);
|
||||
} else {
|
||||
return new StyleSpan(Typeface.NORMAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user