Filter text from clipboard

This commit is contained in:
Sad Ellie 2023-02-25 23:21:15 +04:00
parent b10630b9c7
commit 74cc7336fb
2 changed files with 105 additions and 2 deletions

View File

@ -20,11 +20,43 @@ package com.sadellie.unitto.feature.calculator
import androidx.compose.ui.text.TextRange import androidx.compose.ui.text.TextRange
import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.input.TextFieldValue
import com.sadellie.unitto.core.base.KEY_0
import com.sadellie.unitto.core.base.KEY_1
import com.sadellie.unitto.core.base.KEY_2
import com.sadellie.unitto.core.base.KEY_3
import com.sadellie.unitto.core.base.KEY_4
import com.sadellie.unitto.core.base.KEY_5
import com.sadellie.unitto.core.base.KEY_6
import com.sadellie.unitto.core.base.KEY_7
import com.sadellie.unitto.core.base.KEY_8
import com.sadellie.unitto.core.base.KEY_9
import com.sadellie.unitto.core.base.KEY_BASE_A
import com.sadellie.unitto.core.base.KEY_BASE_B
import com.sadellie.unitto.core.base.KEY_BASE_C
import com.sadellie.unitto.core.base.KEY_BASE_D
import com.sadellie.unitto.core.base.KEY_BASE_E
import com.sadellie.unitto.core.base.KEY_BASE_F
import com.sadellie.unitto.core.base.KEY_COS import com.sadellie.unitto.core.base.KEY_COS
import com.sadellie.unitto.core.base.KEY_DIVIDE
import com.sadellie.unitto.core.base.KEY_DIVIDE_DISPLAY
import com.sadellie.unitto.core.base.KEY_DOT import com.sadellie.unitto.core.base.KEY_DOT
import com.sadellie.unitto.core.base.KEY_EXPONENT
import com.sadellie.unitto.core.base.KEY_E_SMALL
import com.sadellie.unitto.core.base.KEY_FACTORIAL
import com.sadellie.unitto.core.base.KEY_LEFT_BRACKET
import com.sadellie.unitto.core.base.KEY_LN import com.sadellie.unitto.core.base.KEY_LN
import com.sadellie.unitto.core.base.KEY_LOG import com.sadellie.unitto.core.base.KEY_LOG
import com.sadellie.unitto.core.base.KEY_MINUS
import com.sadellie.unitto.core.base.KEY_MINUS_DISPLAY
import com.sadellie.unitto.core.base.KEY_MODULO
import com.sadellie.unitto.core.base.KEY_MULTIPLY
import com.sadellie.unitto.core.base.KEY_MULTIPLY_DISPLAY
import com.sadellie.unitto.core.base.KEY_PERCENT
import com.sadellie.unitto.core.base.KEY_PI
import com.sadellie.unitto.core.base.KEY_PLUS
import com.sadellie.unitto.core.base.KEY_RIGHT_BRACKET
import com.sadellie.unitto.core.base.KEY_SIN import com.sadellie.unitto.core.base.KEY_SIN
import com.sadellie.unitto.core.base.KEY_SQRT
import com.sadellie.unitto.core.base.KEY_TAN import com.sadellie.unitto.core.base.KEY_TAN
import com.sadellie.unitto.core.ui.UnittoFormatter import com.sadellie.unitto.core.ui.UnittoFormatter
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
@ -33,6 +65,8 @@ import javax.inject.Inject
import kotlin.math.abs import kotlin.math.abs
class TextFieldController @Inject constructor() { class TextFieldController @Inject constructor() {
var input: MutableStateFlow<TextFieldValue> = MutableStateFlow(TextFieldValue())
// Internally we don't care about user preference here, because during composition this // Internally we don't care about user preference here, because during composition this
// symbols will be replaced to those that user wanted. // symbols will be replaced to those that user wanted.
// We do this because it adds unnecessary logic: it requires additional logic to observe and // We do this because it adds unnecessary logic: it requires additional logic to observe and
@ -46,7 +80,19 @@ class TextFieldController @Inject constructor() {
private val cursorFixer by lazy { CursorFixer() } private val cursorFixer by lazy { CursorFixer() }
var input: MutableStateFlow<TextFieldValue> = MutableStateFlow(TextFieldValue()) private val knownSymbols: List<String> by lazy {
listOf(
KEY_SIN, KEY_COS, KEY_TAN, KEY_LN, KEY_LOG,
KEY_LEFT_BRACKET, KEY_RIGHT_BRACKET,
KEY_EXPONENT, KEY_SQRT, KEY_FACTORIAL,
KEY_MODULO, KEY_E_SMALL, KEY_PERCENT, KEY_PI,
KEY_MULTIPLY, KEY_MULTIPLY_DISPLAY,
KEY_PLUS, KEY_MINUS, KEY_MINUS_DISPLAY, KEY_DIVIDE, KEY_DIVIDE_DISPLAY,
KEY_BASE_A, KEY_BASE_B, KEY_BASE_C, KEY_BASE_D, KEY_BASE_E, KEY_BASE_F,
KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, KEY_0,
KEY_DOT,
)
}
fun addToInput(symbols: String) { fun addToInput(symbols: String) {
@ -71,6 +117,11 @@ class TextFieldController @Inject constructor() {
} }
} }
/**
* Method to call when pasting from clipbaord. It filters input before calling [addToInput].
*/
fun pasteSymbols(symbols: String) = addToInput(symbols.filterUnknownSymbols())
fun moveCursor(newPosition: IntRange) { fun moveCursor(newPosition: IntRange) {
val currentInput = input.value.text val currentInput = input.value.text
val fixedLeftCursor = cursorFixer.fixCursorIfNeeded(currentInput, newPosition.first) val fixedLeftCursor = cursorFixer.fixCursorIfNeeded(currentInput, newPosition.first)
@ -126,6 +177,28 @@ class TextFieldController @Inject constructor() {
private fun String.fixFormat(): String = localFormatter.reFormat(this) private fun String.fixFormat(): String = localFormatter.reFormat(this)
private fun String.filterUnknownSymbols(): String {
var clearStr = this.replace(" ", "")
var garbage = clearStr
// String with unknown symbols
knownSymbols.forEach {
garbage = garbage.replace(it, " ")
}
// Remove unknown symbols from input
garbage.split(" ").forEach {
clearStr = clearStr.replace(it, "")
}
clearStr = clearStr
.replace(KEY_DIVIDE, KEY_DIVIDE_DISPLAY)
.replace(KEY_MULTIPLY, KEY_MULTIPLY_DISPLAY)
.replace(KEY_MINUS, KEY_MINUS_DISPLAY)
return clearStr
}
inner class CursorFixer { inner class CursorFixer {
val illegalTokens by lazy { val illegalTokens by lazy {
listOf( listOf(

View File

@ -189,7 +189,7 @@ internal class TextFieldControllerTest {
} }
@Test @Test
fun `placed cursor illegally`() { fun `Place cursor illegally`() {
textFieldController.addToInput("123456.789") textFieldController.addToInput("123456.789")
// Input is 123,456.789 // Input is 123,456.789
textFieldController.moveCursor(4..4) textFieldController.moveCursor(4..4)
@ -211,4 +211,34 @@ internal class TextFieldControllerTest {
// Input is 123,456.789 // Input is 123,456.789
assertEquals("123456.789+cos(..)", textFieldController.inputTextWithoutFormatting()) assertEquals("123456.789+cos(..)", textFieldController.inputTextWithoutFormatting())
} }
@Test
fun `Paste completely weird stuff`() {
textFieldController.pasteSymbols("crazy stuff from clipboard")
assertEquals("", textFieldController.text)
}
@Test
fun `Paste partially weird stuff`() {
textFieldController.pasteSymbols("some crazy stuff cos(8+9)*7= that user may have in clipboard")
assertEquals("ecos(8+9)×7ee", textFieldController.text)
}
@Test
fun `Paste acceptable stuff that needs symbol replacement`() {
textFieldController.pasteSymbols("cos(8+9)*7")
assertEquals("cos(8+9)×7", textFieldController.text)
}
@Test
fun `Paste acceptable stuff that does not need replacement`() {
textFieldController.pasteSymbols("cos(8+9)×7")
assertEquals("cos(8+9)×7", textFieldController.text)
}
@Test
fun `Paste nothing`() {
textFieldController.pasteSymbols("")
assertEquals("", textFieldController.text)
}
} }