mirror of
https://github.com/Myzel394/NumberHub.git
synced 2025-06-18 16:25:27 +02:00
Merge pull request #13 from Myzel394/improve-keyboard-layout
Improve converter screen
This commit is contained in:
commit
f92becc333
@ -25,7 +25,6 @@ import androidx.compose.foundation.layout.FlowRowScope
|
|||||||
import androidx.compose.foundation.layout.fillMaxHeight
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -51,8 +50,8 @@ fun KeypadFlow(
|
|||||||
@IntRange(0, 100) verticalPadding: Int = 10,
|
@IntRange(0, 100) verticalPadding: Int = 10,
|
||||||
content: @Composable FlowRowScope.(width: Float, height: Float) -> Unit,
|
content: @Composable FlowRowScope.(width: Float, height: Float) -> Unit,
|
||||||
) {
|
) {
|
||||||
val height: Float = remember { (1f - verticalPadding / 100f) / rows }
|
val height: Float = (1f - verticalPadding / 100f) / rows
|
||||||
val width: Float = remember { (1f - horizontalPadding / 100f) / columns }
|
val width: Float = (1f - horizontalPadding / 100f) / columns
|
||||||
|
|
||||||
FlowRow(
|
FlowRow(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
|
@ -102,17 +102,232 @@ class UnitsRepositoryImpl @Inject constructor(
|
|||||||
|
|
||||||
suspend fun getPairId(id: String): String = withContext(Dispatchers.IO) {
|
suspend fun getPairId(id: String): String = withContext(Dispatchers.IO) {
|
||||||
val basedUnitPair = getUnitStats(id).pairedUnitId
|
val basedUnitPair = getUnitStats(id).pairedUnitId
|
||||||
if (basedUnitPair != null) return@withContext basedUnitPair
|
if (basedUnitPair != null) {
|
||||||
|
return@withContext basedUnitPair
|
||||||
|
}
|
||||||
|
|
||||||
val inMemoryUnit = inMemory.first { it.id == id }
|
val inMemoryUnit = inMemory.first { it.id == id }
|
||||||
val collection = inMemory.filter { it.group == inMemoryUnit.group }
|
val collection = inMemory.filter { it.group == inMemoryUnit.group }
|
||||||
|
|
||||||
val pair = collection
|
return@withContext when (inMemoryUnit.id) {
|
||||||
|
// === === === Length === === ===
|
||||||
|
UnitID.nanometer -> UnitID.micrometer
|
||||||
|
UnitID.micrometer -> UnitID.millimeter
|
||||||
|
UnitID.millimeter -> UnitID.centimeter
|
||||||
|
|
||||||
|
UnitID.centimeter -> UnitID.inch
|
||||||
|
UnitID.inch -> UnitID.centimeter
|
||||||
|
UnitID.decimeter -> UnitID.centimeter
|
||||||
|
UnitID.foot -> UnitID.meter
|
||||||
|
UnitID.yard -> UnitID.meter
|
||||||
|
UnitID.meter -> UnitID.foot
|
||||||
|
|
||||||
|
UnitID.kilometer -> UnitID.mile
|
||||||
|
UnitID.mile -> UnitID.kilometer
|
||||||
|
UnitID.nautical_mile -> UnitID.kilometer
|
||||||
|
|
||||||
|
UnitID.mercury_equatorial_radius -> UnitID.kilometer
|
||||||
|
UnitID.mars_equatorial_radius -> UnitID.kilometer
|
||||||
|
UnitID.venus_equatorial_radius -> UnitID.kilometer
|
||||||
|
UnitID.earth_equatorial_radius -> UnitID.kilometer
|
||||||
|
UnitID.neptune_equatorial_radius -> UnitID.kilometer
|
||||||
|
UnitID.uranus_equatorial_radius -> UnitID.kilometer
|
||||||
|
UnitID.saturn_equatorial_radius -> UnitID.kilometer
|
||||||
|
UnitID.jupiter_equatorial_radius -> UnitID.kilometer
|
||||||
|
UnitID.sun_equatorial_radius -> UnitID.kilometer
|
||||||
|
|
||||||
|
UnitID.light_year -> UnitID.kilometer
|
||||||
|
|
||||||
|
UnitID.parsec -> UnitID.light_year
|
||||||
|
UnitID.kiloparsec -> UnitID.parsec
|
||||||
|
UnitID.megaparsec -> UnitID.kiloparsec
|
||||||
|
|
||||||
|
|
||||||
|
// === === === Mass === === ===
|
||||||
|
UnitID.electron_mass_rest -> UnitID.atomic_mass_unit
|
||||||
|
UnitID.atomic_mass_unit -> UnitID.electron_mass_rest
|
||||||
|
|
||||||
|
UnitID.microgram -> UnitID.milligram
|
||||||
|
UnitID.milligram -> UnitID.gram
|
||||||
|
UnitID.grain -> UnitID.gram
|
||||||
|
UnitID.carat -> UnitID.gram
|
||||||
|
|
||||||
|
UnitID.gram -> UnitID.carat
|
||||||
|
UnitID.ounce -> UnitID.gram
|
||||||
|
UnitID.pound -> UnitID.kilogram
|
||||||
|
UnitID.kilogram -> UnitID.pound
|
||||||
|
|
||||||
|
UnitID.metric_ton -> UnitID.kilogram
|
||||||
|
UnitID.imperial_ton -> UnitID.pound
|
||||||
|
|
||||||
|
UnitID.mercury_mass -> UnitID.kilogram
|
||||||
|
UnitID.mars_mass -> UnitID.kilogram
|
||||||
|
UnitID.venus_mass -> UnitID.kilogram
|
||||||
|
UnitID.earth_mass -> UnitID.kilogram
|
||||||
|
UnitID.uranus_mass -> UnitID.kilogram
|
||||||
|
UnitID.neptune_mass -> UnitID.kilogram
|
||||||
|
UnitID.saturn_mass -> UnitID.kilogram
|
||||||
|
UnitID.jupiter_mass -> UnitID.kilogram
|
||||||
|
UnitID.sun_mass -> UnitID.kilogram
|
||||||
|
|
||||||
|
|
||||||
|
// === === === Speed === === ===
|
||||||
|
UnitID.millimeter_per_hour -> UnitID.millimeter_per_second
|
||||||
|
UnitID.millimeter_per_second -> UnitID.millimeter_per_hour
|
||||||
|
UnitID.millimeter_per_minute -> UnitID.millimeter_per_second
|
||||||
|
UnitID.centimeter_per_hour -> UnitID.centimeter_per_second
|
||||||
|
UnitID.centimeter_per_second -> UnitID.centimeter_per_hour
|
||||||
|
UnitID.centimeter_per_minute -> UnitID.centimeter_per_second
|
||||||
|
UnitID.meter_per_hour -> UnitID.meter_per_second
|
||||||
|
UnitID.meter_per_second -> UnitID.meter_per_hour
|
||||||
|
UnitID.meter_per_minute -> UnitID.meter_per_second
|
||||||
|
|
||||||
|
UnitID.kilometer_per_hour -> UnitID.mile_per_hour
|
||||||
|
UnitID.kilometer_per_second -> UnitID.mile_per_second
|
||||||
|
UnitID.kilometer_per_minute -> UnitID.kilometer_per_second
|
||||||
|
UnitID.mile_per_hour -> UnitID.kilometer_per_hour
|
||||||
|
UnitID.mile_per_second -> UnitID.kilometer_per_second
|
||||||
|
UnitID.mile_per_minute -> UnitID.mile_per_second
|
||||||
|
|
||||||
|
UnitID.foot_per_hour -> UnitID.foot_per_second
|
||||||
|
UnitID.foot_per_second -> UnitID.foot_per_hour
|
||||||
|
UnitID.foot_per_minute -> UnitID.foot_per_second
|
||||||
|
UnitID.yard_per_hour -> UnitID.yard_per_second
|
||||||
|
UnitID.yard_per_second -> UnitID.yard_per_hour
|
||||||
|
UnitID.yard_per_minute -> UnitID.yard_per_second
|
||||||
|
|
||||||
|
UnitID.knot -> UnitID.kilometer_per_hour
|
||||||
|
UnitID.mach -> UnitID.kilometer_per_hour
|
||||||
|
UnitID.velocity_of_light_in_vacuum -> UnitID.kilometer_per_hour
|
||||||
|
UnitID.earths_orbital_speed -> UnitID.kilometer_per_hour
|
||||||
|
|
||||||
|
UnitID.cosmic_velocity_first -> UnitID.kilometer_per_hour
|
||||||
|
UnitID.cosmic_velocity_second -> UnitID.kilometer_per_hour
|
||||||
|
UnitID.cosmic_velocity_third -> UnitID.kilometer_per_hour
|
||||||
|
|
||||||
|
|
||||||
|
// === === === Temperature === === ===
|
||||||
|
UnitID.celsius -> UnitID.fahrenheit
|
||||||
|
UnitID.fahrenheit -> UnitID.celsius
|
||||||
|
UnitID.kelvin -> UnitID.celsius
|
||||||
|
|
||||||
|
|
||||||
|
// === === === Area === === ===
|
||||||
|
UnitID.square_micrometer -> UnitID.square_millimeter
|
||||||
|
UnitID.square_millimeter -> UnitID.square_centimeter
|
||||||
|
UnitID.square_centimeter -> UnitID.square_meter
|
||||||
|
UnitID.square_decimeter -> UnitID.square_meter
|
||||||
|
UnitID.square_meter -> UnitID.square_kilometer
|
||||||
|
|
||||||
|
UnitID.square_kilometer -> UnitID.square_meter
|
||||||
|
|
||||||
|
UnitID.square_inch -> UnitID.square_foot
|
||||||
|
UnitID.square_foot -> UnitID.square_inch
|
||||||
|
UnitID.square_yard -> UnitID.square_meter
|
||||||
|
UnitID.square_mile -> UnitID.square_kilometer
|
||||||
|
|
||||||
|
UnitID.acre -> UnitID.square_meter
|
||||||
|
UnitID.hectare -> UnitID.square_meter
|
||||||
|
UnitID.cent -> UnitID.square_meter
|
||||||
|
|
||||||
|
|
||||||
|
// === === === Time === === ===
|
||||||
|
UnitID.attosecond -> UnitID.nanosecond
|
||||||
|
UnitID.nanosecond -> UnitID.microsecond
|
||||||
|
UnitID.microsecond -> UnitID.millisecond
|
||||||
|
UnitID.millisecond -> UnitID.second
|
||||||
|
|
||||||
|
UnitID.jiffy -> UnitID.millisecond
|
||||||
|
|
||||||
|
UnitID.second -> UnitID.millisecond
|
||||||
|
UnitID.minute -> UnitID.second
|
||||||
|
UnitID.hour -> UnitID.minute
|
||||||
|
UnitID.day -> UnitID.hour
|
||||||
|
UnitID.week -> UnitID.day
|
||||||
|
|
||||||
|
|
||||||
|
// === === === Data === === ===
|
||||||
|
// TODO: Add tibibyte, exibyte
|
||||||
|
UnitID.bit -> UnitID.byte
|
||||||
|
UnitID.byte -> UnitID.kilobyte
|
||||||
|
UnitID.kilobyte -> UnitID.megabyte
|
||||||
|
UnitID.megabyte -> UnitID.gigabyte
|
||||||
|
UnitID.gigabyte -> UnitID.terabyte
|
||||||
|
UnitID.terabyte -> UnitID.petabyte
|
||||||
|
UnitID.petabyte -> UnitID.exabyte
|
||||||
|
|
||||||
|
UnitID.kilobit -> UnitID.kilobyte
|
||||||
|
UnitID.megabit -> UnitID.megabyte
|
||||||
|
UnitID.gigabit -> UnitID.gigabyte
|
||||||
|
UnitID.terabit -> UnitID.terabyte
|
||||||
|
UnitID.petabit -> UnitID.petabyte
|
||||||
|
UnitID.exabit -> UnitID.exabyte
|
||||||
|
|
||||||
|
UnitID.kibibit -> UnitID.kilobyte
|
||||||
|
UnitID.mebibit -> UnitID.megabyte
|
||||||
|
UnitID.gibibit -> UnitID.gigabyte
|
||||||
|
|
||||||
|
UnitID.kibibyte -> UnitID.kilobyte
|
||||||
|
UnitID.mebibyte -> UnitID.megabyte
|
||||||
|
UnitID.gibibyte -> UnitID.gigabyte
|
||||||
|
|
||||||
|
|
||||||
|
// === === === Acceleration === === ===
|
||||||
|
UnitID.millimeter_per_square_second -> UnitID.centimeter_per_square_second
|
||||||
|
UnitID.centimeter_per_square_second -> UnitID.meter_per_square_second
|
||||||
|
UnitID.decimeter_per_square_second -> UnitID.meter_per_square_second
|
||||||
|
UnitID.meter_per_square_second -> UnitID.kilometer_per_square_second
|
||||||
|
|
||||||
|
UnitID.mercury_surface_gravity -> UnitID.meter_per_square_second
|
||||||
|
UnitID.mars_surface_gravity -> UnitID.meter_per_square_second
|
||||||
|
UnitID.venus_surface_gravity -> UnitID.meter_per_square_second
|
||||||
|
UnitID.uranus_surface_gravity -> UnitID.meter_per_square_second
|
||||||
|
UnitID.earth_surface_gravity -> UnitID.meter_per_square_second
|
||||||
|
UnitID.saturn_surface_gravity -> UnitID.meter_per_square_second
|
||||||
|
UnitID.neptune_surface_gravity -> UnitID.meter_per_square_second
|
||||||
|
UnitID.jupiter_surface_gravity -> UnitID.meter_per_square_second
|
||||||
|
UnitID.sun_surface_gravity -> UnitID.meter_per_square_second
|
||||||
|
|
||||||
|
|
||||||
|
// === === === Power === === ===
|
||||||
|
UnitID.attowatt -> UnitID.watt
|
||||||
|
UnitID.watt -> UnitID.kilowatt
|
||||||
|
UnitID.kilowatt -> UnitID.watt
|
||||||
|
UnitID.megawatt -> UnitID.kilowatt
|
||||||
|
|
||||||
|
|
||||||
|
// === === === Angle === === ===
|
||||||
|
UnitID.degree -> UnitID.radian
|
||||||
|
UnitID.radian -> UnitID.degree
|
||||||
|
|
||||||
|
|
||||||
|
// === === === Data Transfer === === ===
|
||||||
|
UnitID.bit_per_second -> UnitID.byte_per_second
|
||||||
|
UnitID.kilobit_per_second -> UnitID.kilobyte_per_second
|
||||||
|
UnitID.megabit_per_second -> UnitID.megabyte_per_second
|
||||||
|
UnitID.gigabit_per_second -> UnitID.gigabyte_per_second
|
||||||
|
UnitID.terabit_per_second -> UnitID.terabyte_per_second
|
||||||
|
UnitID.petabit_per_second -> UnitID.petabyte_per_second
|
||||||
|
UnitID.exabit_per_second -> UnitID.exabyte_per_second
|
||||||
|
|
||||||
|
UnitID.byte_per_second -> UnitID.kilobyte_per_second
|
||||||
|
UnitID.kilobyte_per_second -> UnitID.megabyte_per_second
|
||||||
|
UnitID.megabyte_per_second -> UnitID.gigabyte_per_second
|
||||||
|
UnitID.gigabyte_per_second -> UnitID.megabyte_per_second
|
||||||
|
UnitID.terabyte_per_second -> UnitID.gigabyte_per_second
|
||||||
|
UnitID.petabyte_per_second -> UnitID.terabyte_per_second
|
||||||
|
|
||||||
|
|
||||||
|
// === === === Fuel === === ===
|
||||||
|
UnitID.kilometer_per_liter -> UnitID.mile_us_per_liter
|
||||||
|
UnitID.mile_us_per_liter -> UnitID.kilometer_per_liter
|
||||||
|
|
||||||
|
else ->
|
||||||
|
(collection
|
||||||
.map { getById(it.id) to getUnitStats(it.id) }
|
.map { getById(it.id) to getUnitStats(it.id) }
|
||||||
.sortedByDescending { it.second.frequency }
|
.sortedByDescending { it.second.frequency }
|
||||||
.firstOrNull { it.second.isFavorite }?.first ?: collection.first()
|
.firstOrNull { it.second.isFavorite }?.first ?: collection.first()).id
|
||||||
|
}
|
||||||
return@withContext pair.id
|
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun incrementCounter(id: String) = withContext(Dispatchers.IO) {
|
suspend fun incrementCounter(id: String) = withContext(Dispatchers.IO) {
|
||||||
|
@ -37,6 +37,16 @@ sealed interface BasicUnit {
|
|||||||
|
|
||||||
interface NumberBase : BasicUnit {
|
interface NumberBase : BasicUnit {
|
||||||
fun convert(unitTo: NumberBase, value: String): String
|
fun convert(unitTo: NumberBase, value: String): String
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val Hexadecimal = NumberBaseUnit(
|
||||||
|
"hexadecimal",
|
||||||
|
BigDecimal(16),
|
||||||
|
UnitGroup.NUMBER_BASE,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Default : BasicUnit {
|
interface Default : BasicUnit {
|
||||||
|
@ -120,7 +120,7 @@ internal fun Preferences.getUnitConverterFormatTime(): Boolean {
|
|||||||
|
|
||||||
internal fun Preferences.getUnitConverterSorting(): UnitsListSorting {
|
internal fun Preferences.getUnitConverterSorting(): UnitsListSorting {
|
||||||
return this[PrefsKeys.UNIT_CONVERTER_SORTING]
|
return this[PrefsKeys.UNIT_CONVERTER_SORTING]
|
||||||
?.let { UnitsListSorting.valueOf(it) } ?: UnitsListSorting.USAGE
|
?.let { UnitsListSorting.valueOf(it) } ?: UnitsListSorting.SCALE_ASC
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun Preferences.getShownUnitGroups(): List<UnitGroup> {
|
internal fun Preferences.getShownUnitGroups(): List<UnitGroup> {
|
||||||
|
@ -22,6 +22,7 @@ import androidx.compose.animation.AnimatedContent
|
|||||||
import androidx.compose.animation.AnimatedVisibility
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
import androidx.compose.animation.SizeTransform
|
import androidx.compose.animation.SizeTransform
|
||||||
import androidx.compose.animation.core.FastOutSlowInEasing
|
import androidx.compose.animation.core.FastOutSlowInEasing
|
||||||
|
import androidx.compose.animation.core.LinearEasing
|
||||||
import androidx.compose.animation.core.animateFloatAsState
|
import androidx.compose.animation.core.animateFloatAsState
|
||||||
import androidx.compose.animation.core.tween
|
import androidx.compose.animation.core.tween
|
||||||
import androidx.compose.animation.expandHorizontally
|
import androidx.compose.animation.expandHorizontally
|
||||||
@ -31,6 +32,11 @@ import androidx.compose.animation.fadeOut
|
|||||||
import androidx.compose.animation.shrinkVertically
|
import androidx.compose.animation.shrinkVertically
|
||||||
import androidx.compose.animation.togetherWith
|
import androidx.compose.animation.togetherWith
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.gestures.AnchoredDraggableState
|
||||||
|
import androidx.compose.foundation.gestures.DraggableAnchors
|
||||||
|
import androidx.compose.foundation.gestures.Orientation
|
||||||
|
import androidx.compose.foundation.gestures.anchoredDraggable
|
||||||
|
import androidx.compose.foundation.horizontalScroll
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
@ -40,6 +46,7 @@ import androidx.compose.foundation.layout.fillMaxSize
|
|||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.outlined.SwapHoriz
|
import androidx.compose.material.icons.outlined.SwapHoriz
|
||||||
@ -64,6 +71,7 @@ import androidx.compose.ui.draw.rotate
|
|||||||
import androidx.compose.ui.focus.onFocusEvent
|
import androidx.compose.ui.focus.onFocusEvent
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.input.TextFieldValue
|
import androidx.compose.ui.text.input.TextFieldValue
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
@ -94,11 +102,14 @@ import app.myzel394.numberhub.data.common.isExpression
|
|||||||
import app.myzel394.numberhub.data.converter.ConverterResult
|
import app.myzel394.numberhub.data.converter.ConverterResult
|
||||||
import app.myzel394.numberhub.data.converter.UnitID
|
import app.myzel394.numberhub.data.converter.UnitID
|
||||||
import app.myzel394.numberhub.data.model.converter.UnitGroup
|
import app.myzel394.numberhub.data.model.converter.UnitGroup
|
||||||
|
import app.myzel394.numberhub.feature.converter.components.BaseCalculationSummary
|
||||||
import app.myzel394.numberhub.feature.converter.components.DefaultKeyboard
|
import app.myzel394.numberhub.feature.converter.components.DefaultKeyboard
|
||||||
import app.myzel394.numberhub.feature.converter.components.NumberBaseKeyboard
|
import app.myzel394.numberhub.feature.converter.components.NumberBaseKeyboard
|
||||||
import app.myzel394.numberhub.feature.converter.components.UnitSelectionButton
|
import app.myzel394.numberhub.feature.converter.components.UnitSelectionButton
|
||||||
|
import app.myzel394.numberhub.feature.converter.components.ValueOneSummary
|
||||||
import java.math.BigDecimal
|
import java.math.BigDecimal
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
import kotlin.math.absoluteValue
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
internal fun ConverterRoute(
|
internal fun ConverterRoute(
|
||||||
@ -203,10 +214,30 @@ private fun NumberBase(
|
|||||||
convert()
|
convert()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val density = LocalDensity.current
|
||||||
|
val dragState = remember {
|
||||||
|
AnchoredDraggableState(
|
||||||
|
initialValue = DragState.CLOSED,
|
||||||
|
anchors = DraggableAnchors {
|
||||||
|
DragState.CLOSED at 0f
|
||||||
|
DragState.OPEN at with(density) { -60.dp.toPx() }
|
||||||
|
},
|
||||||
|
positionalThreshold = { 0f },
|
||||||
|
velocityThreshold = { 0f },
|
||||||
|
animationSpec = tween(easing = LinearEasing, durationMillis = 50),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
PortraitLandscape(
|
PortraitLandscape(
|
||||||
modifier = modifier.fillMaxSize(),
|
modifier = modifier.fillMaxSize(),
|
||||||
content1 = { contentModifier ->
|
content1 = { contentModifier ->
|
||||||
ColumnWithConstraints(modifier = contentModifier) {
|
ColumnWithConstraints(
|
||||||
|
modifier = contentModifier
|
||||||
|
.anchoredDraggable(
|
||||||
|
state = dragState,
|
||||||
|
orientation = Orientation.Vertical,
|
||||||
|
),
|
||||||
|
) {
|
||||||
val textFieldModifier = Modifier.weight(2f)
|
val textFieldModifier = Modifier.weight(2f)
|
||||||
|
|
||||||
NumberBaseTextField(
|
NumberBaseTextField(
|
||||||
@ -224,6 +255,22 @@ private fun NumberBase(
|
|||||||
)
|
)
|
||||||
AnimatedUnitShortName(stringResource(uiState.unitTo.shortName))
|
AnimatedUnitShortName(stringResource(uiState.unitTo.shortName))
|
||||||
|
|
||||||
|
if (uiState.result is ConverterResult.NumberBase) {
|
||||||
|
BaseCalculationSummary(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.horizontalScroll(rememberScrollState())
|
||||||
|
.then(with(density) { Modifier.height(dragState.offset.absoluteValue.toDp()) }),
|
||||||
|
basis = uiState.unitTo,
|
||||||
|
result = uiState.result,
|
||||||
|
onResultChange = { newValue ->
|
||||||
|
val valueConverted = uiState.unitTo.convert(uiState.unitFrom, newValue)
|
||||||
|
|
||||||
|
updateInput1(TextFieldValue(valueConverted))
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(it.maxHeight * 0.03f))
|
Spacer(modifier = Modifier.height(it.maxHeight * 0.03f))
|
||||||
|
|
||||||
UnitSelectionButtons(
|
UnitSelectionButtons(
|
||||||
@ -250,6 +297,7 @@ private fun NumberBase(
|
|||||||
addDigit = { updateInput1(uiState.input.addTokens(it)) },
|
addDigit = { updateInput1(uiState.input.addTokens(it)) },
|
||||||
deleteDigit = { updateInput1(uiState.input.deleteTokens()) },
|
deleteDigit = { updateInput1(uiState.input.deleteTokens()) },
|
||||||
clearInput = { updateInput1(TextFieldValue()) },
|
clearInput = { updateInput1(TextFieldValue()) },
|
||||||
|
basis = uiState.unitFrom,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@ -284,6 +332,20 @@ private fun Default(
|
|||||||
}
|
}
|
||||||
var focusedOnInput1 by rememberSaveable { mutableStateOf(true) }
|
var focusedOnInput1 by rememberSaveable { mutableStateOf(true) }
|
||||||
|
|
||||||
|
val density = LocalDensity.current
|
||||||
|
val dragState = remember {
|
||||||
|
AnchoredDraggableState(
|
||||||
|
initialValue = DragState.CLOSED,
|
||||||
|
anchors = DraggableAnchors {
|
||||||
|
DragState.CLOSED at 0f
|
||||||
|
DragState.OPEN at with(density) { -60.dp.toPx() }
|
||||||
|
},
|
||||||
|
positionalThreshold = { 0f },
|
||||||
|
velocityThreshold = { 0f },
|
||||||
|
animationSpec = tween(easing = LinearEasing, durationMillis = 50),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
LaunchedEffect(connection) {
|
LaunchedEffect(connection) {
|
||||||
if ((connection == ConnectionState.Available) and (uiState.result is ConverterResult.Error)) {
|
if ((connection == ConnectionState.Available) and (uiState.result is ConverterResult.Error)) {
|
||||||
val unitFrom = uiState.unitFrom
|
val unitFrom = uiState.unitFrom
|
||||||
@ -304,7 +366,13 @@ private fun Default(
|
|||||||
PortraitLandscape(
|
PortraitLandscape(
|
||||||
modifier = modifier.fillMaxSize(),
|
modifier = modifier.fillMaxSize(),
|
||||||
content1 = { contentModifier ->
|
content1 = { contentModifier ->
|
||||||
ColumnWithConstraints(modifier = contentModifier) { boxWithConstraintsScope ->
|
ColumnWithConstraints(
|
||||||
|
modifier = contentModifier
|
||||||
|
.anchoredDraggable(
|
||||||
|
state = dragState,
|
||||||
|
orientation = Orientation.Vertical,
|
||||||
|
),
|
||||||
|
) { boxWithConstraintsScope ->
|
||||||
val textFieldModifier = Modifier
|
val textFieldModifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.weight(2f)
|
.weight(2f)
|
||||||
@ -425,6 +493,18 @@ private fun Default(
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (uiState.result is ConverterResult.Default && uiState.unitTo.factor >= BigDecimal.ZERO) {
|
||||||
|
ValueOneSummary(
|
||||||
|
modifier = with(density) {
|
||||||
|
Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(dragState.offset.absoluteValue.toDp())
|
||||||
|
.horizontalScroll(rememberScrollState())
|
||||||
|
},
|
||||||
|
uiState = uiState,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(boxWithConstraintsScope.maxHeight * 0.03f))
|
Spacer(modifier = Modifier.height(boxWithConstraintsScope.maxHeight * 0.03f))
|
||||||
|
|
||||||
UnitSelectionButtons(
|
UnitSelectionButtons(
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
package app.myzel394.numberhub.feature.converter
|
||||||
|
|
||||||
|
internal enum class DragState { CLOSED, OPEN }
|
@ -156,7 +156,7 @@ private fun UnitFromSelectorScreenPreview() {
|
|||||||
selectedUnitGroup = UnitGroup.SPEED,
|
selectedUnitGroup = UnitGroup.SPEED,
|
||||||
shownUnitGroups = UnitGroup.entries,
|
shownUnitGroups = UnitGroup.entries,
|
||||||
showFavoritesOnly = false,
|
showFavoritesOnly = false,
|
||||||
sorting = UnitsListSorting.USAGE,
|
sorting = UnitsListSorting.SCALE_ASC,
|
||||||
),
|
),
|
||||||
onQueryChange = {},
|
onQueryChange = {},
|
||||||
toggleFavoritesOnly = {},
|
toggleFavoritesOnly = {},
|
||||||
|
@ -155,7 +155,7 @@ private fun UnitToSelectorPreview() {
|
|||||||
query = TextFieldValue("test"),
|
query = TextFieldValue("test"),
|
||||||
units = units,
|
units = units,
|
||||||
showFavoritesOnly = false,
|
showFavoritesOnly = false,
|
||||||
sorting = UnitsListSorting.USAGE,
|
sorting = UnitsListSorting.SCALE_ASC,
|
||||||
input = "100",
|
input = "100",
|
||||||
scale = 3,
|
scale = 3,
|
||||||
outputFormat = OutputFormat.PLAIN,
|
outputFormat = OutputFormat.PLAIN,
|
||||||
|
@ -0,0 +1,86 @@
|
|||||||
|
package app.myzel394.numberhub.feature.converter.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.offset
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import app.myzel394.numberhub.data.converter.ConverterResult
|
||||||
|
import app.myzel394.numberhub.data.model.converter.unit.BasicUnit
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
internal fun BaseCalculationSummary(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
basis: BasicUnit.NumberBase,
|
||||||
|
result: ConverterResult.NumberBase,
|
||||||
|
onResultChange: (String) -> Unit,
|
||||||
|
) {
|
||||||
|
val fontStyle = MaterialTheme.typography.headlineSmall
|
||||||
|
|
||||||
|
Row(
|
||||||
|
modifier,
|
||||||
|
horizontalArrangement = Arrangement.End,
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
) {
|
||||||
|
for (index in 0..<result.value.length) {
|
||||||
|
val character = result.value[index]
|
||||||
|
val digit = character.digitToInt(16);
|
||||||
|
val base = basis.factor.toInt()
|
||||||
|
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.clip(MaterialTheme.shapes.small)
|
||||||
|
.clickable {
|
||||||
|
val newCurrentValue = (digit + 1) % base
|
||||||
|
val newResultText = result.value.substring(
|
||||||
|
0,
|
||||||
|
index,
|
||||||
|
) + newCurrentValue.toString(16) + result.value.substring(index + 1)
|
||||||
|
|
||||||
|
onResultChange(newResultText)
|
||||||
|
}
|
||||||
|
.padding(vertical = 2.dp, horizontal = 6.dp),
|
||||||
|
horizontalArrangement = Arrangement.Center,
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "$digit",
|
||||||
|
style = fontStyle,
|
||||||
|
color = MaterialTheme.colorScheme.primary,
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = " · $base",
|
||||||
|
style = fontStyle,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = "${result.value.length - index - 1}",
|
||||||
|
modifier = Modifier.offset(
|
||||||
|
y = -(MaterialTheme.typography.bodySmall.fontSize.div(
|
||||||
|
2,
|
||||||
|
)).value.dp,
|
||||||
|
),
|
||||||
|
style = fontStyle.copy(
|
||||||
|
fontSize = MaterialTheme.typography.bodySmall.fontSize,
|
||||||
|
),
|
||||||
|
color = MaterialTheme.colorScheme.tertiary,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index < result.value.length - 1) {
|
||||||
|
Text(
|
||||||
|
text = " + ",
|
||||||
|
style = fontStyle,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -18,18 +18,33 @@
|
|||||||
|
|
||||||
package app.myzel394.numberhub.feature.converter.components
|
package app.myzel394.numberhub.feature.converter.components
|
||||||
|
|
||||||
|
import androidx.compose.animation.AnimatedContent
|
||||||
|
import androidx.compose.animation.AnimatedContentTransitionScope
|
||||||
|
import androidx.compose.animation.core.tween
|
||||||
|
import androidx.compose.animation.togetherWith
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.FlowRow
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.fillMaxHeight
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
import app.myzel394.numberhub.core.base.R
|
import app.myzel394.numberhub.core.base.R
|
||||||
import app.myzel394.numberhub.core.base.Token
|
import app.myzel394.numberhub.core.base.Token
|
||||||
import app.myzel394.numberhub.core.ui.LocalWindowSize
|
import app.myzel394.numberhub.core.ui.LocalWindowSize
|
||||||
import app.myzel394.numberhub.core.ui.WindowHeightSizeClass
|
import app.myzel394.numberhub.core.ui.WindowHeightSizeClass
|
||||||
|
import app.myzel394.numberhub.core.ui.WindowWidthSizeClass
|
||||||
|
import app.myzel394.numberhub.core.ui.common.ColumnWithConstraints
|
||||||
import app.myzel394.numberhub.core.ui.common.KeyboardButtonFilled
|
import app.myzel394.numberhub.core.ui.common.KeyboardButtonFilled
|
||||||
import app.myzel394.numberhub.core.ui.common.KeyboardButtonLight
|
import app.myzel394.numberhub.core.ui.common.KeyboardButtonLight
|
||||||
import app.myzel394.numberhub.core.ui.common.KeyboardButtonTertiary
|
import app.myzel394.numberhub.core.ui.common.KeyboardButtonTertiary
|
||||||
@ -65,6 +80,9 @@ import app.myzel394.numberhub.core.ui.common.icons.iconpack.Plus
|
|||||||
import app.myzel394.numberhub.core.ui.common.icons.iconpack.Power
|
import app.myzel394.numberhub.core.ui.common.icons.iconpack.Power
|
||||||
import app.myzel394.numberhub.core.ui.common.icons.iconpack.RightBracket
|
import app.myzel394.numberhub.core.ui.common.icons.iconpack.RightBracket
|
||||||
import app.myzel394.numberhub.core.ui.common.icons.iconpack.Root
|
import app.myzel394.numberhub.core.ui.common.icons.iconpack.Root
|
||||||
|
import app.myzel394.numberhub.data.model.converter.unit.BasicUnit
|
||||||
|
import app.myzel394.numberhub.feature.converter.createSortedArray
|
||||||
|
import kotlin.math.ceil
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
internal fun DefaultKeyboard(
|
internal fun DefaultKeyboard(
|
||||||
@ -79,92 +97,401 @@ internal fun DefaultKeyboard(
|
|||||||
) {
|
) {
|
||||||
val fractionalIcon = remember(fractional) { if (fractional == Token.PERIOD) IconPack.Dot else IconPack.Comma }
|
val fractionalIcon = remember(fractional) { if (fractional == Token.PERIOD) IconPack.Dot else IconPack.Comma }
|
||||||
val fractionalIconDescription = remember(fractional) { if (fractional == Token.PERIOD) R.string.keyboard_dot else R.string.comma }
|
val fractionalIconDescription = remember(fractional) { if (fractional == Token.PERIOD) R.string.keyboard_dot else R.string.comma }
|
||||||
val contentHeight: Float = if (LocalWindowSize.current.heightSizeClass < WindowHeightSizeClass.Medium) KeyboardButtonToken.CONTENT_HEIGHT_SHORT else KeyboardButtonToken.CONTENT_HEIGHT_TALL
|
val contentHeight: Float =
|
||||||
|
if (LocalWindowSize.current.heightSizeClass < WindowHeightSizeClass.Medium) KeyboardButtonToken.CONTENT_HEIGHT_SHORT else KeyboardButtonToken.CONTENT_HEIGHT_TALL
|
||||||
|
|
||||||
KeypadFlow(
|
KeypadFlow(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
rows = 5,
|
rows = 5,
|
||||||
columns = 4,
|
columns = 4,
|
||||||
) { width, height ->
|
) { width, height ->
|
||||||
val bModifier = Modifier.fillMaxWidth(width).fillMaxHeight(height)
|
val bModifier = Modifier
|
||||||
|
.fillMaxWidth(width)
|
||||||
|
.fillMaxHeight(height)
|
||||||
|
|
||||||
if (acButton) {
|
if (acButton) {
|
||||||
KeyboardButtonTertiary(bModifier, IconPack.Clear, stringResource(R.string.delete_label), contentHeight) { clearInput() }
|
KeyboardButtonTertiary(
|
||||||
KeyboardButtonFilled(bModifier, IconPack.Brackets, stringResource(R.string.keyboard_brackets), contentHeight) { addBracket() }
|
bModifier,
|
||||||
|
IconPack.Clear,
|
||||||
|
stringResource(R.string.delete_label),
|
||||||
|
contentHeight,
|
||||||
|
) { clearInput() }
|
||||||
|
KeyboardButtonFilled(
|
||||||
|
bModifier,
|
||||||
|
IconPack.Brackets,
|
||||||
|
stringResource(R.string.keyboard_brackets),
|
||||||
|
contentHeight,
|
||||||
|
) { addBracket() }
|
||||||
} else {
|
} else {
|
||||||
KeyboardButtonFilled(bModifier, IconPack.LeftBracket, stringResource(R.string.keyboard_left_bracket), contentHeight) { addDigit(Token.Operator.leftBracket) }
|
KeyboardButtonFilled(
|
||||||
KeyboardButtonFilled(bModifier, IconPack.RightBracket, stringResource(R.string.keyboard_right_bracket), contentHeight) { addDigit(Token.Operator.rightBracket) }
|
bModifier,
|
||||||
|
IconPack.LeftBracket,
|
||||||
|
stringResource(R.string.keyboard_left_bracket),
|
||||||
|
contentHeight,
|
||||||
|
) { addDigit(Token.Operator.leftBracket) }
|
||||||
|
KeyboardButtonFilled(
|
||||||
|
bModifier,
|
||||||
|
IconPack.RightBracket,
|
||||||
|
stringResource(R.string.keyboard_right_bracket),
|
||||||
|
contentHeight,
|
||||||
|
) { addDigit(Token.Operator.rightBracket) }
|
||||||
}
|
}
|
||||||
KeyboardButtonFilled(bModifier, IconPack.Power, stringResource(R.string.keyboard_power), contentHeight) { addDigit(Token.Operator.power) }
|
KeyboardButtonFilled(
|
||||||
KeyboardButtonFilled(bModifier, IconPack.Root, stringResource(R.string.keyboard_root), contentHeight) { addDigit(Token.Operator.sqrt) }
|
bModifier,
|
||||||
|
IconPack.Power,
|
||||||
|
stringResource(R.string.keyboard_power),
|
||||||
|
contentHeight,
|
||||||
|
) { addDigit(Token.Operator.power) }
|
||||||
|
KeyboardButtonFilled(
|
||||||
|
bModifier,
|
||||||
|
IconPack.Root,
|
||||||
|
stringResource(R.string.keyboard_root),
|
||||||
|
contentHeight,
|
||||||
|
) { addDigit(Token.Operator.sqrt) }
|
||||||
|
|
||||||
KeyboardButtonLight(bModifier, IconPack.Key7, Token.Digit._7, contentHeight) { addDigit(Token.Digit._7) }
|
KeyboardButtonLight(
|
||||||
KeyboardButtonLight(bModifier, IconPack.Key8, Token.Digit._8, contentHeight) { addDigit(Token.Digit._8) }
|
bModifier,
|
||||||
KeyboardButtonLight(bModifier, IconPack.Key9, Token.Digit._9, contentHeight) { addDigit(Token.Digit._9) }
|
IconPack.Key7,
|
||||||
KeyboardButtonFilled(bModifier, IconPack.Divide, stringResource(R.string.keyboard_divide), contentHeight) { addDigit(Token.Operator.divide) }
|
Token.Digit._7,
|
||||||
|
contentHeight,
|
||||||
|
) { addDigit(Token.Digit._7) }
|
||||||
|
KeyboardButtonLight(
|
||||||
|
bModifier,
|
||||||
|
IconPack.Key8,
|
||||||
|
Token.Digit._8,
|
||||||
|
contentHeight,
|
||||||
|
) { addDigit(Token.Digit._8) }
|
||||||
|
KeyboardButtonLight(
|
||||||
|
bModifier,
|
||||||
|
IconPack.Key9,
|
||||||
|
Token.Digit._9,
|
||||||
|
contentHeight,
|
||||||
|
) { addDigit(Token.Digit._9) }
|
||||||
|
KeyboardButtonFilled(
|
||||||
|
bModifier,
|
||||||
|
IconPack.Divide,
|
||||||
|
stringResource(R.string.keyboard_divide),
|
||||||
|
contentHeight,
|
||||||
|
) { addDigit(Token.Operator.divide) }
|
||||||
|
|
||||||
KeyboardButtonLight(bModifier, IconPack.Key4, Token.Digit._4, contentHeight) { addDigit(Token.Digit._4) }
|
KeyboardButtonLight(
|
||||||
KeyboardButtonLight(bModifier, IconPack.Key5, Token.Digit._5, contentHeight) { addDigit(Token.Digit._5) }
|
bModifier,
|
||||||
KeyboardButtonLight(bModifier, IconPack.Key6, Token.Digit._6, contentHeight) { addDigit(Token.Digit._6) }
|
IconPack.Key4,
|
||||||
KeyboardButtonFilled(bModifier, IconPack.Multiply, stringResource(R.string.keyboard_multiply), contentHeight) { addDigit(Token.Operator.multiply) }
|
Token.Digit._4,
|
||||||
|
contentHeight,
|
||||||
|
) { addDigit(Token.Digit._4) }
|
||||||
|
KeyboardButtonLight(
|
||||||
|
bModifier,
|
||||||
|
IconPack.Key5,
|
||||||
|
Token.Digit._5,
|
||||||
|
contentHeight,
|
||||||
|
) { addDigit(Token.Digit._5) }
|
||||||
|
KeyboardButtonLight(
|
||||||
|
bModifier,
|
||||||
|
IconPack.Key6,
|
||||||
|
Token.Digit._6,
|
||||||
|
contentHeight,
|
||||||
|
) { addDigit(Token.Digit._6) }
|
||||||
|
KeyboardButtonFilled(
|
||||||
|
bModifier,
|
||||||
|
IconPack.Multiply,
|
||||||
|
stringResource(R.string.keyboard_multiply),
|
||||||
|
contentHeight,
|
||||||
|
) { addDigit(Token.Operator.multiply) }
|
||||||
|
|
||||||
KeyboardButtonLight(bModifier, IconPack.Key1, Token.Digit._1, contentHeight) { addDigit(Token.Digit._1) }
|
KeyboardButtonLight(
|
||||||
KeyboardButtonLight(bModifier, IconPack.Key2, Token.Digit._2, contentHeight) { addDigit(Token.Digit._2) }
|
bModifier,
|
||||||
KeyboardButtonLight(bModifier, IconPack.Key3, Token.Digit._3, contentHeight) { addDigit(Token.Digit._3) }
|
IconPack.Key1,
|
||||||
KeyboardButtonFilled(bModifier, IconPack.Minus, stringResource(R.string.keyboard_minus), contentHeight) { addDigit(Token.Operator.minus) }
|
Token.Digit._1,
|
||||||
|
contentHeight,
|
||||||
|
) { addDigit(Token.Digit._1) }
|
||||||
|
KeyboardButtonLight(
|
||||||
|
bModifier,
|
||||||
|
IconPack.Key2,
|
||||||
|
Token.Digit._2,
|
||||||
|
contentHeight,
|
||||||
|
) { addDigit(Token.Digit._2) }
|
||||||
|
KeyboardButtonLight(
|
||||||
|
bModifier,
|
||||||
|
IconPack.Key3,
|
||||||
|
Token.Digit._3,
|
||||||
|
contentHeight,
|
||||||
|
) { addDigit(Token.Digit._3) }
|
||||||
|
KeyboardButtonFilled(
|
||||||
|
bModifier,
|
||||||
|
IconPack.Minus,
|
||||||
|
stringResource(R.string.keyboard_minus),
|
||||||
|
contentHeight,
|
||||||
|
) { addDigit(Token.Operator.minus) }
|
||||||
|
|
||||||
if (middleZero) {
|
if (middleZero) {
|
||||||
KeyboardButtonLight(bModifier, fractionalIcon, stringResource(fractionalIconDescription), contentHeight) { addDigit(Token.Digit.dot) }
|
KeyboardButtonLight(
|
||||||
KeyboardButtonLight(bModifier, IconPack.Key0, Token.Digit._0, contentHeight) { addDigit(Token.Digit._0) }
|
bModifier,
|
||||||
|
fractionalIcon,
|
||||||
|
stringResource(fractionalIconDescription),
|
||||||
|
contentHeight,
|
||||||
|
) { addDigit(Token.Digit.dot) }
|
||||||
|
KeyboardButtonLight(
|
||||||
|
bModifier,
|
||||||
|
IconPack.Key0,
|
||||||
|
Token.Digit._0,
|
||||||
|
contentHeight,
|
||||||
|
) { addDigit(Token.Digit._0) }
|
||||||
} else {
|
} else {
|
||||||
KeyboardButtonLight(bModifier, IconPack.Key0, Token.Digit._0, contentHeight) { addDigit(Token.Digit._0) }
|
KeyboardButtonLight(
|
||||||
KeyboardButtonLight(bModifier, fractionalIcon, stringResource(fractionalIconDescription), contentHeight) { addDigit(Token.Digit.dot) }
|
bModifier,
|
||||||
|
IconPack.Key0,
|
||||||
|
Token.Digit._0,
|
||||||
|
contentHeight,
|
||||||
|
) { addDigit(Token.Digit._0) }
|
||||||
|
KeyboardButtonLight(
|
||||||
|
bModifier,
|
||||||
|
fractionalIcon,
|
||||||
|
stringResource(fractionalIconDescription),
|
||||||
|
contentHeight,
|
||||||
|
) { addDigit(Token.Digit.dot) }
|
||||||
}
|
}
|
||||||
KeyboardButtonLight(bModifier, IconPack.Backspace, stringResource(R.string.delete_label), contentHeight, onLongClick = clearInput) { deleteDigit() }
|
KeyboardButtonLight(
|
||||||
KeyboardButtonFilled(bModifier, IconPack.Plus, stringResource(R.string.keyboard_plus), contentHeight) { addDigit(Token.Operator.plus) }
|
bModifier,
|
||||||
|
IconPack.Backspace,
|
||||||
|
stringResource(R.string.delete_label),
|
||||||
|
contentHeight,
|
||||||
|
onLongClick = clearInput,
|
||||||
|
) { deleteDigit() }
|
||||||
|
KeyboardButtonFilled(
|
||||||
|
bModifier,
|
||||||
|
IconPack.Plus,
|
||||||
|
stringResource(R.string.keyboard_plus),
|
||||||
|
contentHeight,
|
||||||
|
) { addDigit(Token.Operator.plus) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val AVAILABLE_NUMBERS = mapOf<String, ImageVector>(
|
||||||
|
Token.Digit._0 to IconPack.Key0,
|
||||||
|
Token.Digit._1 to IconPack.Key1,
|
||||||
|
Token.Digit._2 to IconPack.Key2,
|
||||||
|
Token.Digit._3 to IconPack.Key3,
|
||||||
|
Token.Digit._4 to IconPack.Key4,
|
||||||
|
Token.Digit._5 to IconPack.Key5,
|
||||||
|
Token.Digit._6 to IconPack.Key6,
|
||||||
|
Token.Digit._7 to IconPack.Key7,
|
||||||
|
Token.Digit._8 to IconPack.Key8,
|
||||||
|
Token.Digit._9 to IconPack.Key9,
|
||||||
|
Token.Letter._A to IconPack.KeyA,
|
||||||
|
Token.Letter._B to IconPack.KeyB,
|
||||||
|
Token.Letter._C to IconPack.KeyC,
|
||||||
|
Token.Letter._D to IconPack.KeyD,
|
||||||
|
Token.Letter._E to IconPack.KeyE,
|
||||||
|
Token.Letter._F to IconPack.KeyF,
|
||||||
|
)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
internal fun NumberBaseKeyboard(
|
internal fun NumberBaseKeyboard(
|
||||||
modifier: Modifier,
|
modifier: Modifier,
|
||||||
addDigit: (String) -> Unit,
|
addDigit: (String) -> Unit,
|
||||||
clearInput: () -> Unit,
|
clearInput: () -> Unit,
|
||||||
deleteDigit: () -> Unit,
|
deleteDigit: () -> Unit,
|
||||||
|
basis: BasicUnit.NumberBase,
|
||||||
) {
|
) {
|
||||||
val contentHeight: Float = if (LocalWindowSize.current.heightSizeClass < WindowHeightSizeClass.Medium) KeyboardButtonToken.CONTENT_HEIGHT_SHORT else KeyboardButtonToken.CONTENT_HEIGHT_TALL
|
val contentHeight: Float = if (LocalWindowSize.current.heightSizeClass < WindowHeightSizeClass.Medium) KeyboardButtonToken.CONTENT_HEIGHT_SHORT else KeyboardButtonToken.CONTENT_HEIGHT_TALL
|
||||||
|
val isUsingColumn =
|
||||||
|
(LocalWindowSize.current.widthSizeClass > WindowWidthSizeClass.Expanded) or (LocalWindowSize.current.heightSizeClass > WindowHeightSizeClass.Compact)
|
||||||
|
|
||||||
KeypadFlow(
|
var direction by remember {
|
||||||
|
mutableStateOf(AnimatedContentTransitionScope.SlideDirection.Right)
|
||||||
|
}
|
||||||
|
|
||||||
|
LaunchedEffect(isUsingColumn) {
|
||||||
|
direction = if (isUsingColumn) {
|
||||||
|
AnimatedContentTransitionScope.SlideDirection.Right
|
||||||
|
} else {
|
||||||
|
AnimatedContentTransitionScope.SlideDirection.Up
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LaunchedEffect(basis) {
|
||||||
|
direction = when (direction) {
|
||||||
|
AnimatedContentTransitionScope.SlideDirection.Up -> AnimatedContentTransitionScope.SlideDirection.Down
|
||||||
|
AnimatedContentTransitionScope.SlideDirection.Down -> AnimatedContentTransitionScope.SlideDirection.Up
|
||||||
|
AnimatedContentTransitionScope.SlideDirection.Left -> AnimatedContentTransitionScope.SlideDirection.Right
|
||||||
|
AnimatedContentTransitionScope.SlideDirection.Right -> AnimatedContentTransitionScope.SlideDirection.Left
|
||||||
|
else -> direction
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnWithConstraints(modifier) { constraints ->
|
||||||
|
AnimatedContent(
|
||||||
|
transitionSpec = {
|
||||||
|
slideIntoContainer(animationSpec = tween(600), towards = direction).togetherWith(
|
||||||
|
slideOutOfContainer(animationSpec = tween(600), towards = direction),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
targetState = basis.factor.toInt(),
|
||||||
|
label = "ConverterKeyboard-FlowRow",
|
||||||
|
) { amount ->
|
||||||
|
val columns: Int = when {
|
||||||
|
amount == 5 -> 2
|
||||||
|
amount == 3 -> 2
|
||||||
|
amount == 7 -> 2
|
||||||
|
amount == 10 -> 3
|
||||||
|
amount < 10 -> if (amount.and(1) == 0) 2 else if (amount % 3 == 0) 3 else amount % 3
|
||||||
|
else -> 3
|
||||||
|
}
|
||||||
|
val rows = when {
|
||||||
|
amount == 5 -> 3
|
||||||
|
amount == 3 -> 2
|
||||||
|
amount == 7 -> 4
|
||||||
|
amount == 10 -> 4
|
||||||
|
amount < 10 -> ceil(amount.toDouble() / columns.toDouble()).toInt() + 1
|
||||||
|
amount == 11 -> 5
|
||||||
|
amount == 12 -> 5
|
||||||
|
amount == 13 -> 5
|
||||||
|
else -> 6
|
||||||
|
}
|
||||||
|
val horizontalSpacing = 8.dp
|
||||||
|
val verticalSpacing = 12.dp
|
||||||
|
val height: Float = (1f - (verticalSpacing * (rows - 1) / constraints.maxHeight)) / rows
|
||||||
|
|
||||||
|
FlowRow(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
rows = 6,
|
maxItemsInEachRow = columns,
|
||||||
columns = 3,
|
horizontalArrangement = Arrangement.spacedBy(horizontalSpacing),
|
||||||
) { width, height ->
|
verticalArrangement = Arrangement.spacedBy(verticalSpacing),
|
||||||
val bModifier = Modifier.fillMaxWidth(width).fillMaxHeight(height)
|
) {
|
||||||
val wideButtonModifier = Modifier.fillMaxHeight(height).fillMaxWidth(width * 2)
|
val bModifier = Modifier
|
||||||
|
.fillMaxHeight(height)
|
||||||
|
.fillMaxWidth()
|
||||||
|
|
||||||
KeyboardButtonFilled(bModifier, IconPack.KeyA, Token.Letter._A, contentHeight) { addDigit(Token.Letter._A) }
|
when {
|
||||||
KeyboardButtonFilled(bModifier, IconPack.KeyB, Token.Letter._B, contentHeight) { addDigit(Token.Letter._B) }
|
amount in arrayOf(3, 5, 7) -> {
|
||||||
KeyboardButtonFilled(bModifier, IconPack.KeyC, Token.Letter._C, contentHeight) { addDigit(Token.Letter._C) }
|
for (int in createSortedArray(1..<amount, columns)) {
|
||||||
|
val key = AVAILABLE_NUMBERS.keys.elementAt(int)
|
||||||
|
val icon = AVAILABLE_NUMBERS[key]!!
|
||||||
|
KeyboardButtonLight(
|
||||||
|
bModifier.weight(1f),
|
||||||
|
icon,
|
||||||
|
key,
|
||||||
|
contentHeight,
|
||||||
|
) { addDigit(key) }
|
||||||
|
}
|
||||||
|
|
||||||
KeyboardButtonFilled(bModifier, IconPack.KeyD, Token.Letter._D, contentHeight) { addDigit(Token.Letter._D) }
|
KeyboardButtonLight(
|
||||||
KeyboardButtonFilled(bModifier, IconPack.KeyE, Token.Letter._E, contentHeight) { addDigit(Token.Letter._E) }
|
bModifier.weight(1f),
|
||||||
KeyboardButtonFilled(bModifier, IconPack.KeyF, Token.Letter._F, contentHeight) { addDigit(Token.Letter._F) }
|
IconPack.Key0,
|
||||||
|
Token.Digit._0,
|
||||||
|
contentHeight,
|
||||||
|
) { addDigit(Token.Digit._0) }
|
||||||
|
KeyboardButtonTertiary(
|
||||||
|
bModifier.weight(1f),
|
||||||
|
IconPack.Backspace,
|
||||||
|
stringResource(R.string.delete_label),
|
||||||
|
contentHeight,
|
||||||
|
clearInput,
|
||||||
|
) { deleteDigit() }
|
||||||
|
}
|
||||||
|
|
||||||
KeyboardButtonLight(bModifier, IconPack.Key7, Token.Digit._7, contentHeight) { addDigit(Token.Digit._7) }
|
amount < 10 -> {
|
||||||
KeyboardButtonLight(bModifier, IconPack.Key8, Token.Digit._8, contentHeight) { addDigit(Token.Digit._8) }
|
for (int in createSortedArray(0..<amount.coerceAtMost(10), columns)) {
|
||||||
KeyboardButtonLight(bModifier, IconPack.Key9, Token.Digit._9, contentHeight) { addDigit(Token.Digit._9) }
|
val key = AVAILABLE_NUMBERS.keys.elementAt(int)
|
||||||
|
val icon = AVAILABLE_NUMBERS[key]!!
|
||||||
|
KeyboardButtonLight(
|
||||||
|
bModifier.weight(1f),
|
||||||
|
icon,
|
||||||
|
key,
|
||||||
|
contentHeight,
|
||||||
|
) { addDigit(key) }
|
||||||
|
}
|
||||||
|
|
||||||
KeyboardButtonLight(bModifier, IconPack.Key4, Token.Digit._4, contentHeight) { addDigit(Token.Digit._4) }
|
KeyboardButtonTertiary(
|
||||||
KeyboardButtonLight(bModifier, IconPack.Key5, Token.Digit._5, contentHeight) { addDigit(Token.Digit._5) }
|
bModifier,
|
||||||
KeyboardButtonLight(bModifier, IconPack.Key6, Token.Digit._6, contentHeight) { addDigit(Token.Digit._6) }
|
IconPack.Backspace,
|
||||||
|
stringResource(R.string.delete_label),
|
||||||
|
contentHeight,
|
||||||
|
clearInput,
|
||||||
|
) { deleteDigit() }
|
||||||
|
}
|
||||||
|
|
||||||
KeyboardButtonLight(bModifier, IconPack.Key1, Token.Digit._1, contentHeight) { addDigit(Token.Digit._1) }
|
amount == 10 -> {
|
||||||
KeyboardButtonLight(bModifier, IconPack.Key2, Token.Digit._2, contentHeight) { addDigit(Token.Digit._2) }
|
for (int in createSortedArray(1..9, columns)) {
|
||||||
KeyboardButtonLight(bModifier, IconPack.Key3, Token.Digit._3, contentHeight) { addDigit(Token.Digit._3) }
|
val key = AVAILABLE_NUMBERS.keys.elementAt(int)
|
||||||
|
val icon = AVAILABLE_NUMBERS[key]!!
|
||||||
|
KeyboardButtonLight(
|
||||||
|
bModifier.weight(1f),
|
||||||
|
icon,
|
||||||
|
key,
|
||||||
|
contentHeight,
|
||||||
|
) { addDigit(key) }
|
||||||
|
}
|
||||||
|
|
||||||
// TODO Should be a separate o use custom widthFillFactors and heightFillFactors
|
KeyboardButtonLight(
|
||||||
KeyboardButtonLight(bModifier, IconPack.Key0, Token.Digit._0, contentHeight) { addDigit(Token.Digit._0) }
|
bModifier.weight(1f),
|
||||||
KeyboardButtonLight(wideButtonModifier, IconPack.Backspace, stringResource(R.string.delete_label), contentHeight, clearInput) { deleteDigit() }
|
IconPack.Key0,
|
||||||
|
Token.Digit._0,
|
||||||
|
contentHeight,
|
||||||
|
) { addDigit(Token.Digit._0) }
|
||||||
|
KeyboardButtonTertiary(
|
||||||
|
bModifier.weight(2f),
|
||||||
|
IconPack.Backspace,
|
||||||
|
stringResource(R.string.delete_label),
|
||||||
|
contentHeight,
|
||||||
|
clearInput,
|
||||||
|
) { deleteDigit() }
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
val rowsAmount = ceil((amount - 10) / 3f).toInt()
|
||||||
|
|
||||||
|
for (row in (rowsAmount - 1) downTo 0) {
|
||||||
|
Row(
|
||||||
|
Modifier.fillMaxWidth(),
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(horizontalSpacing),
|
||||||
|
) {
|
||||||
|
val rowStart = 10 + (row) * columns
|
||||||
|
val rowEnd = (rowStart + 3).coerceAtMost(amount.coerceAtMost(16))
|
||||||
|
|
||||||
|
for (index in createSortedArray(rowStart..<rowEnd, columns)) {
|
||||||
|
val key = AVAILABLE_NUMBERS.keys.elementAt(index)
|
||||||
|
val icon = AVAILABLE_NUMBERS[key]!!
|
||||||
|
KeyboardButtonFilled(
|
||||||
|
bModifier.weight(1f),
|
||||||
|
icon,
|
||||||
|
key,
|
||||||
|
contentHeight,
|
||||||
|
) { addDigit(key) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int in createSortedArray(1..9, columns)) {
|
||||||
|
val key = AVAILABLE_NUMBERS.keys.elementAt(int)
|
||||||
|
val icon = AVAILABLE_NUMBERS[key]!!
|
||||||
|
KeyboardButtonLight(
|
||||||
|
bModifier.weight(1f),
|
||||||
|
icon,
|
||||||
|
key,
|
||||||
|
contentHeight,
|
||||||
|
) { addDigit(key) }
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyboardButtonLight(
|
||||||
|
bModifier.weight(1f),
|
||||||
|
IconPack.Key0,
|
||||||
|
Token.Digit._0,
|
||||||
|
contentHeight,
|
||||||
|
) { addDigit(Token.Digit._0) }
|
||||||
|
|
||||||
|
KeyboardButtonTertiary(
|
||||||
|
bModifier.weight(2f),
|
||||||
|
IconPack.Backspace,
|
||||||
|
stringResource(R.string.delete_label),
|
||||||
|
contentHeight,
|
||||||
|
clearInput,
|
||||||
|
) { deleteDigit() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,5 +518,6 @@ private fun PreviewConverterKeyboardNumberBase() {
|
|||||||
addDigit = {},
|
addDigit = {},
|
||||||
clearInput = {},
|
clearInput = {},
|
||||||
deleteDigit = {},
|
deleteDigit = {},
|
||||||
|
basis = BasicUnit.NumberBase.Hexadecimal,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,74 @@
|
|||||||
|
package app.myzel394.numberhub.feature.converter.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import app.myzel394.numberhub.data.common.format
|
||||||
|
import app.myzel394.numberhub.feature.converter.UnitConverterUIState
|
||||||
|
import java.math.BigDecimal
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
internal fun ValueOneSummary(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
uiState: UnitConverterUIState.Default,
|
||||||
|
) {
|
||||||
|
val unitFromLabel = LocalContext.current.getString(uiState.unitFrom.displayName)
|
||||||
|
val unitToLabel = LocalContext.current.getString(uiState.unitTo.displayName)
|
||||||
|
val value = uiState.unitFrom.convert(uiState.unitTo, BigDecimal(1))
|
||||||
|
.format(uiState.scale, uiState.outputFormat)
|
||||||
|
|
||||||
|
val fontStyle = MaterialTheme.typography.headlineSmall
|
||||||
|
|
||||||
|
Row(
|
||||||
|
modifier = modifier,
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.End,
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
1.toString(),
|
||||||
|
style = fontStyle,
|
||||||
|
color = MaterialTheme.colorScheme.primary,
|
||||||
|
)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
" ",
|
||||||
|
style = fontStyle,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
|
)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
unitFromLabel,
|
||||||
|
style = fontStyle,
|
||||||
|
color = MaterialTheme.colorScheme.tertiary,
|
||||||
|
)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
" = ",
|
||||||
|
style = fontStyle,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
|
)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
value,
|
||||||
|
style = fontStyle,
|
||||||
|
color = MaterialTheme.colorScheme.primary,
|
||||||
|
)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
" ",
|
||||||
|
style = fontStyle,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
|
)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
unitToLabel,
|
||||||
|
style = fontStyle,
|
||||||
|
color = MaterialTheme.colorScheme.tertiary,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
package app.myzel394.numberhub.feature.converter
|
||||||
|
|
||||||
|
import kotlin.math.ceil
|
||||||
|
|
||||||
|
// So here's the problem. If we just go down from 3 downto 0 with columns 2, this results in:
|
||||||
|
// [3, 2]
|
||||||
|
// [1, 0]
|
||||||
|
// While this is correct, the ordering is incorrect. It should be
|
||||||
|
// [2, 3]
|
||||||
|
// [0, 1]
|
||||||
|
// TODO: Add support for rtl languages
|
||||||
|
internal fun createSortedArray(range: IntRange, columns: Int): List<Int> {
|
||||||
|
val result = mutableListOf<Int>()
|
||||||
|
val rows = ceil(range.count().toDouble() / columns.toDouble()).toInt()
|
||||||
|
for (row in rows downTo 0) {
|
||||||
|
for (column in 0 until columns) {
|
||||||
|
val index = row * columns + column + range.first
|
||||||
|
if (index <= range.last) {
|
||||||
|
result.add(index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
@ -139,7 +139,7 @@ private fun PreviewConverterSettingsScreen() {
|
|||||||
precision = 3,
|
precision = 3,
|
||||||
outputFormat = OutputFormat.PLAIN,
|
outputFormat = OutputFormat.PLAIN,
|
||||||
unitConverterFormatTime = false,
|
unitConverterFormatTime = false,
|
||||||
unitConverterSorting = UnitsListSorting.USAGE,
|
unitConverterSorting = UnitsListSorting.SCALE_ASC,
|
||||||
shownUnitGroups = UnitGroup.entries,
|
shownUnitGroups = UnitGroup.entries,
|
||||||
unitConverterFavoritesOnly = false,
|
unitConverterFavoritesOnly = false,
|
||||||
enableToolsExperiment = false,
|
enableToolsExperiment = false,
|
||||||
|
@ -5,25 +5,25 @@ versionName = "NumberHub"
|
|||||||
androidxBrowserBrowser = "1.8.0"
|
androidxBrowserBrowser = "1.8.0"
|
||||||
androidGradlePlugin = "8.3.2"
|
androidGradlePlugin = "8.3.2"
|
||||||
androidxActivityActivityCompose = "1.9.0"
|
androidxActivityActivityCompose = "1.9.0"
|
||||||
androidxAppCompatAppCompat = "1.6.1"
|
androidxAppCompatAppCompat = "1.7.0"
|
||||||
androidxCompose = "1.6.7"
|
androidxCompose = "1.6.8"
|
||||||
androidxComposeCompiler = "1.5.9"
|
androidxComposeCompiler = "1.5.9"
|
||||||
androidxComposeMaterial3 = "1.2.1"
|
androidxComposeMaterial3 = "1.2.1"
|
||||||
androidxCoreCoreKts = "1.13.1"
|
androidxCoreCoreKts = "1.13.1"
|
||||||
androidxGlanceGlance = "1.0.0"
|
androidxGlanceGlance = "1.1.0"
|
||||||
androidxDatastoreDatastorePreferences = "1.1.1"
|
androidxDatastoreDatastorePreferences = "1.1.1"
|
||||||
androidxEspresso = "3.5.1"
|
androidxEspresso = "3.6.1"
|
||||||
androidxHiltHiltNavigationCompose = "1.2.0"
|
androidxHiltHiltNavigationCompose = "1.2.0"
|
||||||
androidxMacroBenchmark = "1.2.4"
|
androidxMacroBenchmark = "1.2.4"
|
||||||
androidxLifecycleLifecycleRuntimeCompose = "2.7.0"
|
androidxLifecycleLifecycleRuntimeCompose = "2.8.3"
|
||||||
androidxNavigationNavigationCompose = "2.7.7"
|
androidxNavigationNavigationCompose = "2.7.7"
|
||||||
androidxProfileinstallerProfileinstaller = "1.3.1"
|
androidxProfileinstallerProfileinstaller = "1.3.1"
|
||||||
androidxRoom = "2.6.1"
|
androidxRoom = "2.6.1"
|
||||||
androidxTest = "1.5.0"
|
androidxTest = "1.6.1"
|
||||||
androidxTestExtJunitKtx = "1.1.5"
|
androidxTestExtJunitKtx = "1.2.1"
|
||||||
androidxTestRunner = "1.5.2"
|
androidxTestRunner = "1.6.1"
|
||||||
androidxUiAutomator = "2.3.0"
|
androidxUiAutomator = "2.3.0"
|
||||||
androidxWindowWindow = "1.2.0"
|
androidxWindowWindow = "1.3.0"
|
||||||
androidxWorkWorkRuntimeKtx = "2.9.0"
|
androidxWorkWorkRuntimeKtx = "2.9.0"
|
||||||
comAndroidToolsDesugarJdkLibs = "2.0.4"
|
comAndroidToolsDesugarJdkLibs = "2.0.4"
|
||||||
comGithubSadellieThemmo = "1.3.0"
|
comGithubSadellieThemmo = "1.3.0"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user