Skip to content

Commit

Permalink
fix crash when post is single line with hashtags (#4778)
Browse files Browse the repository at this point in the history
```
java.lang.StringIndexOutOfBoundsException
     at android.text.SpannableStringBuilder.<init>(SpannableStringBuilder.java:63)
     at android.text.SpannableStringBuilder.subSequence(SpannableStringBuilder.java:1198)
     at com.keylesspalace.tusky.util.LinkHelper.setClickableText(LinkHelper.kt:99)
     at com.keylesspalace.tusky.adapter.StatusBaseViewHolder.setTextVisible(StatusBaseViewHolder.java:289)
     at com.keylesspalace.tusky.adapter.StatusBaseViewHolder.setSpoilerAndContent(StatusBaseViewHolder.java:244)
     at com.keylesspalace.tusky.adapter.StatusBaseViewHolder.setupWithStatus(StatusBaseViewHolder.java:820)
     at com.keylesspalace.tusky.adapter.StatusViewHolder.setupWithStatus(StatusViewHolder.java:91)
     at com.keylesspalace.tusky.components.timeline.TimelinePagingAdapter.bindViewHolder(TimelinePagingAdapter.kt:100)
     at com.keylesspalace.tusky.components.timeline.TimelinePagingAdapter.onBindViewHolder(TimelinePagingAdapter.kt:82)
     at androidx.recyclerview.widget.RecyclerView$Adapter.bindViewHolder(RecyclerView.java:7847)
     at androidx.recyclerview.widget.RecyclerView$Recycler.tryBindViewHolderByDeadline(RecyclerView.java:6646)
     at androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:6917)
     at androidx.recyclerview.widget.GapWorker.prefetchPositionWithDeadline(GapWorker.java:288)
     at androidx.recyclerview.widget.GapWorker.flushTaskWithDeadline(GapWorker.java:345)
     at androidx.recyclerview.widget.GapWorker.flushTasksWithDeadline(GapWorker.java:361)
     at androidx.recyclerview.widget.GapWorker.prefetch(GapWorker.java:368)
     at androidx.recyclerview.widget.GapWorker.run(GapWorker.java:399)
     at android.os.Handler.handleCallback(Handler.java:959)
     at android.os.Handler.dispatchMessage(Handler.java:100)
     at android.os.Looper.loopOnce(Looper.java:232)
     at android.os.Looper.loop(Looper.java:317)
     at android.app.ActivityThread.main(ActivityThread.java:8705)
     at java.lang.reflect.Method.invoke(Native Method)
     at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:580)
     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:886)
```
  • Loading branch information
connyduck authored Nov 29, 2024
1 parent fc52074 commit 05b2a5d
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ internal fun getTrailingHashtags(content: Spanned): Pair<Int, List<HashTag>> {
return when (trailingContentLength) {
0 -> Pair(content.length, emptyList())
else -> {
val trailingContentOffset = content.length - trailingContentLength
val trailingContentOffset = (content.length - trailingContentLength).coerceAtLeast(0)
Pair(
trailingContentOffset,
content.getSpans(trailingContentOffset, content.length, URLSpan::class.java)
Expand Down
25 changes: 20 additions & 5 deletions app/src/test/java/com/keylesspalace/tusky/util/LinkHelperTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -317,17 +317,30 @@ class LinkHelperTest {

@Test
fun `get trailing hashtags with empty content returns empty list`() {
assert(getTrailingHashtags(SpannableStringBuilder("")).second.isEmpty())
val (endOfContent, trailingHashtags) = getTrailingHashtags(SpannableStringBuilder(""))
assertEquals(0, endOfContent)
assert(trailingHashtags.isEmpty())
}

@Test
fun `get trailing hashtags with no hashtags returns empty list`() {
assert(getTrailingHashtags(SpannableStringBuilder("some untagged content")).second.isEmpty())
val (endOfContent, trailingHashtags) = getTrailingHashtags(SpannableStringBuilder("some untagged content"))
assertEquals(21, endOfContent)
assert(trailingHashtags.isEmpty())
}

@Test
fun `get trailing hashtags with all inline hashtags returns empty list`() {
assert(getTrailingHashtags(SpannableStringBuilder("some #inline #tagged #content")).second.isEmpty())
val (endOfContent, trailingHashtags) = getTrailingHashtags(SpannableStringBuilder("some #inline #tagged #content"))
assertEquals(29, endOfContent)
assert(trailingHashtags.isEmpty())
}

@Test
fun `get trailing hashtags with only hashtags returns empty list`() {
val (endOfContent, trailingHashtags) = getTrailingHashtags(SpannableStringBuilder("#some #inline #tagged #content"))
assertEquals(0, endOfContent)
assert(trailingHashtags.isEmpty())
}

@Test
Expand All @@ -336,7 +349,8 @@ class LinkHelperTest {
tags.first().let { append("#${it.name}", URLSpan(it.url), 0) }
}

val (_, trailingHashtags) = getTrailingHashtags(content)
val (endOfContent, trailingHashtags) = getTrailingHashtags(content)
assertEquals(30, endOfContent)
assertEquals(tags.first().name, trailingHashtags.single().name)
assertEquals(tags.first().url, trailingHashtags.single().url)
}
Expand All @@ -352,7 +366,8 @@ class LinkHelperTest {
}
}

val (_, trailingHashtags) = getTrailingHashtags(content)
val (endOfContent, trailingHashtags) = getTrailingHashtags(content)
assertEquals(30, endOfContent)
assertEquals(tags.size, trailingHashtags.size)
tags.forEachIndexed { index, tag ->
assertEquals(tag.name, trailingHashtags[index].name)
Expand Down

0 comments on commit 05b2a5d

Please sign in to comment.