mirror of
https://github.com/Myzel394/NumberHub.git
synced 2025-06-19 00:35:26 +02:00
Added Number base converter #14
This commit is contained in:
parent
9308398d77
commit
b1c8780fc1
@ -29,6 +29,13 @@ const val KEY_8 = "8"
|
||||
const val KEY_9 = "9"
|
||||
const val KEY_0 = "0"
|
||||
|
||||
const val KEY_BASE_A = "A"
|
||||
const val KEY_BASE_B = "B"
|
||||
const val KEY_BASE_C = "C"
|
||||
const val KEY_BASE_D = "D"
|
||||
const val KEY_BASE_E = "E"
|
||||
const val KEY_BASE_F = "F"
|
||||
|
||||
const val KEY_DOT = "."
|
||||
const val KEY_COMMA = ","
|
||||
const val KEY_CLEAR = "<"
|
||||
|
@ -62,6 +62,7 @@ class AllUnitsRepository @Inject constructor() {
|
||||
UnitGroup.ANGLE to angleCollection,
|
||||
UnitGroup.DATA_TRANSFER to dataTransferCollection,
|
||||
UnitGroup.FLUX to fluxCollection,
|
||||
UnitGroup.NUMBER_BASE to numberBaseCollection,
|
||||
)
|
||||
}
|
||||
|
||||
@ -762,4 +763,23 @@ class AllUnitsRepository @Inject constructor() {
|
||||
MyUnit(MyUnitIDS.gigaweber, BigDecimal.valueOf(100000000000000000), UnitGroup.FLUX, R.string.gigaweber, R.string.gigaweber_short),
|
||||
)
|
||||
}
|
||||
private val numberBaseCollection: List<AbstractUnit> by lazy {
|
||||
listOf(
|
||||
NumberBaseUnit(MyUnitIDS.binary, 2, UnitGroup.NUMBER_BASE, R.string.binary, R.string.binary_short),
|
||||
NumberBaseUnit(MyUnitIDS.ternary, 3, UnitGroup.NUMBER_BASE, R.string.ternary, R.string.ternary_short),
|
||||
NumberBaseUnit(MyUnitIDS.quaternary, 4, UnitGroup.NUMBER_BASE, R.string.quaternary, R.string.quaternary_short),
|
||||
NumberBaseUnit(MyUnitIDS.quinary, 5, UnitGroup.NUMBER_BASE, R.string.quinary, R.string.quinary_short),
|
||||
NumberBaseUnit(MyUnitIDS.senary, 6, UnitGroup.NUMBER_BASE, R.string.senary, R.string.senary_short),
|
||||
NumberBaseUnit(MyUnitIDS.septenary, 7, UnitGroup.NUMBER_BASE, R.string.septenary, R.string.septenary_short),
|
||||
NumberBaseUnit(MyUnitIDS.octal, 8, UnitGroup.NUMBER_BASE, R.string.octal, R.string.octal_short),
|
||||
NumberBaseUnit(MyUnitIDS.nonary, 9, UnitGroup.NUMBER_BASE, R.string.nonary, R.string.nonary_short),
|
||||
NumberBaseUnit(MyUnitIDS.decimal, 10, UnitGroup.NUMBER_BASE, R.string.decimal, R.string.decimal_short),
|
||||
NumberBaseUnit(MyUnitIDS.undecimal, 11, UnitGroup.NUMBER_BASE, R.string.undecimal, R.string.undecimal_short),
|
||||
NumberBaseUnit(MyUnitIDS.duodecimal, 12, UnitGroup.NUMBER_BASE, R.string.duodecimal, R.string.duodecimal_short),
|
||||
NumberBaseUnit(MyUnitIDS.tridecimal, 13, UnitGroup.NUMBER_BASE, R.string.tridecimal, R.string.tridecimal_short),
|
||||
NumberBaseUnit(MyUnitIDS.tetradecimal, 14, UnitGroup.NUMBER_BASE, R.string.tetradecimal, R.string.tetradecimal_short),
|
||||
NumberBaseUnit(MyUnitIDS.pentadecimal, 15, UnitGroup.NUMBER_BASE, R.string.pentadecimal, R.string.pentadecimal_short),
|
||||
NumberBaseUnit(MyUnitIDS.hexadecimal, 16, UnitGroup.NUMBER_BASE, R.string.hexadecimal, R.string.hexadecimal_short),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -495,4 +495,21 @@ object MyUnitIDS {
|
||||
const val kiloweber = "kiloweber"
|
||||
const val megaweber = "megaweber"
|
||||
const val gigaweber = "gigaweber"
|
||||
|
||||
// NUMBER BASE
|
||||
const val binary = "binary"
|
||||
const val ternary = "ternary"
|
||||
const val quaternary = "quaternary"
|
||||
const val quinary = "quinary"
|
||||
const val senary = "senary"
|
||||
const val septenary = "septenary"
|
||||
const val octal = "octal"
|
||||
const val nonary = "nonary"
|
||||
const val decimal = "decimal"
|
||||
const val undecimal = "undecimal"
|
||||
const val duodecimal = "duodecimal"
|
||||
const val tridecimal = "tridecimal"
|
||||
const val tetradecimal = "tetradecimal"
|
||||
const val pentadecimal = "pentadecimal"
|
||||
const val hexadecimal = "hexadecimal"
|
||||
}
|
||||
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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.data.units
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import java.math.BigDecimal
|
||||
|
||||
class NumberBaseUnit(
|
||||
unitId: String,
|
||||
val base: Int,
|
||||
group: UnitGroup,
|
||||
@StringRes displayName: Int,
|
||||
@StringRes shortName: Int,
|
||||
) : AbstractUnit(
|
||||
unitId = unitId,
|
||||
displayName = displayName,
|
||||
shortName = shortName,
|
||||
basicUnit = BigDecimal.ONE,
|
||||
group = group,
|
||||
) {
|
||||
override fun convert(unitTo: AbstractUnit, value: BigDecimal, scale: Int): BigDecimal = this.basicUnit
|
||||
|
||||
fun convertToBase(input: String, toBase: Int): String {
|
||||
return input.toBigInteger(base).toString(toBase)
|
||||
}
|
||||
|
||||
}
|
@ -49,4 +49,5 @@ enum class UnitGroup(
|
||||
ANGLE(res = R.string.angle),
|
||||
DATA_TRANSFER(res = R.string.data_transfer),
|
||||
FLUX(res = R.string.flux),
|
||||
NUMBER_BASE(res = R.string.number_base),
|
||||
}
|
||||
|
@ -40,6 +40,7 @@ import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.sadellie.unitto.R
|
||||
import com.sadellie.unitto.data.NavRoutes.SETTINGS_SCREEN
|
||||
import com.sadellie.unitto.data.units.AbstractUnit
|
||||
import com.sadellie.unitto.data.units.UnitGroup
|
||||
import com.sadellie.unitto.screens.common.AnimatedTopBarText
|
||||
import com.sadellie.unitto.screens.main.components.Keyboard
|
||||
import com.sadellie.unitto.screens.main.components.TopScreenPart
|
||||
@ -81,8 +82,10 @@ fun MainScreen(
|
||||
navControllerAction = { navControllerAction(it) },
|
||||
swapMeasurements = { viewModel.swapUnits() },
|
||||
processInput = { viewModel.processInput(it) },
|
||||
deleteDigit = { viewModel.deleteDigit() }
|
||||
) { viewModel.clearInput() }
|
||||
deleteDigit = { viewModel.deleteDigit() },
|
||||
clearInput = { viewModel.clearInput() },
|
||||
baseConverterMode = viewModel.unitFrom.group == UnitGroup.NUMBER_BASE
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
@ -108,6 +111,7 @@ private fun MainScreenContent(
|
||||
processInput: (String) -> Unit = {},
|
||||
deleteDigit: () -> Unit = {},
|
||||
clearInput: () -> Unit = {},
|
||||
baseConverterMode: Boolean,
|
||||
) {
|
||||
PortraitLandscape(
|
||||
modifier = modifier,
|
||||
@ -123,7 +127,8 @@ private fun MainScreenContent(
|
||||
loadingNetwork = mainScreenUIState.isLoadingNetwork,
|
||||
networkError = mainScreenUIState.showError,
|
||||
onUnitSelectionClick = navControllerAction,
|
||||
swapUnits = swapMeasurements
|
||||
swapUnits = swapMeasurements,
|
||||
baseConverterMode = baseConverterMode,
|
||||
)
|
||||
},
|
||||
content2 = {
|
||||
@ -132,6 +137,7 @@ private fun MainScreenContent(
|
||||
addDigit = processInput,
|
||||
deleteDigit = deleteDigit,
|
||||
clearInput = clearInput,
|
||||
baseConverter = baseConverterMode,
|
||||
)
|
||||
}
|
||||
)
|
||||
|
@ -49,19 +49,20 @@ import com.sadellie.unitto.data.KEY_PLUS
|
||||
import com.sadellie.unitto.data.KEY_RIGHT_BRACKET
|
||||
import com.sadellie.unitto.data.KEY_SQRT
|
||||
import com.sadellie.unitto.data.OPERATORS
|
||||
import com.sadellie.unitto.data.combine
|
||||
import com.sadellie.unitto.data.preferences.UserPreferences
|
||||
import com.sadellie.unitto.data.preferences.UserPreferencesRepository
|
||||
import com.sadellie.unitto.data.toStringWith
|
||||
import com.sadellie.unitto.data.trimZeros
|
||||
import com.sadellie.unitto.data.units.AbstractUnit
|
||||
import com.sadellie.unitto.data.units.AllUnitsRepository
|
||||
import com.sadellie.unitto.data.units.MyUnitIDS
|
||||
import com.sadellie.unitto.data.units.NumberBaseUnit
|
||||
import com.sadellie.unitto.data.units.UnitGroup
|
||||
import com.sadellie.unitto.data.units.database.MyBasedUnit
|
||||
import com.sadellie.unitto.data.units.database.MyBasedUnitsRepository
|
||||
import com.sadellie.unitto.data.units.remote.CurrencyApi
|
||||
import com.sadellie.unitto.data.units.remote.CurrencyUnitResponse
|
||||
import com.sadellie.unitto.data.combine
|
||||
import com.sadellie.unitto.data.toStringWith
|
||||
import com.sadellie.unitto.data.trimZeros
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.cancel
|
||||
@ -134,10 +135,35 @@ class MainViewModel @Inject constructor(
|
||||
var unitTo: AbstractUnit by mutableStateOf(allUnitsRepository.getById(MyUnitIDS.mile))
|
||||
private set
|
||||
|
||||
/**
|
||||
* This function takes local variables, converts values and then causes the UI to update
|
||||
*/
|
||||
private suspend fun convertInput() {
|
||||
private suspend fun convertAsNumberBase() {
|
||||
withContext(Dispatchers.Default) {
|
||||
while (isActive) {
|
||||
val conversionResult = try {
|
||||
(unitFrom as NumberBaseUnit).convertToBase(
|
||||
input = input.value,
|
||||
toBase = (unitTo as NumberBaseUnit).base,
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
when (e) {
|
||||
is NumberFormatException, is IllegalArgumentException -> {
|
||||
""
|
||||
}
|
||||
is ClassCastException -> {
|
||||
cancel()
|
||||
return@withContext
|
||||
}
|
||||
else -> {
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
_result.update { conversionResult }
|
||||
cancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun convertAsExpression() {
|
||||
withContext(Dispatchers.Default) {
|
||||
while (isActive) {
|
||||
// First we clean the input from garbage at the end
|
||||
@ -195,12 +221,34 @@ class MainViewModel @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function takes local variables, converts values and then causes the UI to update
|
||||
*/
|
||||
private suspend fun convertInput() {
|
||||
if (unitFrom.group == UnitGroup.NUMBER_BASE) {
|
||||
convertAsNumberBase()
|
||||
} else {
|
||||
convertAsExpression()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Change left side unit. Unit to convert from
|
||||
*
|
||||
* @param clickedUnit Unit we need to change to
|
||||
*/
|
||||
fun changeUnitFrom(clickedUnit: AbstractUnit) {
|
||||
// Do we change to NumberBase?
|
||||
if ((unitFrom.group != UnitGroup.NUMBER_BASE) and (clickedUnit.group == UnitGroup.NUMBER_BASE)) {
|
||||
// It was not NUMBER_BASE, but now we change to it. Clear input.
|
||||
clearInput()
|
||||
}
|
||||
|
||||
if ((unitFrom.group == UnitGroup.NUMBER_BASE) and (clickedUnit.group != UnitGroup.NUMBER_BASE)) {
|
||||
// It was NUMBER_BASE, but now we change to something else. Clear input.
|
||||
clearInput()
|
||||
}
|
||||
|
||||
// First we change unit
|
||||
unitFrom = clickedUnit
|
||||
|
||||
@ -512,12 +560,8 @@ class MainViewModel @Inject constructor(
|
||||
/**
|
||||
* Returns value to be used when converting value on the right side screen (unit selection)
|
||||
*/
|
||||
fun inputValue(): BigDecimal? {
|
||||
return try {
|
||||
(mainFlow.value.calculatedValue ?: mainFlow.value.inputValue).toBigDecimal()
|
||||
} catch (e: NumberFormatException) {
|
||||
null
|
||||
}
|
||||
fun inputValue(): String {
|
||||
return mainFlow.value.calculatedValue ?: mainFlow.value.inputValue
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -24,7 +24,6 @@ import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.sadellie.unitto.data.KEY_0
|
||||
import com.sadellie.unitto.data.KEY_1
|
||||
@ -36,6 +35,12 @@ import com.sadellie.unitto.data.KEY_6
|
||||
import com.sadellie.unitto.data.KEY_7
|
||||
import com.sadellie.unitto.data.KEY_8
|
||||
import com.sadellie.unitto.data.KEY_9
|
||||
import com.sadellie.unitto.data.KEY_BASE_A
|
||||
import com.sadellie.unitto.data.KEY_BASE_B
|
||||
import com.sadellie.unitto.data.KEY_BASE_C
|
||||
import com.sadellie.unitto.data.KEY_BASE_D
|
||||
import com.sadellie.unitto.data.KEY_BASE_E
|
||||
import com.sadellie.unitto.data.KEY_BASE_F
|
||||
import com.sadellie.unitto.data.KEY_CLEAR
|
||||
import com.sadellie.unitto.data.KEY_DIVIDE
|
||||
import com.sadellie.unitto.data.KEY_DIVIDE_DISPLAY
|
||||
@ -58,13 +63,15 @@ import com.sadellie.unitto.screens.Formatter
|
||||
* @param addDigit Function that is called when clicking number and dot buttons
|
||||
* @param deleteDigit Function that is called when clicking delete "<" button
|
||||
* @param clearInput Function that is called when clicking clear "AC" button
|
||||
* @param baseConverter When True will use layout for base conversion.
|
||||
*/
|
||||
@Composable
|
||||
fun Keyboard(
|
||||
modifier: Modifier = Modifier,
|
||||
addDigit: (String) -> Unit = {},
|
||||
deleteDigit: () -> Unit = {},
|
||||
clearInput: () -> Unit = {}
|
||||
clearInput: () -> Unit = {},
|
||||
baseConverter: Boolean = false,
|
||||
) {
|
||||
Column(
|
||||
modifier = modifier.fillMaxSize()
|
||||
@ -76,41 +83,67 @@ fun Keyboard(
|
||||
.padding(4.dp)
|
||||
// Column modifier
|
||||
val cModifier = Modifier.weight(1f)
|
||||
Row(cModifier) {
|
||||
KeyboardButton(bModifier, KEY_LEFT_BRACKET, isPrimary = false, onClick = addDigit)
|
||||
KeyboardButton(bModifier, KEY_RIGHT_BRACKET, isPrimary = false, onClick = addDigit)
|
||||
KeyboardButton(bModifier, KEY_EXPONENT, isPrimary = false, onClick = { addDigit(KEY_EXPONENT) })
|
||||
KeyboardButton(bModifier, KEY_SQRT, isPrimary = false, onClick = { addDigit(KEY_SQRT) })
|
||||
}
|
||||
Row(cModifier) {
|
||||
KeyboardButton(bModifier, KEY_7, onClick = addDigit)
|
||||
KeyboardButton(bModifier, KEY_8, onClick = addDigit)
|
||||
KeyboardButton(bModifier, KEY_9, onClick = addDigit)
|
||||
KeyboardButton(bModifier, KEY_DIVIDE_DISPLAY, isPrimary = false) { addDigit(KEY_DIVIDE) }
|
||||
}
|
||||
Row(cModifier) {
|
||||
KeyboardButton(bModifier, KEY_4, onClick = addDigit)
|
||||
KeyboardButton(bModifier, KEY_5, onClick = addDigit)
|
||||
KeyboardButton(bModifier, KEY_6, onClick = addDigit)
|
||||
KeyboardButton(bModifier, KEY_MULTIPLY_DISPLAY, isPrimary = false) { addDigit(KEY_MULTIPLY) }
|
||||
}
|
||||
Row(cModifier) {
|
||||
KeyboardButton(bModifier, KEY_1, onClick = addDigit)
|
||||
KeyboardButton(bModifier, KEY_2, onClick = addDigit)
|
||||
KeyboardButton(bModifier, KEY_3, onClick = addDigit)
|
||||
KeyboardButton(bModifier, KEY_MINUS_DISPLAY, isPrimary = false) { addDigit(KEY_MINUS) }
|
||||
}
|
||||
Row(cModifier) {
|
||||
KeyboardButton(bModifier, KEY_0, onClick = addDigit)
|
||||
KeyboardButton(bModifier, Formatter.fractional) { addDigit(KEY_DOT) }
|
||||
KeyboardButton(Modifier.fillMaxSize().weight(2f).padding(4.dp), KEY_CLEAR, onLongClick = clearInput) { deleteDigit() }
|
||||
KeyboardButton(bModifier, KEY_PLUS, isPrimary = false) { addDigit(KEY_PLUS) }
|
||||
if (baseConverter) {
|
||||
Row(cModifier) {
|
||||
KeyboardButton(bModifier, KEY_BASE_A, isPrimary = false, onClick = addDigit)
|
||||
KeyboardButton(bModifier, KEY_BASE_B, isPrimary = false, onClick = addDigit)
|
||||
KeyboardButton(bModifier, KEY_BASE_C, isPrimary = false, onClick = addDigit)
|
||||
}
|
||||
Row(cModifier) {
|
||||
KeyboardButton(bModifier, KEY_BASE_D, isPrimary = false, onClick = addDigit)
|
||||
KeyboardButton(bModifier, KEY_BASE_E, isPrimary = false, onClick = addDigit)
|
||||
KeyboardButton(bModifier, KEY_BASE_F, isPrimary = false, onClick = addDigit)
|
||||
}
|
||||
Row(cModifier) {
|
||||
KeyboardButton(bModifier, KEY_7, onClick = addDigit)
|
||||
KeyboardButton(bModifier, KEY_8, onClick = addDigit)
|
||||
KeyboardButton(bModifier, KEY_9, onClick = addDigit)
|
||||
}
|
||||
Row(cModifier) {
|
||||
KeyboardButton(bModifier, KEY_4, onClick = addDigit)
|
||||
KeyboardButton(bModifier, KEY_5, onClick = addDigit)
|
||||
KeyboardButton(bModifier, KEY_6, onClick = addDigit)
|
||||
}
|
||||
Row(cModifier) {
|
||||
KeyboardButton(bModifier, KEY_1, onClick = addDigit)
|
||||
KeyboardButton(bModifier, KEY_2, onClick = addDigit)
|
||||
KeyboardButton(bModifier, KEY_3, onClick = addDigit)
|
||||
}
|
||||
Row(cModifier) {
|
||||
KeyboardButton(bModifier, KEY_0, onClick = addDigit)
|
||||
KeyboardButton(Modifier.fillMaxSize().weight(2f).padding(4.dp), KEY_CLEAR, onLongClick = clearInput) { deleteDigit() }
|
||||
}
|
||||
} else {
|
||||
Row(cModifier) {
|
||||
KeyboardButton(bModifier, KEY_LEFT_BRACKET, isPrimary = false, onClick = addDigit)
|
||||
KeyboardButton(bModifier, KEY_RIGHT_BRACKET, isPrimary = false, onClick = addDigit)
|
||||
KeyboardButton(bModifier, KEY_EXPONENT, isPrimary = false, onClick = { addDigit(KEY_EXPONENT) })
|
||||
KeyboardButton(bModifier, KEY_SQRT, isPrimary = false, onClick = { addDigit(KEY_SQRT) })
|
||||
}
|
||||
Row(cModifier) {
|
||||
KeyboardButton(bModifier, KEY_7, onClick = addDigit)
|
||||
KeyboardButton(bModifier, KEY_8, onClick = addDigit)
|
||||
KeyboardButton(bModifier, KEY_9, onClick = addDigit)
|
||||
KeyboardButton(bModifier, KEY_DIVIDE_DISPLAY, isPrimary = false) { addDigit(KEY_DIVIDE) }
|
||||
}
|
||||
Row(cModifier) {
|
||||
KeyboardButton(bModifier, KEY_4, onClick = addDigit)
|
||||
KeyboardButton(bModifier, KEY_5, onClick = addDigit)
|
||||
KeyboardButton(bModifier, KEY_6, onClick = addDigit)
|
||||
KeyboardButton(bModifier, KEY_MULTIPLY_DISPLAY, isPrimary = false) { addDigit(KEY_MULTIPLY) }
|
||||
}
|
||||
Row(cModifier) {
|
||||
KeyboardButton(bModifier, KEY_1, onClick = addDigit)
|
||||
KeyboardButton(bModifier, KEY_2, onClick = addDigit)
|
||||
KeyboardButton(bModifier, KEY_3, onClick = addDigit)
|
||||
KeyboardButton(bModifier, KEY_MINUS_DISPLAY, isPrimary = false) { addDigit(KEY_MINUS) }
|
||||
}
|
||||
Row(cModifier) {
|
||||
KeyboardButton(bModifier, KEY_0, onClick = addDigit)
|
||||
KeyboardButton(bModifier, Formatter.fractional) { addDigit(KEY_DOT) }
|
||||
KeyboardButton(bModifier, KEY_CLEAR, onLongClick = clearInput) { deleteDigit() }
|
||||
KeyboardButton(bModifier, KEY_PLUS, isPrimary = false) { addDigit(KEY_PLUS) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun PreviewKeyboard() {
|
||||
Keyboard()
|
||||
}
|
||||
|
@ -76,7 +76,8 @@ fun TopScreenPart(
|
||||
loadingNetwork: Boolean,
|
||||
networkError: Boolean,
|
||||
onUnitSelectionClick: (String) -> Unit,
|
||||
swapUnits: () -> Unit
|
||||
swapUnits: () -> Unit,
|
||||
baseConverterMode: Boolean,
|
||||
) {
|
||||
var swapped by remember { mutableStateOf(false) }
|
||||
val swapButtonRotation: Float by animateFloatAsState(
|
||||
@ -94,6 +95,7 @@ fun TopScreenPart(
|
||||
when {
|
||||
loadingDatabase || loadingNetwork -> stringResource(R.string.loading_label)
|
||||
networkError -> stringResource(R.string.error_label)
|
||||
baseConverterMode -> inputValue.uppercase()
|
||||
else -> Formatter.format(inputValue)
|
||||
}
|
||||
},
|
||||
@ -107,6 +109,7 @@ fun TopScreenPart(
|
||||
when {
|
||||
loadingDatabase || loadingNetwork -> stringResource(R.string.loading_label)
|
||||
networkError -> stringResource(R.string.error_label)
|
||||
baseConverterMode -> outputValue.uppercase()
|
||||
else -> Formatter.format(outputValue)
|
||||
}
|
||||
},
|
||||
|
@ -48,6 +48,7 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.sadellie.unitto.R
|
||||
import com.sadellie.unitto.data.units.AbstractUnit
|
||||
import com.sadellie.unitto.data.units.NumberBaseUnit
|
||||
import com.sadellie.unitto.data.units.UnitGroup
|
||||
import com.sadellie.unitto.screens.Formatter
|
||||
import com.sadellie.unitto.screens.common.Header
|
||||
@ -174,12 +175,27 @@ fun RightSideScreen(
|
||||
navigateUp: () -> Unit,
|
||||
navigateToSettingsAction: () -> Unit,
|
||||
selectAction: (AbstractUnit) -> Unit,
|
||||
inputValue: BigDecimal?,
|
||||
inputValue: String,
|
||||
unitFrom: AbstractUnit
|
||||
) {
|
||||
val uiState = viewModel.mainFlow.collectAsStateWithLifecycle()
|
||||
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
|
||||
val focusManager = LocalFocusManager.current
|
||||
val inputAsBigDecimal: BigDecimal? = try {
|
||||
inputValue.toBigDecimal()
|
||||
} catch (e: NumberFormatException) {
|
||||
null
|
||||
}
|
||||
|
||||
val convertMethod: (AbstractUnit) -> String = when {
|
||||
unitFrom.group == UnitGroup.NUMBER_BASE -> {{
|
||||
convertForSecondaryNumberBase(inputValue, unitFrom as NumberBaseUnit, it as NumberBaseUnit)
|
||||
}}
|
||||
inputAsBigDecimal != null -> {{
|
||||
convertForSecondary(inputAsBigDecimal, unitFrom, it)
|
||||
}}
|
||||
else -> {{""}}
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||
@ -224,13 +240,7 @@ fun RightSideScreen(
|
||||
navigateUp()
|
||||
},
|
||||
favoriteAction = { viewModel.favoriteUnit(it) },
|
||||
convertValue = {
|
||||
inputValue?.let {
|
||||
Formatter.format(
|
||||
unitFrom.convert(unit, it, 3).toPlainString()
|
||||
) + " "
|
||||
} ?: ""
|
||||
}
|
||||
convertValue = convertMethod
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -240,6 +250,20 @@ fun RightSideScreen(
|
||||
}
|
||||
}
|
||||
|
||||
internal fun convertForSecondary(inputValue: BigDecimal, unitFrom: AbstractUnit, unitTo: AbstractUnit): String {
|
||||
return Formatter.format(
|
||||
unitFrom.convert(unitTo, inputValue, 3).toPlainString() + " "
|
||||
)
|
||||
}
|
||||
|
||||
internal fun convertForSecondaryNumberBase(inputValue: String, unitFrom: NumberBaseUnit, unitTo: NumberBaseUnit): String {
|
||||
return try {
|
||||
unitFrom.convertToBase(inputValue, unitTo.base) + " "
|
||||
} catch (e: NumberFormatException) {
|
||||
""
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun UnitGroupHeader(modifier: Modifier, unitGroup: UnitGroup) {
|
||||
Header(
|
||||
|
@ -931,6 +931,38 @@
|
||||
<string name="gigaweber">Gigaweber</string>
|
||||
<string name="gigaweber_short">GWb</string>
|
||||
|
||||
<!--Number base-->
|
||||
<string name="binary">Binary</string>
|
||||
<string name="binary_short">base2</string>
|
||||
<string name="ternary">Ternary</string>
|
||||
<string name="ternary_short">base3</string>
|
||||
<string name="quaternary">Quaternary</string>
|
||||
<string name="quaternary_short">base4</string>
|
||||
<string name="quinary">Quinary</string>
|
||||
<string name="quinary_short">base5</string>
|
||||
<string name="senary">Senary</string>
|
||||
<string name="senary_short">base6</string>
|
||||
<string name="septenary">Septenary</string>
|
||||
<string name="septenary_short">base7</string>
|
||||
<string name="octal">Octal</string>
|
||||
<string name="octal_short">base8</string>
|
||||
<string name="nonary">Nonary</string>
|
||||
<string name="nonary_short">base9</string>
|
||||
<string name="decimal">Decimal</string>
|
||||
<string name="decimal_short">base10</string>
|
||||
<string name="undecimal">Undecimal</string>
|
||||
<string name="undecimal_short">base11</string>
|
||||
<string name="duodecimal">Duodecimal</string>
|
||||
<string name="duodecimal_short">base12</string>
|
||||
<string name="tridecimal">Tridecimal</string>
|
||||
<string name="tridecimal_short">base13</string>
|
||||
<string name="tetradecimal">Tetradecimal</string>
|
||||
<string name="tetradecimal_short">base14</string>
|
||||
<string name="pentadecimal">Pentadecimal</string>
|
||||
<string name="pentadecimal_short">base15</string>
|
||||
<string name="hexadecimal">Hexadecimal</string>
|
||||
<string name="hexadecimal_short">base16</string>
|
||||
|
||||
<!--Groups-->
|
||||
<string name="length">Length</string>
|
||||
<string name="time">Time</string>
|
||||
@ -948,6 +980,7 @@
|
||||
<string name="acceleration">Acceleration</string>
|
||||
<string name="currency">Currency</string>
|
||||
<string name="flux">Flux</string>
|
||||
<string name="number_base">Base</string>
|
||||
|
||||
<!--Screen names-->
|
||||
<string name="units_screen_from">Convert from</string>
|
||||
|
@ -351,15 +351,41 @@ class AllUnitsTest {
|
||||
MyUnitIDS.gigaweber.checkWith(MyUnitIDS.weber, "68.2", "68200000000")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNumberBase() {
|
||||
MyUnitIDS.binary.checkWith(MyUnitIDS.octal, "1000001001", "1011")
|
||||
MyUnitIDS.ternary.checkWith(MyUnitIDS.decimal, "10112020111", "69430")
|
||||
MyUnitIDS.quaternary.checkWith(MyUnitIDS.quinary, "20321", "4234")
|
||||
MyUnitIDS.quinary.checkWith(MyUnitIDS.nonary, "4234", "702")
|
||||
MyUnitIDS.senary.checkWith(MyUnitIDS.nonary, "4234", "1274")
|
||||
MyUnitIDS.septenary.checkWith(MyUnitIDS.nonary, "4234", "2041")
|
||||
MyUnitIDS.octal.checkWith(MyUnitIDS.undecimal, "42343277", "5107945")
|
||||
MyUnitIDS.nonary.checkWith(MyUnitIDS.duodecimal, "42343287", "69b9a81")
|
||||
MyUnitIDS.decimal.checkWith(MyUnitIDS.duodecimal, "42343287", "12220273")
|
||||
MyUnitIDS.undecimal.checkWith(MyUnitIDS.hexadecimal, "4234a287", "4e3f0c2")
|
||||
MyUnitIDS.duodecimal.checkWith(MyUnitIDS.hexadecimal, "4234a287", "8f30d07")
|
||||
MyUnitIDS.tridecimal.checkWith(MyUnitIDS.hexadecimal, "4234a287", "f9c3ff4")
|
||||
MyUnitIDS.tetradecimal.checkWith(MyUnitIDS.hexadecimal, "bb", "a5")
|
||||
MyUnitIDS.pentadecimal.checkWith(MyUnitIDS.hexadecimal, "BABE", "9a82")
|
||||
MyUnitIDS.hexadecimal.checkWith(MyUnitIDS.quinary, "FADE", "4023342")
|
||||
}
|
||||
|
||||
private fun String.checkWith(checkingId: String, value: String, expected: String) {
|
||||
val unit = allUnitsRepository.getById(this)
|
||||
val actual = unit
|
||||
.convert(allUnitsRepository.getById(checkingId), BigDecimal(value), 5)
|
||||
.toPlainString()
|
||||
val unitFrom = allUnitsRepository.getById(this)
|
||||
val unitTo = allUnitsRepository.getById(checkingId)
|
||||
|
||||
val actual = if (unitFrom.group == UnitGroup.NUMBER_BASE) {
|
||||
(unitFrom as NumberBaseUnit)
|
||||
.convertToBase(value, (unitTo as NumberBaseUnit).base)
|
||||
} else {
|
||||
unitFrom
|
||||
.convert(unitTo, BigDecimal(value), 5)
|
||||
.toPlainString()
|
||||
}
|
||||
assertEquals("Failed at $this to $checkingId", expected, actual)
|
||||
println("PASSED: $this -> $expected == $actual")
|
||||
val content: Set<String> = history.getOrDefault(unit.group, setOf())
|
||||
history[unit.group] = content.plus(this)
|
||||
val content: Set<String> = history.getOrDefault(unitFrom.group, setOf())
|
||||
history[unitFrom.group] = content.plus(this)
|
||||
}
|
||||
|
||||
@After
|
||||
|
Loading…
x
Reference in New Issue
Block a user