-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Android] Ensure pills are deleted all at once (#676)
- Loading branch information
1 parent
0a7ab7a
commit fd9de23
Showing
4 changed files
with
162 additions
and
6 deletions.
There are no files selected for viewing
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
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
29 changes: 29 additions & 0 deletions
29
...ndroid/library/src/main/java/io/element/android/wysiwyg/internal/utils/TextRangeHelper.kt
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package io.element.android.wysiwyg.internal.utils | ||
|
||
import android.text.Spanned | ||
import android.text.style.ReplacementSpan | ||
import kotlin.math.max | ||
import kotlin.math.min | ||
|
||
internal object TextRangeHelper { | ||
/** | ||
* Return a new range that covers the given range and extends it to cover | ||
* any replacement spans at either end. | ||
* | ||
* The range is returned as a pair of integers where the first is less than the last | ||
*/ | ||
fun extendRangeToReplacementSpans( | ||
spanned: Spanned, | ||
start: Int, | ||
length: Int, | ||
): Pair<Int, Int> { | ||
require(length > 0) | ||
val end = start + length | ||
val spans = spanned.getSpans(start, end, ReplacementSpan::class.java) | ||
val firstReplacementSpanStart = spans.minOfOrNull { spanned.getSpanStart(it) } | ||
val lastReplacementSpanEnd = spans.maxOfOrNull { spanned.getSpanEnd(it) } | ||
val newStart = min(start, firstReplacementSpanStart ?: end) | ||
val newEnd = max(end, lastReplacementSpanEnd ?: end) | ||
return newStart to newEnd | ||
} | ||
} |
106 changes: 106 additions & 0 deletions
106
.../library/src/test/kotlin/io/element/android/wysiwyg/internal/utils/TextRangeHelperTest.kt
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
package io.element.android.wysiwyg.internal.utils | ||
|
||
import android.graphics.Canvas | ||
import android.graphics.Paint | ||
import android.text.SpannableStringBuilder | ||
import android.text.Spanned | ||
import android.text.style.ReplacementSpan | ||
import org.junit.Assert.assertEquals | ||
import org.junit.Test | ||
import org.junit.runner.RunWith | ||
import org.robolectric.RobolectricTestRunner | ||
|
||
@RunWith(RobolectricTestRunner::class) | ||
class TextRangeHelperTest { | ||
@Test(expected = IllegalArgumentException::class) | ||
fun `given negative length, when extend to cover ReplacementSpans, it throws`() { | ||
val text = SpannableStringBuilder("0123456789") | ||
|
||
TextRangeHelper.extendRangeToReplacementSpans( | ||
text, 3, -1 | ||
) | ||
} | ||
@Test | ||
fun `given plain text, when extend to cover ReplacementSpans, selection is not extended`() { | ||
val text = SpannableStringBuilder("0123456789") | ||
|
||
val newSelection = TextRangeHelper.extendRangeToReplacementSpans( | ||
text, 3, 4 | ||
) | ||
|
||
assertEquals(3 to 7, newSelection) | ||
} | ||
|
||
@Test | ||
fun `given ReplacementSpan at end, when extend to cover ReplacementSpans, selection extended`() { | ||
val text = SpannableStringBuilder("0123456789") | ||
text.setSpan(MyReplacementSpan(), 6, 10, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) | ||
|
||
val newSelection = TextRangeHelper.extendRangeToReplacementSpans( | ||
text, 3, 4 | ||
) | ||
|
||
assertEquals(3 to 10, newSelection) | ||
} | ||
|
||
@Test | ||
fun `given ReplacementSpan at start, when extend to cover ReplacementSpans, selection extended`() { | ||
val text = SpannableStringBuilder("0123456789") | ||
text.setSpan(MyReplacementSpan(), 0, 4, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) | ||
|
||
val newSelection = TextRangeHelper.extendRangeToReplacementSpans( | ||
text, 3, 4 | ||
) | ||
|
||
assertEquals(0 to 7, newSelection) | ||
} | ||
|
||
@Test | ||
fun `given ReplacementSpan immediately before and after, when extend to cover ReplacementSpans, selection not extended`() { | ||
val text = SpannableStringBuilder("0123456789") | ||
text.setSpan(MyReplacementSpan(), 0, 3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) | ||
text.setSpan(MyReplacementSpan(), 7, 10, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) | ||
|
||
val newSelection = TextRangeHelper.extendRangeToReplacementSpans( | ||
text, 3, 4 | ||
) | ||
|
||
assertEquals(3 to 7, newSelection) | ||
} | ||
|
||
@Test | ||
fun `given ReplacementSpan at start and end, when extend to cover ReplacementSpans, selection extended`() { | ||
val text = SpannableStringBuilder("0123456789") | ||
text.setSpan(MyReplacementSpan(), 0, 4, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) | ||
text.setSpan(MyReplacementSpan(), 6, 10, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) | ||
|
||
val newSelection = TextRangeHelper.extendRangeToReplacementSpans( | ||
text, 3, 4 | ||
) | ||
|
||
assertEquals(0 to 10, newSelection) | ||
} | ||
} | ||
|
||
class MyReplacementSpan : ReplacementSpan() { | ||
override fun getSize( | ||
paint: Paint, | ||
text: CharSequence?, | ||
start: Int, | ||
end: Int, | ||
fm: Paint.FontMetricsInt? | ||
): Int = 10 | ||
|
||
override fun draw( | ||
canvas: Canvas, | ||
text: CharSequence?, | ||
start: Int, | ||
end: Int, | ||
x: Float, | ||
top: Int, | ||
y: Int, | ||
bottom: Int, | ||
paint: Paint | ||
) { | ||
} | ||
} |