Fix relinkifying tags in posts from remote servers (#2359)

* Fix relinkifying tags in posts from remote servers

* Completely ignore urls, and (case-insensitively) match tag names instead
This commit is contained in:
Levi Bard 2022-02-28 16:54:25 +01:00 committed by GitHub
parent 2c91b1148c
commit cdefcc441f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 15 additions and 43 deletions

View File

@ -98,15 +98,16 @@ fun setClickableText(
} }
@VisibleForTesting @VisibleForTesting
fun getTagName(text: CharSequence, tags: List<HashTag>?, span: URLSpan): String? { fun getTagName(text: CharSequence, tags: List<HashTag>?): String? {
val scrapedName = text.subSequence(1, text.length).toString()
return when (tags) { return when (tags) {
null -> text.subSequence(1, text.length).toString() null -> scrapedName
else -> tags.firstOrNull { it.url == span.url }?.name else -> tags.firstOrNull { it.name.equals(scrapedName, true) }?.name
} }
} }
private fun getCustomSpanForTag(text: CharSequence, tags: List<HashTag>?, span: URLSpan, listener: LinkListener): ClickableSpan? { private fun getCustomSpanForTag(text: CharSequence, tags: List<HashTag>?, span: URLSpan, listener: LinkListener): ClickableSpan? {
return getTagName(text, tags, span)?.let { return getTagName(text, tags)?.let {
object : NoUnderlineURLSpan(span.url) { object : NoUnderlineURLSpan(span.url) {
override fun onClick(view: View) = listener.onViewTag(it) override fun onClick(view: View) = listener.onViewTag(it)
} }

View File

@ -70,56 +70,27 @@ class LinkHelperTest {
} }
@Test @Test
fun whenSettingClickableTest_tagUrlsArePreserved() { fun whenCheckingTags_tagNameIsComparedCaseInsensitively() {
val builder = SpannableStringBuilder()
for (tag in tags) { for (tag in tags) {
builder.append("#${tag.name}", URLSpan(tag.url), 0) for (mutatedTagName in listOf(tag.name, tag.name.uppercase(), tag.name.lowercase())) {
builder.append(" ") val tagName = getTagName("#$mutatedTagName", tags)
} Assert.assertNotNull(tagName)
Assert.assertNotNull(tags.firstOrNull { it.name == tagName })
var urlSpans = builder.getSpans(0, builder.length, URLSpan::class.java) }
for (span in urlSpans) {
setClickableText(span, builder, emptyList(), tags, listener)
}
urlSpans = builder.getSpans(0, builder.length, URLSpan::class.java)
for (span in urlSpans) {
Assert.assertNotNull(tags.firstOrNull { it.url == span.url })
} }
} }
@Test @Test
fun whenSettingClickableTest_nonTagUrlsAreNotConverted() { fun hashedUrlSpans_withNoMatchingTag_areNotModified() {
val builder = SpannableStringBuilder()
val nonTagUrl = "http://example.com/"
for (tag in tags) { for (tag in tags) {
builder.append("#${tag.name}", URLSpan(nonTagUrl), 0) Assert.assertNull(getTagName("#not${tag.name}", tags))
builder.append(" ")
builder.append("#${tag.name} ")
}
var urlSpans = builder.getSpans(0, builder.length, URLSpan::class.java)
for (span in urlSpans) {
setClickableText(span, builder, emptyList(), tags, listener)
}
urlSpans = builder.getSpans(0, builder.length, URLSpan::class.java)
for (span in urlSpans) {
Assert.assertEquals(nonTagUrl, span.url)
} }
} }
@Test @Test
fun whenTagsAreNull_tagNameIsGeneratedFromText() { fun whenTagsAreNull_tagNameIsGeneratedFromText() {
SpannableStringBuilder().apply { for (tag in tags) {
for (tag in tags) { Assert.assertEquals(tag.name, getTagName("#${tag.name}", null))
append("#${tag.name}", URLSpan(tag.url), 0)
append(" ")
}
getSpans(0, length, URLSpan::class.java).forEach {
Assert.assertNotNull(getTagName(subSequence(getSpanStart(it), getSpanEnd(it)), null, it))
}
} }
} }