package com.keylesspalace.tusky.util import android.content.Context import android.text.Spannable import android.text.SpannableStringBuilder import android.text.Spanned import android.text.style.CharacterStyle import android.text.style.DynamicDrawableSpan import android.text.style.ForegroundColorSpan import android.text.style.ImageSpan import android.text.style.URLSpan import com.keylesspalace.tusky.util.twittertext.Regex import com.mikepenz.iconics.IconicsDrawable import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial import java.util.regex.Pattern /** * @see * Tag#HASHTAG_RE. */ private const val HASHTAG_SEPARATORS = "_\\u00B7\\u30FB\\u200c" internal const val TAG_PATTERN_STRING = "(? * Account#MENTION_RE */ private const val USERNAME_PATTERN_STRING = "[a-z0-9_]+([a-z0-9_.-]+[a-z0-9_]+)?" internal const val MENTION_PATTERN_STRING = "(? = defaultFinders) { // Strip all existing colour spans. for (spanClass in spanClasses) { clearSpans(spanClass) } for (finder in finders) { // before running the regular expression, check if there is even a chance of it finding something if (this.contains(finder.searchString)) { val matcher = finder.pattern.matcher(this) while (matcher.find()) { // we found a match val start = matcher.start(1) val end = matcher.end(1) // only add a span if there is no other one yet (e.g. the #anchor part of an url might match as hashtag, but must be ignored) if (this.getSpans(start, end, URLSpan::class.java).isEmpty()) { this.setSpan( getSpan(finder.type, this, colour, start, end), start, end, Spanned.SPAN_INCLUSIVE_EXCLUSIVE ) } } } } } private fun Spannable.clearSpans(spanClass: Class) { for (span in getSpans(0, length, spanClass)) { removeSpan(span) } } /** * Replaces text of the form [iconics name] with their spanned counterparts (ImageSpan). */ fun addDrawables(text: CharSequence, color: Int, size: Int, context: Context): Spannable { val builder = SpannableStringBuilder(text) val pattern = Pattern.compile("\\[iconics ([0-9a-z_]+)]") val matcher = pattern.matcher(builder) while (matcher.find()) { val resourceName = matcher.group(1) ?: continue val drawable = IconicsDrawable(context, GoogleMaterial.getIcon(resourceName)) drawable.setBounds(0, 0, size, size) drawable.setTint(color) builder.setSpan(ImageSpan(drawable, DynamicDrawableSpan.ALIGN_BASELINE), matcher.start(), matcher.end(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) } return builder } private fun getSpan( matchType: FoundMatchType, string: CharSequence, colour: Int, start: Int, end: Int ): CharacterStyle { return when (matchType) { FoundMatchType.HTTP_URL, FoundMatchType.HTTPS_URL -> NoUnderlineURLSpan(string.substring(start, end)) FoundMatchType.MENTION -> MentionSpan(string.substring(start, end)) else -> ForegroundColorSpan(colour) } }