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_9 = "9"
|
||||||
const val KEY_0 = "0"
|
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_DOT = "."
|
||||||
const val KEY_COMMA = ","
|
const val KEY_COMMA = ","
|
||||||
const val KEY_CLEAR = "<"
|
const val KEY_CLEAR = "<"
|
||||||
|
@ -62,6 +62,7 @@ class AllUnitsRepository @Inject constructor() {
|
|||||||
UnitGroup.ANGLE to angleCollection,
|
UnitGroup.ANGLE to angleCollection,
|
||||||
UnitGroup.DATA_TRANSFER to dataTransferCollection,
|
UnitGroup.DATA_TRANSFER to dataTransferCollection,
|
||||||
UnitGroup.FLUX to fluxCollection,
|
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),
|
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 kiloweber = "kiloweber"
|
||||||
const val megaweber = "megaweber"
|
const val megaweber = "megaweber"
|
||||||
const val gigaweber = "gigaweber"
|
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),
|
ANGLE(res = R.string.angle),
|
||||||
DATA_TRANSFER(res = R.string.data_transfer),
|
DATA_TRANSFER(res = R.string.data_transfer),
|
||||||
FLUX(res = R.string.flux),
|
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.R
|
||||||
import com.sadellie.unitto.data.NavRoutes.SETTINGS_SCREEN
|
import com.sadellie.unitto.data.NavRoutes.SETTINGS_SCREEN
|
||||||
import com.sadellie.unitto.data.units.AbstractUnit
|
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.common.AnimatedTopBarText
|
||||||
import com.sadellie.unitto.screens.main.components.Keyboard
|
import com.sadellie.unitto.screens.main.components.Keyboard
|
||||||
import com.sadellie.unitto.screens.main.components.TopScreenPart
|
import com.sadellie.unitto.screens.main.components.TopScreenPart
|
||||||
@ -81,8 +82,10 @@ fun MainScreen(
|
|||||||
navControllerAction = { navControllerAction(it) },
|
navControllerAction = { navControllerAction(it) },
|
||||||
swapMeasurements = { viewModel.swapUnits() },
|
swapMeasurements = { viewModel.swapUnits() },
|
||||||
processInput = { viewModel.processInput(it) },
|
processInput = { viewModel.processInput(it) },
|
||||||
deleteDigit = { viewModel.deleteDigit() }
|
deleteDigit = { viewModel.deleteDigit() },
|
||||||
) { viewModel.clearInput() }
|
clearInput = { viewModel.clearInput() },
|
||||||
|
baseConverterMode = viewModel.unitFrom.group == UnitGroup.NUMBER_BASE
|
||||||
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -108,6 +111,7 @@ private fun MainScreenContent(
|
|||||||
processInput: (String) -> Unit = {},
|
processInput: (String) -> Unit = {},
|
||||||
deleteDigit: () -> Unit = {},
|
deleteDigit: () -> Unit = {},
|
||||||
clearInput: () -> Unit = {},
|
clearInput: () -> Unit = {},
|
||||||
|
baseConverterMode: Boolean,
|
||||||
) {
|
) {
|
||||||
PortraitLandscape(
|
PortraitLandscape(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
@ -123,7 +127,8 @@ private fun MainScreenContent(
|
|||||||
loadingNetwork = mainScreenUIState.isLoadingNetwork,
|
loadingNetwork = mainScreenUIState.isLoadingNetwork,
|
||||||
networkError = mainScreenUIState.showError,
|
networkError = mainScreenUIState.showError,
|
||||||
onUnitSelectionClick = navControllerAction,
|
onUnitSelectionClick = navControllerAction,
|
||||||
swapUnits = swapMeasurements
|
swapUnits = swapMeasurements,
|
||||||
|
baseConverterMode = baseConverterMode,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
content2 = {
|
content2 = {
|
||||||
@ -132,6 +137,7 @@ private fun MainScreenContent(
|
|||||||
addDigit = processInput,
|
addDigit = processInput,
|
||||||
deleteDigit = deleteDigit,
|
deleteDigit = deleteDigit,
|
||||||
clearInput = clearInput,
|
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_RIGHT_BRACKET
|
||||||
import com.sadellie.unitto.data.KEY_SQRT
|
import com.sadellie.unitto.data.KEY_SQRT
|
||||||
import com.sadellie.unitto.data.OPERATORS
|
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.UserPreferences
|
||||||
import com.sadellie.unitto.data.preferences.UserPreferencesRepository
|
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.AbstractUnit
|
||||||
import com.sadellie.unitto.data.units.AllUnitsRepository
|
import com.sadellie.unitto.data.units.AllUnitsRepository
|
||||||
import com.sadellie.unitto.data.units.MyUnitIDS
|
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.UnitGroup
|
||||||
import com.sadellie.unitto.data.units.database.MyBasedUnit
|
import com.sadellie.unitto.data.units.database.MyBasedUnit
|
||||||
import com.sadellie.unitto.data.units.database.MyBasedUnitsRepository
|
import com.sadellie.unitto.data.units.database.MyBasedUnitsRepository
|
||||||
import com.sadellie.unitto.data.units.remote.CurrencyApi
|
import com.sadellie.unitto.data.units.remote.CurrencyApi
|
||||||
import com.sadellie.unitto.data.units.remote.CurrencyUnitResponse
|
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 dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.cancel
|
import kotlinx.coroutines.cancel
|
||||||
@ -134,10 +135,35 @@ class MainViewModel @Inject constructor(
|
|||||||
var unitTo: AbstractUnit by mutableStateOf(allUnitsRepository.getById(MyUnitIDS.mile))
|
var unitTo: AbstractUnit by mutableStateOf(allUnitsRepository.getById(MyUnitIDS.mile))
|
||||||
private set
|
private set
|
||||||
|
|
||||||
/**
|
private suspend fun convertAsNumberBase() {
|
||||||
* This function takes local variables, converts values and then causes the UI to update
|
withContext(Dispatchers.Default) {
|
||||||
*/
|
while (isActive) {
|
||||||
private suspend fun convertInput() {
|
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) {
|
withContext(Dispatchers.Default) {
|
||||||
while (isActive) {
|
while (isActive) {
|
||||||
// First we clean the input from garbage at the end
|
// 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
|
* Change left side unit. Unit to convert from
|
||||||
*
|
*
|
||||||
* @param clickedUnit Unit we need to change to
|
* @param clickedUnit Unit we need to change to
|
||||||
*/
|
*/
|
||||||
fun changeUnitFrom(clickedUnit: AbstractUnit) {
|
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
|
// First we change unit
|
||||||
unitFrom = clickedUnit
|
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)
|
* Returns value to be used when converting value on the right side screen (unit selection)
|
||||||
*/
|
*/
|
||||||
fun inputValue(): BigDecimal? {
|
fun inputValue(): String {
|
||||||
return try {
|
return mainFlow.value.calculatedValue ?: mainFlow.value.inputValue
|
||||||
(mainFlow.value.calculatedValue ?: mainFlow.value.inputValue).toBigDecimal()
|
|
||||||
} catch (e: NumberFormatException) {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -24,7 +24,6 @@ import androidx.compose.foundation.layout.fillMaxSize
|
|||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.sadellie.unitto.data.KEY_0
|
import com.sadellie.unitto.data.KEY_0
|
||||||
import com.sadellie.unitto.data.KEY_1
|
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_7
|
||||||
import com.sadellie.unitto.data.KEY_8
|
import com.sadellie.unitto.data.KEY_8
|
||||||
import com.sadellie.unitto.data.KEY_9
|
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_CLEAR
|
||||||
import com.sadellie.unitto.data.KEY_DIVIDE
|
import com.sadellie.unitto.data.KEY_DIVIDE
|
||||||
import com.sadellie.unitto.data.KEY_DIVIDE_DISPLAY
|
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 addDigit Function that is called when clicking number and dot buttons
|
||||||
* @param deleteDigit Function that is called when clicking delete "<" button
|
* @param deleteDigit Function that is called when clicking delete "<" button
|
||||||
* @param clearInput Function that is called when clicking clear "AC" button
|
* @param clearInput Function that is called when clicking clear "AC" button
|
||||||
|
* @param baseConverter When True will use layout for base conversion.
|
||||||
*/
|
*/
|
||||||
@Composable
|
@Composable
|
||||||
fun Keyboard(
|
fun Keyboard(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
addDigit: (String) -> Unit = {},
|
addDigit: (String) -> Unit = {},
|
||||||
deleteDigit: () -> Unit = {},
|
deleteDigit: () -> Unit = {},
|
||||||
clearInput: () -> Unit = {}
|
clearInput: () -> Unit = {},
|
||||||
|
baseConverter: Boolean = false,
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
modifier = modifier.fillMaxSize()
|
modifier = modifier.fillMaxSize()
|
||||||
@ -76,41 +83,67 @@ fun Keyboard(
|
|||||||
.padding(4.dp)
|
.padding(4.dp)
|
||||||
// Column modifier
|
// Column modifier
|
||||||
val cModifier = Modifier.weight(1f)
|
val cModifier = Modifier.weight(1f)
|
||||||
Row(cModifier) {
|
if (baseConverter) {
|
||||||
KeyboardButton(bModifier, KEY_LEFT_BRACKET, isPrimary = false, onClick = addDigit)
|
Row(cModifier) {
|
||||||
KeyboardButton(bModifier, KEY_RIGHT_BRACKET, isPrimary = false, onClick = addDigit)
|
KeyboardButton(bModifier, KEY_BASE_A, isPrimary = false, onClick = addDigit)
|
||||||
KeyboardButton(bModifier, KEY_EXPONENT, isPrimary = false, onClick = { addDigit(KEY_EXPONENT) })
|
KeyboardButton(bModifier, KEY_BASE_B, isPrimary = false, onClick = addDigit)
|
||||||
KeyboardButton(bModifier, KEY_SQRT, isPrimary = false, onClick = { addDigit(KEY_SQRT) })
|
KeyboardButton(bModifier, KEY_BASE_C, isPrimary = false, onClick = addDigit)
|
||||||
}
|
}
|
||||||
Row(cModifier) {
|
Row(cModifier) {
|
||||||
KeyboardButton(bModifier, KEY_7, onClick = addDigit)
|
KeyboardButton(bModifier, KEY_BASE_D, isPrimary = false, onClick = addDigit)
|
||||||
KeyboardButton(bModifier, KEY_8, onClick = addDigit)
|
KeyboardButton(bModifier, KEY_BASE_E, isPrimary = false, onClick = addDigit)
|
||||||
KeyboardButton(bModifier, KEY_9, onClick = addDigit)
|
KeyboardButton(bModifier, KEY_BASE_F, isPrimary = false, onClick = addDigit)
|
||||||
KeyboardButton(bModifier, KEY_DIVIDE_DISPLAY, isPrimary = false) { addDigit(KEY_DIVIDE) }
|
}
|
||||||
}
|
Row(cModifier) {
|
||||||
Row(cModifier) {
|
KeyboardButton(bModifier, KEY_7, onClick = addDigit)
|
||||||
KeyboardButton(bModifier, KEY_4, onClick = addDigit)
|
KeyboardButton(bModifier, KEY_8, onClick = addDigit)
|
||||||
KeyboardButton(bModifier, KEY_5, onClick = addDigit)
|
KeyboardButton(bModifier, KEY_9, onClick = addDigit)
|
||||||
KeyboardButton(bModifier, KEY_6, onClick = addDigit)
|
}
|
||||||
KeyboardButton(bModifier, KEY_MULTIPLY_DISPLAY, isPrimary = false) { addDigit(KEY_MULTIPLY) }
|
Row(cModifier) {
|
||||||
}
|
KeyboardButton(bModifier, KEY_4, onClick = addDigit)
|
||||||
Row(cModifier) {
|
KeyboardButton(bModifier, KEY_5, onClick = addDigit)
|
||||||
KeyboardButton(bModifier, KEY_1, onClick = addDigit)
|
KeyboardButton(bModifier, KEY_6, onClick = addDigit)
|
||||||
KeyboardButton(bModifier, KEY_2, onClick = addDigit)
|
}
|
||||||
KeyboardButton(bModifier, KEY_3, onClick = addDigit)
|
Row(cModifier) {
|
||||||
KeyboardButton(bModifier, KEY_MINUS_DISPLAY, isPrimary = false) { addDigit(KEY_MINUS) }
|
KeyboardButton(bModifier, KEY_1, onClick = addDigit)
|
||||||
}
|
KeyboardButton(bModifier, KEY_2, onClick = addDigit)
|
||||||
Row(cModifier) {
|
KeyboardButton(bModifier, KEY_3, onClick = addDigit)
|
||||||
KeyboardButton(bModifier, KEY_0, onClick = addDigit)
|
}
|
||||||
KeyboardButton(bModifier, Formatter.fractional) { addDigit(KEY_DOT) }
|
Row(cModifier) {
|
||||||
KeyboardButton(Modifier.fillMaxSize().weight(2f).padding(4.dp), KEY_CLEAR, onLongClick = clearInput) { deleteDigit() }
|
KeyboardButton(bModifier, KEY_0, onClick = addDigit)
|
||||||
KeyboardButton(bModifier, KEY_PLUS, isPrimary = false) { addDigit(KEY_PLUS) }
|
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,
|
loadingNetwork: Boolean,
|
||||||
networkError: Boolean,
|
networkError: Boolean,
|
||||||
onUnitSelectionClick: (String) -> Unit,
|
onUnitSelectionClick: (String) -> Unit,
|
||||||
swapUnits: () -> Unit
|
swapUnits: () -> Unit,
|
||||||
|
baseConverterMode: Boolean,
|
||||||
) {
|
) {
|
||||||
var swapped by remember { mutableStateOf(false) }
|
var swapped by remember { mutableStateOf(false) }
|
||||||
val swapButtonRotation: Float by animateFloatAsState(
|
val swapButtonRotation: Float by animateFloatAsState(
|
||||||
@ -94,6 +95,7 @@ fun TopScreenPart(
|
|||||||
when {
|
when {
|
||||||
loadingDatabase || loadingNetwork -> stringResource(R.string.loading_label)
|
loadingDatabase || loadingNetwork -> stringResource(R.string.loading_label)
|
||||||
networkError -> stringResource(R.string.error_label)
|
networkError -> stringResource(R.string.error_label)
|
||||||
|
baseConverterMode -> inputValue.uppercase()
|
||||||
else -> Formatter.format(inputValue)
|
else -> Formatter.format(inputValue)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -107,6 +109,7 @@ fun TopScreenPart(
|
|||||||
when {
|
when {
|
||||||
loadingDatabase || loadingNetwork -> stringResource(R.string.loading_label)
|
loadingDatabase || loadingNetwork -> stringResource(R.string.loading_label)
|
||||||
networkError -> stringResource(R.string.error_label)
|
networkError -> stringResource(R.string.error_label)
|
||||||
|
baseConverterMode -> outputValue.uppercase()
|
||||||
else -> Formatter.format(outputValue)
|
else -> Formatter.format(outputValue)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -48,6 +48,7 @@ import androidx.compose.ui.unit.dp
|
|||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import com.sadellie.unitto.R
|
import com.sadellie.unitto.R
|
||||||
import com.sadellie.unitto.data.units.AbstractUnit
|
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.data.units.UnitGroup
|
||||||
import com.sadellie.unitto.screens.Formatter
|
import com.sadellie.unitto.screens.Formatter
|
||||||
import com.sadellie.unitto.screens.common.Header
|
import com.sadellie.unitto.screens.common.Header
|
||||||
@ -174,12 +175,27 @@ fun RightSideScreen(
|
|||||||
navigateUp: () -> Unit,
|
navigateUp: () -> Unit,
|
||||||
navigateToSettingsAction: () -> Unit,
|
navigateToSettingsAction: () -> Unit,
|
||||||
selectAction: (AbstractUnit) -> Unit,
|
selectAction: (AbstractUnit) -> Unit,
|
||||||
inputValue: BigDecimal?,
|
inputValue: String,
|
||||||
unitFrom: AbstractUnit
|
unitFrom: AbstractUnit
|
||||||
) {
|
) {
|
||||||
val uiState = viewModel.mainFlow.collectAsStateWithLifecycle()
|
val uiState = viewModel.mainFlow.collectAsStateWithLifecycle()
|
||||||
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
|
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
|
||||||
val focusManager = LocalFocusManager.current
|
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(
|
Scaffold(
|
||||||
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
|
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||||
@ -224,13 +240,7 @@ fun RightSideScreen(
|
|||||||
navigateUp()
|
navigateUp()
|
||||||
},
|
},
|
||||||
favoriteAction = { viewModel.favoriteUnit(it) },
|
favoriteAction = { viewModel.favoriteUnit(it) },
|
||||||
convertValue = {
|
convertValue = convertMethod
|
||||||
inputValue?.let {
|
|
||||||
Formatter.format(
|
|
||||||
unitFrom.convert(unit, it, 3).toPlainString()
|
|
||||||
) + " "
|
|
||||||
} ?: ""
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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
|
@Composable
|
||||||
private fun UnitGroupHeader(modifier: Modifier, unitGroup: UnitGroup) {
|
private fun UnitGroupHeader(modifier: Modifier, unitGroup: UnitGroup) {
|
||||||
Header(
|
Header(
|
||||||
|
@ -931,6 +931,38 @@
|
|||||||
<string name="gigaweber">Gigaweber</string>
|
<string name="gigaweber">Gigaweber</string>
|
||||||
<string name="gigaweber_short">GWb</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-->
|
<!--Groups-->
|
||||||
<string name="length">Length</string>
|
<string name="length">Length</string>
|
||||||
<string name="time">Time</string>
|
<string name="time">Time</string>
|
||||||
@ -948,6 +980,7 @@
|
|||||||
<string name="acceleration">Acceleration</string>
|
<string name="acceleration">Acceleration</string>
|
||||||
<string name="currency">Currency</string>
|
<string name="currency">Currency</string>
|
||||||
<string name="flux">Flux</string>
|
<string name="flux">Flux</string>
|
||||||
|
<string name="number_base">Base</string>
|
||||||
|
|
||||||
<!--Screen names-->
|
<!--Screen names-->
|
||||||
<string name="units_screen_from">Convert from</string>
|
<string name="units_screen_from">Convert from</string>
|
||||||
|
@ -351,15 +351,41 @@ class AllUnitsTest {
|
|||||||
MyUnitIDS.gigaweber.checkWith(MyUnitIDS.weber, "68.2", "68200000000")
|
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) {
|
private fun String.checkWith(checkingId: String, value: String, expected: String) {
|
||||||
val unit = allUnitsRepository.getById(this)
|
val unitFrom = allUnitsRepository.getById(this)
|
||||||
val actual = unit
|
val unitTo = allUnitsRepository.getById(checkingId)
|
||||||
.convert(allUnitsRepository.getById(checkingId), BigDecimal(value), 5)
|
|
||||||
.toPlainString()
|
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)
|
assertEquals("Failed at $this to $checkingId", expected, actual)
|
||||||
println("PASSED: $this -> $expected == $actual")
|
println("PASSED: $this -> $expected == $actual")
|
||||||
val content: Set<String> = history.getOrDefault(unit.group, setOf())
|
val content: Set<String> = history.getOrDefault(unitFrom.group, setOf())
|
||||||
history[unit.group] = content.plus(this)
|
history[unitFrom.group] = content.plus(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
|
Loading…
x
Reference in New Issue
Block a user