That fuck shit the fascists are using
at master 162 lines 5.3 kB view raw
1package org.tm.archive.util; 2 3import android.text.Annotation; 4import android.text.Spannable; 5import android.text.SpannableString; 6import android.text.TextUtils; 7import android.text.style.CharacterStyle; 8 9import androidx.annotation.NonNull; 10import androidx.annotation.Nullable; 11 12import com.annimon.stream.Stream; 13 14import org.signal.core.util.StringUtil; 15import org.signal.libsignal.protocol.util.Pair; 16import org.tm.archive.components.spoiler.SpoilerAnnotation; 17 18import java.security.InvalidParameterException; 19import java.util.Collections; 20import java.util.LinkedList; 21import java.util.List; 22import java.util.Locale; 23 24public class SearchUtil { 25 26 public static final int STRICT = 0; 27 public static final int MATCH_ALL = 1; 28 29 public static Spannable getHighlightedSpan(@NonNull Locale locale, 30 @NonNull StyleFactory styleFactory, 31 @Nullable CharSequence text, 32 @Nullable String highlight, 33 int matchMode) 34 { 35 if (TextUtils.isEmpty(text)) { 36 return new SpannableString(""); 37 } 38 39 text = StringUtil.replace(text, '\n', " "); 40 41 return getHighlightedSpan(locale, styleFactory, SpannableString.valueOf(text), highlight, matchMode); 42 } 43 44 public static Spannable getHighlightedSpan(@NonNull Locale locale, 45 @NonNull StyleFactory styleFactory, 46 @Nullable Spannable text, 47 @Nullable String highlight, 48 int matchMode) 49 { 50 if (TextUtils.isEmpty(text)) { 51 return new SpannableString(""); 52 } 53 54 55 if (TextUtils.isEmpty(highlight)) { 56 return text; 57 } 58 59 SpannableString spanned = new SpannableString(text); 60 List<Pair<Integer, Integer>> ranges; 61 62 switch (matchMode) { 63 case STRICT: 64 ranges = getStrictHighlightRanges(locale, text.toString(), highlight); 65 break; 66 case MATCH_ALL: 67 ranges = getHighlightRanges(locale, text.toString(), highlight); 68 break; 69 default: 70 throw new InvalidParameterException("match mode must be STRICT or MATCH_ALL: " + matchMode); 71 } 72 73 for (Pair<Integer, Integer> range : ranges) { 74 CharacterStyle[] styles = styleFactory.createStyles(); 75 for (CharacterStyle style : styles) { 76 List<Annotation> annotations = SpoilerAnnotation.getSpoilerAnnotations(spanned, range.first(), range.second()); 77 if (annotations.isEmpty()) { 78 spanned.setSpan(style, range.first(), range.second(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 79 } 80 } 81 } 82 83 return spanned; 84 } 85 86 static List<Pair<Integer, Integer>> getStrictHighlightRanges(@NonNull Locale locale, 87 @NonNull String text, 88 @NonNull String highlight) 89 { 90 if (text.length() == 0) { 91 return Collections.emptyList(); 92 } 93 94 String normalizedText = text.toLowerCase(locale); 95 String normalizedHighlight = highlight.toLowerCase(locale); 96 List<String> highlightTokens = Stream.of(normalizedHighlight.split("\\s")).filter(s -> s.trim().length() > 0).toList(); 97 98 List<Pair<Integer, Integer>> ranges = new LinkedList<>(); 99 100 int lastHighlightEndIndex = 0; 101 102 for (String highlightToken : highlightTokens) { 103 int index; 104 105 do { 106 index = normalizedText.indexOf(highlightToken, lastHighlightEndIndex); 107 lastHighlightEndIndex = index + highlightToken.length(); 108 } while (index > 0 && !Character.isWhitespace(normalizedText.charAt(index - 1))); 109 110 if (index >= 0) { 111 ranges.add(new Pair<>(index, lastHighlightEndIndex)); 112 } 113 114 if (index < 0 || lastHighlightEndIndex >= normalizedText.length()) { 115 break; 116 } 117 } 118 119 if (ranges.size() != highlightTokens.size()) { 120 return Collections.emptyList(); 121 } 122 123 return ranges; 124 } 125 126 static List<Pair<Integer, Integer>> getHighlightRanges(@NonNull Locale locale, 127 @NonNull String text, 128 @NonNull String highlight) 129 { 130 if (text.length() == 0) { 131 return Collections.emptyList(); 132 } 133 134 String normalizedText = text.toLowerCase(locale); 135 String normalizedHighlight = highlight.toLowerCase(locale); 136 List<String> highlightTokens = Stream.of(normalizedHighlight.split("\\s")).filter(s -> s.trim().length() > 0).toList(); 137 138 List<Pair<Integer, Integer>> ranges = new LinkedList<>(); 139 140 int lastHighlightEndIndex = 0; 141 142 for (String highlightToken : highlightTokens) { 143 int index = 0; 144 lastHighlightEndIndex = 0; 145 146 while (index != -1) { 147 index = normalizedText.indexOf(highlightToken, lastHighlightEndIndex); 148 if (index != -1) { 149 lastHighlightEndIndex = index + highlightToken.length(); 150 ranges.add(new Pair<>(index, lastHighlightEndIndex)); 151 index = lastHighlightEndIndex; 152 } 153 } 154 } 155 156 return ranges; 157 } 158 159 public interface StyleFactory { 160 CharacterStyle[] createStyles(); 161 } 162}