Created
September 25, 2023 12:26
-
-
Save ForceTower/c061d0527ed370ea1ae548d283cb14f7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.graphics.Typeface | |
import android.text.SpannableString | |
import android.text.Spanned | |
import android.text.style.StrikethroughSpan | |
import android.text.style.StyleSpan | |
import android.text.style.UnderlineSpan | |
private val BOLD_REGEX = Regex("\\*([^*]+)\\*") | |
private val ITALIC_REGEX = Regex("_([^_]+)_") | |
private val STRIKE_REGEX = Regex("~([^~]+)~") | |
private val UNDERLINE_REGEX = Regex("#([^#]+)#") | |
private val EFFECT_REGEX_LIST = listOf(BOLD_REGEX, ITALIC_REGEX, STRIKE_REGEX, UNDERLINE_REGEX) | |
private data class EffectIndex(val start: Int, val end: Int, val type: Int) | |
private fun spanByType(type: Int): Any { | |
return when (type) { | |
0 -> StyleSpan(Typeface.BOLD) | |
1 -> StyleSpan(Typeface.ITALIC) | |
2 -> StrikethroughSpan() | |
3 -> UnderlineSpan() | |
else -> throw IllegalStateException("unknown type") | |
} | |
} | |
fun String?.nullIfBlank(): String? { | |
return if (isNullOrBlank()) null else this | |
} | |
fun String.createSpannable(): SpannableString { | |
val values = EFFECT_REGEX_LIST.flatMapIndexed { type, regex -> | |
val matches = regex.findAll(this) | |
matches.map { result -> | |
val range = result.groups[1]?.range ?: throw IllegalStateException("no match at regex?") | |
EffectIndex(range.first - 1, range.last + 1, type) | |
} | |
} | |
val indices = values.flatMap { listOf(it.start, it.end) }.distinct().sorted() | |
fun indexedPosition(index: Int): Int { | |
val position = indices.indexOf(index) | |
return index - position | |
} | |
val finalString = this | |
.replace(BOLD_REGEX, "$1") | |
.replace(ITALIC_REGEX, "$1") | |
.replace(STRIKE_REGEX, "$1") | |
.replace(UNDERLINE_REGEX, "$1") | |
val spannable = SpannableString(finalString).apply { | |
values.forEach { effect -> | |
val span = spanByType(effect.type) | |
setSpan(span, indexedPosition(effect.start), indexedPosition(effect.end), Spanned.SPAN_INCLUSIVE_INCLUSIVE) | |
} | |
} | |
return spannable | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment