diff --git a/feature/calculator/src/main/java/com/sadellie/unitto/feature/calculator/TextFieldController.kt b/feature/calculator/src/main/java/com/sadellie/unitto/feature/calculator/TextFieldController.kt index 61e724d9..d1cb5ed2 100644 --- a/feature/calculator/src/main/java/com/sadellie/unitto/feature/calculator/TextFieldController.kt +++ b/feature/calculator/src/main/java/com/sadellie/unitto/feature/calculator/TextFieldController.kt @@ -20,11 +20,43 @@ package com.sadellie.unitto.feature.calculator import androidx.compose.ui.text.TextRange 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_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_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_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_SQRT import com.sadellie.unitto.core.base.KEY_TAN import com.sadellie.unitto.core.ui.UnittoFormatter import kotlinx.coroutines.flow.MutableStateFlow @@ -33,6 +65,8 @@ import javax.inject.Inject import kotlin.math.abs class TextFieldController @Inject constructor() { + var input: MutableStateFlow = MutableStateFlow(TextFieldValue()) + // Internally we don't care about user preference here, because during composition this // symbols will be replaced to those that user wanted. // 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() } - var input: MutableStateFlow = MutableStateFlow(TextFieldValue()) + private val knownSymbols: List 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) { @@ -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) { val currentInput = input.value.text 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.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 { val illegalTokens by lazy { listOf( diff --git a/feature/calculator/src/test/java/com/sadellie/unitto/feature/calculator/TextFieldControllerTest.kt b/feature/calculator/src/test/java/com/sadellie/unitto/feature/calculator/TextFieldControllerTest.kt index 2f76a956..978946b1 100644 --- a/feature/calculator/src/test/java/com/sadellie/unitto/feature/calculator/TextFieldControllerTest.kt +++ b/feature/calculator/src/test/java/com/sadellie/unitto/feature/calculator/TextFieldControllerTest.kt @@ -189,7 +189,7 @@ internal class TextFieldControllerTest { } @Test - fun `placed cursor illegally`() { + fun `Place cursor illegally`() { textFieldController.addToInput("123456.789") // Input is 123,456.789 textFieldController.moveCursor(4..4) @@ -211,4 +211,34 @@ internal class TextFieldControllerTest { // Input is 123,456.789 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) + } }