diff --git a/core/ui/src/main/java/com/sadellie/unitto/core/ui/common/textfield/ExpressionTransformer.kt b/core/ui/src/main/java/com/sadellie/unitto/core/ui/common/textfield/ExpressionTransformer.kt index 16481555..668772ce 100644 --- a/core/ui/src/main/java/com/sadellie/unitto/core/ui/common/textfield/ExpressionTransformer.kt +++ b/core/ui/src/main/java/com/sadellie/unitto/core/ui/common/textfield/ExpressionTransformer.kt @@ -34,21 +34,24 @@ class ExpressionTransformer(private val formatterSymbols: FormatterSymbols) : Vi } inner class ExpressionMapping( - private val unformatted: String, - private val formatted: String + private val original: String, + private val transformed: String ) : OffsetMapping { // Called when entering text (on each text change) // Basically moves cursor to the right position // // original input is "1000" and cursor is placed at the end "1000|" - // the formatted is "1,000" where cursor should be? - "1,000|" + // the transformed is "1,000" where cursor should be? - "1,000|" override fun originalToTransformed(offset: Int): Int { - val unformattedSubstr = unformatted.take(offset) + if (offset <= 0) return 0 + if (offset >= original.length) return transformed.length + + val unformattedSubstr = original.take(offset) var buffer = "" var groupings = 0 run { - formatted.forEach { + transformed.forEach { when (it) { formatterSymbols.grouping.first() -> groupings++ formatterSymbols.fractional.first() -> buffer += "." @@ -58,18 +61,21 @@ class ExpressionTransformer(private val formatterSymbols: FormatterSymbols) : Vi } } - return formatted.fixCursor(buffer.length + groupings, formatterSymbols.grouping) + return transformed.fixCursor(buffer.length + groupings, formatterSymbols.grouping) } - // Called when clicking formatted text + // Called when clicking transformed text // Snaps cursor to the right position // - // the formatted is "1,000" and cursor is placed at the end "1,000|" + // the transformed is "1,000" and cursor is placed at the end "1,000|" // original input is "1000" where cursor should be? - "1000|" override fun transformedToOriginal(offset: Int): Int { + if (offset <= 0) return 0 + if (offset >= transformed.length) return original.length + val grouping = formatterSymbols.grouping.first() - val fixedCursor = formatted.fixCursor(offset, formatterSymbols.grouping) - val addedSymbols = formatted.take(fixedCursor).count { it == grouping } + val fixedCursor = transformed.fixCursor(offset, formatterSymbols.grouping) + val addedSymbols = transformed.take(fixedCursor).count { it == grouping } return fixedCursor - addedSymbols } } diff --git a/core/ui/src/test/java/com/sadellie/unitto/core/ui/ExpressionTransformerTest.kt b/core/ui/src/test/java/com/sadellie/unitto/core/ui/ExpressionTransformerTest.kt new file mode 100644 index 00000000..430a76c3 --- /dev/null +++ b/core/ui/src/test/java/com/sadellie/unitto/core/ui/ExpressionTransformerTest.kt @@ -0,0 +1,68 @@ +/* + * Unitto is a unit converter for Android + * Copyright (c) 2023 Elshan Agaev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sadellie.unitto.core.ui + +import com.sadellie.unitto.core.ui.common.textfield.ExpressionTransformer +import com.sadellie.unitto.core.ui.common.textfield.FormatterSymbols +import org.junit.Assert.assertEquals +import org.junit.Test + +class ExpressionTransformerTest { + + private val expr = ExpressionTransformer(FormatterSymbols.Comma) + + private fun origToTrans(orig: String, trans: String, offset: Int): Int = + expr.ExpressionMapping(orig, trans).originalToTransformed(offset) + + private fun transToOrig(trans: String, orig: String, offset: Int): Int = + expr.ExpressionMapping(orig, trans).transformedToOriginal(offset) + + @Test + fun `test 1234`() { + // at the start + assertEquals(0, origToTrans("1,234", "1234", 0)) + assertEquals(0, transToOrig("1,234", "1234", 0)) + + // somewhere in inside, no offset needed + assertEquals(1, origToTrans("1234", "1,234", 1)) + assertEquals(1, transToOrig("1,234", "1234", 1)) + + // somewhere in inside, offset needed + assertEquals(1, transToOrig("1,234", "1234", 2)) + + // at the end + assertEquals(5, origToTrans("1234", "1,234", 4)) + assertEquals(4, transToOrig("1,234", "1234", 5)) + } + + @Test + fun `test 123`() { + // at the start + assertEquals(0, origToTrans("123", "123", 0)) + assertEquals(0, transToOrig("123", "123", 0)) + + // somewhere in inside + assertEquals(1, origToTrans("123", "123", 1)) + assertEquals(1, transToOrig("123", "123", 1)) + + // at the end + assertEquals(3, origToTrans("123", "123", 3)) + assertEquals(3, transToOrig("123", "123", 3)) + } +}