mirror of
https://github.com/Myzel394/NumberHub.git
synced 2025-06-19 16:55:26 +02:00
Update text field formatting
This commit is contained in:
parent
24f03b9d3d
commit
4305354931
@ -54,7 +54,7 @@ object Token {
|
|||||||
|
|
||||||
object Operator {
|
object Operator {
|
||||||
const val plus = "+"
|
const val plus = "+"
|
||||||
const val minus = "−"
|
const val minus = "−" // MINUS SIGN, not a regular minus (HYPHEN-MINUS)
|
||||||
const val multiply = "×"
|
const val multiply = "×"
|
||||||
const val divide = "÷"
|
const val divide = "÷"
|
||||||
const val leftBracket = "("
|
const val leftBracket = "("
|
||||||
@ -122,6 +122,7 @@ object Token {
|
|||||||
const val comma = ","
|
const val comma = ","
|
||||||
const val engineeringE = "E"
|
const val engineeringE = "E"
|
||||||
const val minus = "−"
|
const val minus = "−"
|
||||||
|
const val fraction = "⁄"
|
||||||
}
|
}
|
||||||
|
|
||||||
val expressionTokens by lazy {
|
val expressionTokens by lazy {
|
||||||
|
@ -22,11 +22,19 @@ import com.sadellie.unitto.core.base.Token
|
|||||||
|
|
||||||
private val numbersRegex by lazy { Regex("[\\d.]+") }
|
private val numbersRegex by lazy { Regex("[\\d.]+") }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes formatting from expression. Reverse of [formatExpression]. Ugly symbols (for example,
|
||||||
|
* minus) will be replaced with a [Token.Operator.minus] from [Token.sexyToUgly].
|
||||||
|
*
|
||||||
|
* @param formatterSymbols [FormatterSymbols] that were used in [formatExpression].
|
||||||
|
* @return Clean expression. 123,456.789 -> 123456.789
|
||||||
|
*/
|
||||||
fun String.clearAndFilterExpression(formatterSymbols: FormatterSymbols): String {
|
fun String.clearAndFilterExpression(formatterSymbols: FormatterSymbols): String {
|
||||||
var clean = this
|
var clean = this
|
||||||
.replace(formatterSymbols.grouping, "")
|
.replace(formatterSymbols.grouping, "")
|
||||||
.replace(formatterSymbols.fractional, Token.Digit.dot)
|
.replace(formatterSymbols.fractional, Token.Digit.dot)
|
||||||
.replace(" ", "")
|
.replace(" ", Token.Operator.plus)
|
||||||
|
.replace(Token.DisplayOnly.fraction, Token.Operator.divide)
|
||||||
|
|
||||||
Token.sexyToUgly.forEach { (token, ugliness) ->
|
Token.sexyToUgly.forEach { (token, ugliness) ->
|
||||||
ugliness.forEach {
|
ugliness.forEach {
|
||||||
@ -34,22 +42,29 @@ fun String.clearAndFilterExpression(formatterSymbols: FormatterSymbols): String
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return clean.cleanIt(Token.expressionTokens)
|
return clean.leaveLegalTokensOnly(Token.expressionTokens)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun String.clearAndFilterNumberBase(): String {
|
internal fun String.clearAndFilterNumberBase(): String {
|
||||||
return uppercase().cleanIt(Token.numberBaseTokens)
|
return uppercase().leaveLegalTokensOnly(Token.numberBaseTokens)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun String.formatExpression(
|
fun String.formatExpression(
|
||||||
formatterSymbols: FormatterSymbols
|
formatterSymbols: FormatterSymbols
|
||||||
): String {
|
): String {
|
||||||
var input = this
|
var input = this
|
||||||
|
|
||||||
// Don't do anything to engineering string.
|
// Don't do anything to engineering string.
|
||||||
if (input.contains(Token.DisplayOnly.engineeringE)) {
|
if (input.contains(Token.DisplayOnly.engineeringE)) {
|
||||||
return input.replace(Token.Digit.dot, formatterSymbols.fractional)
|
return input.replace(Token.Digit.dot, formatterSymbols.fractional)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Only format integral part
|
||||||
|
if (input.contains(Token.DisplayOnly.fraction)) {
|
||||||
|
val (integral, fraction) = input.split(" ")
|
||||||
|
return "${integral.formatNumber(formatterSymbols)} $fraction"
|
||||||
|
}
|
||||||
|
|
||||||
numbersRegex
|
numbersRegex
|
||||||
.findAll(input)
|
.findAll(input)
|
||||||
.map(MatchResult::value)
|
.map(MatchResult::value)
|
||||||
@ -89,7 +104,7 @@ private fun String.formatNumber(
|
|||||||
return output.plus(remainingPart.replace(".", formatterSymbols.fractional))
|
return output.plus(remainingPart.replace(".", formatterSymbols.fractional))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun String.cleanIt(legalTokens: List<String>): String {
|
private fun String.leaveLegalTokensOnly(legalTokens: List<String>): String {
|
||||||
val streamOfTokens = this
|
val streamOfTokens = this
|
||||||
|
|
||||||
fun peekTokenAfter(cursor: Int): String? {
|
fun peekTokenAfter(cursor: Int): String? {
|
||||||
|
@ -76,29 +76,34 @@ fun ExpressionTextField(
|
|||||||
readOnly: Boolean = false,
|
readOnly: Boolean = false,
|
||||||
placeholder: String = "",
|
placeholder: String = "",
|
||||||
) {
|
) {
|
||||||
|
val localView = LocalView.current
|
||||||
val clipboardManager = LocalClipboardManager.current
|
val clipboardManager = LocalClipboardManager.current
|
||||||
|
val expressionTransformer = remember(formatterSymbols) { ExpressionTransformer(formatterSymbols) }
|
||||||
|
|
||||||
fun copyCallback() {
|
fun copyCallback() {
|
||||||
clipboardManager.copyWithoutGrouping(value, formatterSymbols)
|
clipboardManager.copyWithoutGrouping(value, formatterSymbols)
|
||||||
onCursorChange(TextRange(value.selection.end))
|
onCursorChange(TextRange(value.selection.end))
|
||||||
}
|
}
|
||||||
|
|
||||||
val textToolbar: UnittoTextToolbar = if (readOnly) {
|
val textToolbar: UnittoTextToolbar = remember(readOnly) {
|
||||||
UnittoTextToolbar(
|
if (readOnly) {
|
||||||
view = LocalView.current,
|
UnittoTextToolbar(
|
||||||
copyCallback = ::copyCallback,
|
view = localView,
|
||||||
)
|
copyCallback = ::copyCallback,
|
||||||
} else {
|
)
|
||||||
UnittoTextToolbar(
|
} else {
|
||||||
view = LocalView.current,
|
UnittoTextToolbar(
|
||||||
copyCallback = ::copyCallback,
|
view = localView,
|
||||||
pasteCallback = {
|
copyCallback = ::copyCallback,
|
||||||
pasteCallback(clipboardManager.getText()?.text?.clearAndFilterExpression(formatterSymbols) ?: "")
|
pasteCallback = {
|
||||||
},
|
pasteCallback(clipboardManager.getText()?.text?.clearAndFilterExpression(formatterSymbols) ?: "")
|
||||||
cutCallback = {
|
},
|
||||||
clipboardManager.copyWithoutGrouping(value, formatterSymbols)
|
cutCallback = {
|
||||||
cutCallback()
|
clipboardManager.copyWithoutGrouping(value, formatterSymbols)
|
||||||
}
|
cutCallback()
|
||||||
)
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AutoSizableTextField(
|
AutoSizableTextField(
|
||||||
@ -111,7 +116,7 @@ fun ExpressionTextField(
|
|||||||
readOnly = readOnly,
|
readOnly = readOnly,
|
||||||
showToolbar = textToolbar::showMenu,
|
showToolbar = textToolbar::showMenu,
|
||||||
hideToolbar = textToolbar::hide,
|
hideToolbar = textToolbar::hide,
|
||||||
visualTransformation = ExpressionTransformer(formatterSymbols),
|
visualTransformation = expressionTransformer,
|
||||||
placeholder = placeholder,
|
placeholder = placeholder,
|
||||||
textToolbar = textToolbar,
|
textToolbar = textToolbar,
|
||||||
)
|
)
|
||||||
@ -129,29 +134,32 @@ fun UnformattedTextField(
|
|||||||
readOnly: Boolean = false,
|
readOnly: Boolean = false,
|
||||||
placeholder: String = "",
|
placeholder: String = "",
|
||||||
) {
|
) {
|
||||||
|
val localView = LocalView.current
|
||||||
val clipboardManager = LocalClipboardManager.current
|
val clipboardManager = LocalClipboardManager.current
|
||||||
fun copyCallback() {
|
fun copyCallback() {
|
||||||
clipboardManager.copy(value)
|
clipboardManager.copy(value)
|
||||||
onCursorChange(TextRange(value.selection.end))
|
onCursorChange(TextRange(value.selection.end))
|
||||||
}
|
}
|
||||||
|
|
||||||
val textToolbar: UnittoTextToolbar = if (readOnly) {
|
val textToolbar: UnittoTextToolbar = remember(readOnly) {
|
||||||
UnittoTextToolbar(
|
if (readOnly) {
|
||||||
view = LocalView.current,
|
UnittoTextToolbar(
|
||||||
copyCallback = ::copyCallback,
|
view = localView,
|
||||||
)
|
copyCallback = ::copyCallback,
|
||||||
} else {
|
)
|
||||||
UnittoTextToolbar(
|
} else {
|
||||||
view = LocalView.current,
|
UnittoTextToolbar(
|
||||||
copyCallback = ::copyCallback,
|
view = localView,
|
||||||
pasteCallback = {
|
copyCallback = ::copyCallback,
|
||||||
pasteCallback(clipboardManager.getText()?.text?.clearAndFilterNumberBase() ?: "")
|
pasteCallback = {
|
||||||
},
|
pasteCallback(clipboardManager.getText()?.text?.clearAndFilterNumberBase() ?: "")
|
||||||
cutCallback = {
|
},
|
||||||
clipboardManager.copy(value)
|
cutCallback = {
|
||||||
cutCallback()
|
clipboardManager.copy(value)
|
||||||
}
|
cutCallback()
|
||||||
)
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AutoSizableTextField(
|
AutoSizableTextField(
|
||||||
|
@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sadellie.unitto.core.ui
|
||||||
|
|
||||||
|
import com.sadellie.unitto.core.ui.common.textfield.FormatterSymbols
|
||||||
|
import com.sadellie.unitto.core.ui.common.textfield.clearAndFilterExpression
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
class CleanAndFilterExpression {
|
||||||
|
@Test
|
||||||
|
fun noAdditionalSymbols() {
|
||||||
|
assertEquals("123", "123".clearAndFilterExpression(FormatterSymbols.Comma))
|
||||||
|
assertEquals("123.456", "123.456".clearAndFilterExpression(FormatterSymbols.Comma))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun hasFormatterSymbol() {
|
||||||
|
assertEquals("123456", "123,456".clearAndFilterExpression(FormatterSymbols.Comma))
|
||||||
|
assertEquals("123456.789", "123,456.789".clearAndFilterExpression(FormatterSymbols.Comma))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun hasWrongFormatterSymbol() {
|
||||||
|
assertEquals("123456", "123 456".clearAndFilterExpression(FormatterSymbols.Comma))
|
||||||
|
assertEquals("123456.789", "123 456.789".clearAndFilterExpression(FormatterSymbols.Comma))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun fractionExpression() {
|
||||||
|
assertEquals("1600+1234÷56789", "1,600 1234⁄56789".clearAndFilterExpression(FormatterSymbols.Comma))
|
||||||
|
assertEquals("123456.789+1234÷56789", "123,456.789 1234⁄56789".clearAndFilterExpression(FormatterSymbols.Comma))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun garbage() {
|
||||||
|
// 'e' is a known symbol
|
||||||
|
assertEquals("eeee−123", "pee pee poo poo -123".clearAndFilterExpression(FormatterSymbols.Comma))
|
||||||
|
assertEquals("eeee−123.456", "pee pee poo poo -123.456".clearAndFilterExpression(FormatterSymbols.Comma))
|
||||||
|
}
|
||||||
|
}
|
@ -27,42 +27,46 @@ class ExpressionTransformerTest {
|
|||||||
|
|
||||||
private val expr = ExpressionTransformer(FormatterSymbols.Comma)
|
private val expr = ExpressionTransformer(FormatterSymbols.Comma)
|
||||||
|
|
||||||
private fun origToTrans(orig: String, trans: String, offset: Int): Int =
|
// Use "|" for cursor
|
||||||
expr.ExpressionMapping(orig, trans).originalToTransformed(offset)
|
private fun origToTrans(orig: String, trans: String) {
|
||||||
|
val transformed = trans.replace("|", "")
|
||||||
|
val original = orig.replace("|", "")
|
||||||
|
|
||||||
private fun transToOrig(trans: String, orig: String, offset: Int): Int =
|
val offsetInTrans = trans.indexOf("|")
|
||||||
expr.ExpressionMapping(orig, trans).transformedToOriginal(offset)
|
val offsetInOrig = orig.indexOf("|")
|
||||||
|
|
||||||
|
val expressionMapping = expr.ExpressionMapping(original, transformed)
|
||||||
|
|
||||||
|
assertEquals(offsetInTrans, expressionMapping.originalToTransformed(offsetInOrig))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun transToOrig(trans: String, orig: String) {
|
||||||
|
val transformed = trans.replace("|", "")
|
||||||
|
val original = orig.replace("|", "")
|
||||||
|
|
||||||
|
val offsetInTrans = trans.indexOf("|")
|
||||||
|
val offsetInOrig = orig.indexOf("|")
|
||||||
|
|
||||||
|
val expressionMapping = expr.ExpressionMapping(original, transformed)
|
||||||
|
|
||||||
|
assertEquals(offsetInOrig, expressionMapping.transformedToOriginal(offsetInTrans))
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test 1234`() {
|
fun `test 1234`() {
|
||||||
// at the start
|
transToOrig("|123", "|123")
|
||||||
assertEquals(0, origToTrans("1,234", "1234", 0))
|
origToTrans("12|3", "12|3")
|
||||||
assertEquals(0, transToOrig("1,234", "1234", 0))
|
|
||||||
|
|
||||||
// somewhere in inside, no offset needed
|
transToOrig("|1,234", "|1234")
|
||||||
assertEquals(1, origToTrans("1234", "1,234", 1))
|
origToTrans("|1234", "|1,234")
|
||||||
assertEquals(1, transToOrig("1,234", "1234", 1))
|
|
||||||
|
|
||||||
// somewhere in inside, offset needed
|
transToOrig("1,234|", "1234|")
|
||||||
assertEquals(1, transToOrig("1,234", "1234", 2))
|
origToTrans("1234|", "1,234|")
|
||||||
|
|
||||||
// at the end
|
transToOrig("|cos(1)+1,234", "|cos(1)+1234")
|
||||||
assertEquals(5, origToTrans("1234", "1,234", 4))
|
origToTrans("co|s(1)+1234", "|cos(1)+1,234")
|
||||||
assertEquals(4, transToOrig("1,234", "1234", 5))
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
transToOrig("cos|(1)+1,234", "cos(|1)+1234")
|
||||||
fun `test 123`() {
|
origToTrans("cos|(1)+1234", "cos(|1)+1,234")
|
||||||
// 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))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,8 +32,9 @@ private const val INCOMPLETE_EXPR = "50+123456÷8×0.8-12+"
|
|||||||
private const val COMPLETE_EXPR = "50+123456÷8×0.8-12+0-√9×4^9+2×(9+8×7)"
|
private const val COMPLETE_EXPR = "50+123456÷8×0.8-12+0-√9×4^9+2×(9+8×7)"
|
||||||
private const val LONG_HALF_COMPLETE_EXPR = "50+123456÷89078..9×0.8-12+0-√9×4^9+2×(9+8×7)×sin(13sin123cos"
|
private const val LONG_HALF_COMPLETE_EXPR = "50+123456÷89078..9×0.8-12+0-√9×4^9+2×(9+8×7)×sin(13sin123cos"
|
||||||
private const val SOME_BRACKETS = "(((((((("
|
private const val SOME_BRACKETS = "(((((((("
|
||||||
|
private const val FRACTION_VALUE = "1600 1234⁄56789"
|
||||||
|
|
||||||
class FormatterTest {
|
class FormatterExpressionTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun setSeparatorSpaces() {
|
fun setSeparatorSpaces() {
|
||||||
@ -47,6 +48,7 @@ class FormatterTest {
|
|||||||
assertEquals("50+123 456÷8×0.8−12+0−√9×4^9+2×(9+8×7)", COMPLETE_EXPR.format())
|
assertEquals("50+123 456÷8×0.8−12+0−√9×4^9+2×(9+8×7)", COMPLETE_EXPR.format())
|
||||||
assertEquals("50+123 456÷89 078..9×0.8−12+0−√9×4^9+2×(9+8×7)×sin(13sin123cos", LONG_HALF_COMPLETE_EXPR.format())
|
assertEquals("50+123 456÷89 078..9×0.8−12+0−√9×4^9+2×(9+8×7)×sin(13sin123cos", LONG_HALF_COMPLETE_EXPR.format())
|
||||||
assertEquals("((((((((", SOME_BRACKETS.format())
|
assertEquals("((((((((", SOME_BRACKETS.format())
|
||||||
|
assertEquals("1 600 1234⁄56789", FRACTION_VALUE.format())
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -61,6 +63,7 @@ class FormatterTest {
|
|||||||
assertEquals("50+123,456÷8×0.8−12+0−√9×4^9+2×(9+8×7)", COMPLETE_EXPR.format())
|
assertEquals("50+123,456÷8×0.8−12+0−√9×4^9+2×(9+8×7)", COMPLETE_EXPR.format())
|
||||||
assertEquals("50+123,456÷89,078..9×0.8−12+0−√9×4^9+2×(9+8×7)×sin(13sin123cos", LONG_HALF_COMPLETE_EXPR.format())
|
assertEquals("50+123,456÷89,078..9×0.8−12+0−√9×4^9+2×(9+8×7)×sin(13sin123cos", LONG_HALF_COMPLETE_EXPR.format())
|
||||||
assertEquals("((((((((", SOME_BRACKETS.format())
|
assertEquals("((((((((", SOME_BRACKETS.format())
|
||||||
|
assertEquals("1,600 1234⁄56789", FRACTION_VALUE.format())
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -75,5 +78,6 @@ class FormatterTest {
|
|||||||
assertEquals("50+123.456÷8×0,8−12+0−√9×4^9+2×(9+8×7)", COMPLETE_EXPR.format())
|
assertEquals("50+123.456÷8×0,8−12+0−√9×4^9+2×(9+8×7)", COMPLETE_EXPR.format())
|
||||||
assertEquals("50+123.456÷89.078,,9×0,8−12+0−√9×4^9+2×(9+8×7)×sin(13sin123cos", LONG_HALF_COMPLETE_EXPR.format())
|
assertEquals("50+123.456÷89.078,,9×0,8−12+0−√9×4^9+2×(9+8×7)×sin(13sin123cos", LONG_HALF_COMPLETE_EXPR.format())
|
||||||
assertEquals("((((((((", SOME_BRACKETS.format())
|
assertEquals("((((((((", SOME_BRACKETS.format())
|
||||||
|
assertEquals("1.600 1234⁄56789", FRACTION_VALUE.format())
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -24,13 +24,25 @@ import java.math.BigDecimal
|
|||||||
import java.math.BigInteger
|
import java.math.BigInteger
|
||||||
import java.math.RoundingMode
|
import java.math.RoundingMode
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tries to convert [BigDecimal] into fractional string.
|
||||||
|
*
|
||||||
|
* 0.5 -> `1⁄2`
|
||||||
|
*
|
||||||
|
* 123.5 -> `123 1⁄2`
|
||||||
|
*
|
||||||
|
* 123 -> `Empty string`
|
||||||
|
*
|
||||||
|
* @receiver [BigDecimal]. Scale doesn't matter, but should be `MAX_PRECISION`
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
fun BigDecimal.toFractionalString(): String {
|
fun BigDecimal.toFractionalString(): String {
|
||||||
// https://www.khanacademy.org/math/cc-eighth-grade-math/cc-8th-numbers-operations/cc-8th-repeating-decimals/v/coverting-repeating-decimals-to-fractions-1
|
// https://www.khanacademy.org/math/cc-eighth-grade-math/cc-8th-numbers-operations/cc-8th-repeating-decimals/v/coverting-repeating-decimals-to-fractions-1
|
||||||
// https://www.khanacademy.org/math/cc-eighth-grade-math/cc-8th-numbers-operations/cc-8th-repeating-decimals/v/coverting-repeating-decimals-to-fractions-2
|
// https://www.khanacademy.org/math/cc-eighth-grade-math/cc-8th-numbers-operations/cc-8th-repeating-decimals/v/coverting-repeating-decimals-to-fractions-2
|
||||||
val (integral, fractional) = this.divideAndRemainder(BigDecimal.ONE)
|
val (integral, fractional) = this.divideAndRemainder(BigDecimal.ONE)
|
||||||
val integralBI = integral.toBigInteger()
|
val integralBI = integral.toBigInteger()
|
||||||
|
|
||||||
if (fractional.isEqualTo(BigDecimal.ZERO)) return integralBI.toString()
|
if (fractional.isEqualTo(BigDecimal.ZERO)) return ""
|
||||||
|
|
||||||
val res: String = if (integral.isEqualTo(BigDecimal.ZERO)) "" else "$integralBI "
|
val res: String = if (integral.isEqualTo(BigDecimal.ZERO)) "" else "$integralBI "
|
||||||
|
|
||||||
|
@ -116,7 +116,7 @@ fun TextBox(
|
|||||||
var outputTF by remember(output) {
|
var outputTF by remember(output) {
|
||||||
mutableStateOf(TextFieldValue(output.text))
|
mutableStateOf(TextFieldValue(output.text))
|
||||||
}
|
}
|
||||||
UnformattedTextField(
|
ExpressionTextField(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.weight(2f)
|
.weight(2f)
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
@ -124,6 +124,7 @@ fun TextBox(
|
|||||||
value = outputTF,
|
value = outputTF,
|
||||||
minRatio = 1f,
|
minRatio = 1f,
|
||||||
onCursorChange = { outputTF = outputTF.copy(selection = it) },
|
onCursorChange = { outputTF = outputTF.copy(selection = it) },
|
||||||
|
formatterSymbols = formatterSymbols,
|
||||||
textColor = MaterialTheme.colorScheme.onSurfaceVariant.copy(0.6f),
|
textColor = MaterialTheme.colorScheme.onSurfaceVariant.copy(0.6f),
|
||||||
readOnly = true,
|
readOnly = true,
|
||||||
)
|
)
|
||||||
|
@ -26,13 +26,13 @@ class DecimalToFractionTest {
|
|||||||
@Test
|
@Test
|
||||||
fun testNoDecimal1() {
|
fun testNoDecimal1() {
|
||||||
val bd = BigDecimal("100")
|
val bd = BigDecimal("100")
|
||||||
assertFractional("100", bd.toFractionalString())
|
assertFractional("", bd.toFractionalString())
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testNoDecimal2() {
|
fun testNoDecimal2() {
|
||||||
val bd = BigDecimal("100.000000000")
|
val bd = BigDecimal("100.000000000")
|
||||||
assertFractional("100", bd.toFractionalString())
|
assertFractional("", bd.toFractionalString())
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
Loading…
x
Reference in New Issue
Block a user