mirror of
https://github.com/Myzel394/NumberHub.git
synced 2025-06-18 16:25:27 +02:00
Added formatter for time
This commit is contained in:
parent
d5cc855b3d
commit
542a95acf7
@ -37,6 +37,8 @@ class UnittoLibraryComposePlugin : Plugin<Project> {
|
|||||||
"implementation"(libs.findLibrary("androidx.compose.material3").get())
|
"implementation"(libs.findLibrary("androidx.compose.material3").get())
|
||||||
"implementation"(libs.findLibrary("androidx.lifecycle.runtime.compose").get())
|
"implementation"(libs.findLibrary("androidx.lifecycle.runtime.compose").get())
|
||||||
"implementation"(libs.findLibrary("androidx.compose.material.icons.extended").get())
|
"implementation"(libs.findLibrary("androidx.compose.material.icons.extended").get())
|
||||||
|
"implementation"(libs.findLibrary("androidx.compose.ui.tooling").get())
|
||||||
|
"implementation"(libs.findLibrary("androidx.compose.ui.tooling.preview").get())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,10 +24,20 @@ plugins {
|
|||||||
|
|
||||||
android {
|
android {
|
||||||
namespace = "com.sadellie.unitto.core.ui"
|
namespace = "com.sadellie.unitto.core.ui"
|
||||||
|
|
||||||
|
// Workaround from https://github.com/robolectric/robolectric/pull/4736
|
||||||
|
testOptions {
|
||||||
|
unitTests {
|
||||||
|
isIncludeAndroidResources = true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
testImplementation(libs.junit)
|
testImplementation(libs.junit)
|
||||||
|
testImplementation(libs.org.robolectric)
|
||||||
|
testImplementation(libs.androidx.compose.ui.test.junit4)
|
||||||
|
debugImplementation(libs.androidx.compose.ui.test.manifest)
|
||||||
|
|
||||||
implementation(project(mapOf("path" to ":core:base")))
|
implementation(project(mapOf("path" to ":core:base")))
|
||||||
}
|
}
|
||||||
|
@ -18,14 +18,20 @@
|
|||||||
|
|
||||||
package com.sadellie.unitto.core.ui
|
package com.sadellie.unitto.core.ui
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
import com.sadellie.unitto.core.base.INTERNAL_DISPLAY
|
import com.sadellie.unitto.core.base.INTERNAL_DISPLAY
|
||||||
|
import com.sadellie.unitto.core.base.KEY_0
|
||||||
import com.sadellie.unitto.core.base.KEY_COMMA
|
import com.sadellie.unitto.core.base.KEY_COMMA
|
||||||
import com.sadellie.unitto.core.base.KEY_DOT
|
import com.sadellie.unitto.core.base.KEY_DOT
|
||||||
import com.sadellie.unitto.core.base.KEY_E
|
import com.sadellie.unitto.core.base.KEY_E
|
||||||
import com.sadellie.unitto.core.base.KEY_LEFT_BRACKET
|
import com.sadellie.unitto.core.base.KEY_LEFT_BRACKET
|
||||||
|
import com.sadellie.unitto.core.base.KEY_MINUS
|
||||||
import com.sadellie.unitto.core.base.KEY_RIGHT_BRACKET
|
import com.sadellie.unitto.core.base.KEY_RIGHT_BRACKET
|
||||||
import com.sadellie.unitto.core.base.OPERATORS
|
import com.sadellie.unitto.core.base.OPERATORS
|
||||||
import com.sadellie.unitto.core.base.Separator
|
import com.sadellie.unitto.core.base.Separator
|
||||||
|
import java.math.BigDecimal
|
||||||
|
import java.math.RoundingMode
|
||||||
|
|
||||||
object Formatter {
|
object Formatter {
|
||||||
private const val SPACE = " "
|
private const val SPACE = " "
|
||||||
@ -42,6 +48,19 @@ object Formatter {
|
|||||||
*/
|
*/
|
||||||
var fractional = KEY_COMMA
|
var fractional = KEY_COMMA
|
||||||
|
|
||||||
|
private val timeDivisions by lazy {
|
||||||
|
mapOf(
|
||||||
|
R.string.day_short to BigDecimal("86400000000000000000000"),
|
||||||
|
R.string.hour_short to BigDecimal("3600000000000000000000"),
|
||||||
|
R.string.minute_short to BigDecimal("60000000000000000000"),
|
||||||
|
R.string.second_short to BigDecimal("1000000000000000000"),
|
||||||
|
R.string.millisecond_short to BigDecimal("1000000000000000"),
|
||||||
|
R.string.microsecond_short to BigDecimal("1000000000000"),
|
||||||
|
R.string.nanosecond_short to BigDecimal("1000000000"),
|
||||||
|
R.string.attosecond_short to BigDecimal("1"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Change current separator to another [separator].
|
* Change current separator to another [separator].
|
||||||
*
|
*
|
||||||
@ -118,4 +137,42 @@ object Formatter {
|
|||||||
|
|
||||||
return output
|
return output
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes [input] and [basicUnit] of the unit to format it to be more human readable.
|
||||||
|
*
|
||||||
|
* @return String like "1d 12h 12s".
|
||||||
|
*/
|
||||||
|
@Composable
|
||||||
|
fun formatTime(input: String, basicUnit: BigDecimal?): String {
|
||||||
|
if (basicUnit == null) return KEY_0
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Don't need magic if the input is zero
|
||||||
|
if (BigDecimal(input).compareTo(BigDecimal.ZERO) == 0) return KEY_0
|
||||||
|
} catch (e: NumberFormatException) {
|
||||||
|
// For case such as "10-" and "("
|
||||||
|
return KEY_0
|
||||||
|
}
|
||||||
|
// Attoseconds don't need "magic"
|
||||||
|
if (basicUnit.compareTo(BigDecimal.ONE) == 0) return formatNumber(input)
|
||||||
|
|
||||||
|
var result = if (input.startsWith(KEY_MINUS)) KEY_MINUS else ""
|
||||||
|
var remainingSeconds = BigDecimal(input)
|
||||||
|
.abs()
|
||||||
|
.multiply(basicUnit)
|
||||||
|
.setScale(0, RoundingMode.HALF_EVEN)
|
||||||
|
|
||||||
|
if (remainingSeconds.compareTo(BigDecimal.ZERO) == 0) return KEY_0
|
||||||
|
|
||||||
|
timeDivisions.forEach { (timeStr, divider) ->
|
||||||
|
val division = remainingSeconds.divideAndRemainder(divider)
|
||||||
|
val time = division.component1()
|
||||||
|
remainingSeconds = division.component2()
|
||||||
|
if (time.compareTo(BigDecimal.ZERO) == 1) {
|
||||||
|
result += "${formatNumber(time.toPlainString())}${stringResource(timeStr)} "
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result.trimEnd()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,9 +18,14 @@
|
|||||||
|
|
||||||
package com.sadellie.unitto.core.ui
|
package com.sadellie.unitto.core.ui
|
||||||
|
|
||||||
|
import androidx.compose.ui.test.junit4.createComposeRule
|
||||||
import com.sadellie.unitto.core.base.Separator
|
import com.sadellie.unitto.core.base.Separator
|
||||||
import org.junit.Assert.assertEquals
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.robolectric.RobolectricTestRunner
|
||||||
|
import java.math.BigDecimal
|
||||||
|
|
||||||
private val formatter = Formatter
|
private val formatter = Formatter
|
||||||
|
|
||||||
@ -33,8 +38,12 @@ private const val INCOMPLETE_EXPR = "50+123456÷8×0.8–12+"
|
|||||||
private const val COMPLETE_EXPR = "50+123456÷8×0.8–12+0-√9*4^9+2×(9+8×7)"
|
private const val COMPLETE_EXPR = "50+123456÷8×0.8–12+0-√9*4^9+2×(9+8×7)"
|
||||||
private const val SOME_BRACKETS = "(((((((("
|
private const val SOME_BRACKETS = "(((((((("
|
||||||
|
|
||||||
|
@RunWith(RobolectricTestRunner::class)
|
||||||
class FormatterTest {
|
class FormatterTest {
|
||||||
|
|
||||||
|
@get: Rule
|
||||||
|
val composeTestRule = createComposeRule()
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun setSeparatorSpaces() {
|
fun setSeparatorSpaces() {
|
||||||
formatter.setSeparator(Separator.SPACES)
|
formatter.setSeparator(Separator.SPACES)
|
||||||
@ -77,4 +86,101 @@ class FormatterTest {
|
|||||||
assertEquals("((((((((", formatter.format(SOME_BRACKETS))
|
assertEquals("((((((((", formatter.format(SOME_BRACKETS))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun formatTimeTest() {
|
||||||
|
formatter.setSeparator(Separator.SPACES)
|
||||||
|
composeTestRule.setContent {
|
||||||
|
var basicValue = BigDecimal.valueOf(1)
|
||||||
|
assertEquals("-28", Formatter.formatTime("-28", basicValue))
|
||||||
|
assertEquals("-0.05", Formatter.formatTime("-0.05", basicValue))
|
||||||
|
assertEquals("0", Formatter.formatTime("0", basicValue))
|
||||||
|
assertEquals("0", Formatter.formatTime("-0", basicValue))
|
||||||
|
|
||||||
|
basicValue = BigDecimal.valueOf(86_400_000_000_000_000_000_000.0)
|
||||||
|
assertEquals("-28d", Formatter.formatTime("-28", basicValue))
|
||||||
|
assertEquals("-1h 12m", Formatter.formatTime("-0.05", basicValue))
|
||||||
|
assertEquals("0", Formatter.formatTime("0", basicValue))
|
||||||
|
assertEquals("0", Formatter.formatTime("-0", basicValue))
|
||||||
|
|
||||||
|
// DAYS
|
||||||
|
basicValue = BigDecimal.valueOf(86_400_000_000_000_000_000_000.0)
|
||||||
|
assertEquals("12h", Formatter.formatTime("0.5", basicValue))
|
||||||
|
assertEquals("1h 12m", Formatter.formatTime("0.05", basicValue))
|
||||||
|
assertEquals("7m 12s", Formatter.formatTime("0.005", basicValue))
|
||||||
|
assertEquals("28d", Formatter.formatTime("28", basicValue))
|
||||||
|
assertEquals("90d", Formatter.formatTime("90", basicValue))
|
||||||
|
assertEquals("90d 12h", Formatter.formatTime("90.5", basicValue))
|
||||||
|
assertEquals("90d 7m 12s", Formatter.formatTime("90.005", basicValue))
|
||||||
|
|
||||||
|
// HOURS
|
||||||
|
basicValue = BigDecimal.valueOf(3_600_000_000_000_000_000_000.0)
|
||||||
|
assertEquals("30m", Formatter.formatTime("0.5", basicValue))
|
||||||
|
assertEquals("3m", Formatter.formatTime("0.05", basicValue))
|
||||||
|
assertEquals("18s", Formatter.formatTime("0.005", basicValue))
|
||||||
|
assertEquals("1d 4h", Formatter.formatTime("28", basicValue))
|
||||||
|
assertEquals("3d 18h", Formatter.formatTime("90", basicValue))
|
||||||
|
assertEquals("3d 18h 30m", Formatter.formatTime("90.5", basicValue))
|
||||||
|
assertEquals("3d 18h 18s", Formatter.formatTime("90.005", basicValue))
|
||||||
|
|
||||||
|
// MINUTES
|
||||||
|
basicValue = BigDecimal.valueOf(60_000_000_000_000_000_000.0)
|
||||||
|
assertEquals("30s", Formatter.formatTime("0.5", basicValue))
|
||||||
|
assertEquals("3s", Formatter.formatTime("0.05", basicValue))
|
||||||
|
assertEquals("300ms", Formatter.formatTime("0.005", basicValue))
|
||||||
|
assertEquals("28m", Formatter.formatTime("28", basicValue))
|
||||||
|
assertEquals("1h 30m", Formatter.formatTime("90", basicValue))
|
||||||
|
assertEquals("1h 30m 30s", Formatter.formatTime("90.5", basicValue))
|
||||||
|
assertEquals("1h 30m 300ms", Formatter.formatTime("90.005", basicValue))
|
||||||
|
|
||||||
|
// SECONDS
|
||||||
|
basicValue = BigDecimal.valueOf(1_000_000_000_000_000_000)
|
||||||
|
assertEquals("500ms", Formatter.formatTime("0.5", basicValue))
|
||||||
|
assertEquals("50ms", Formatter.formatTime("0.05", basicValue))
|
||||||
|
assertEquals("5ms", Formatter.formatTime("0.005", basicValue))
|
||||||
|
assertEquals("28s", Formatter.formatTime("28", basicValue))
|
||||||
|
assertEquals("1m 30s", Formatter.formatTime("90", basicValue))
|
||||||
|
assertEquals("1m 30s 500ms", Formatter.formatTime("90.5", basicValue))
|
||||||
|
assertEquals("1m 30s 5ms", Formatter.formatTime("90.005", basicValue))
|
||||||
|
|
||||||
|
// MILLISECONDS
|
||||||
|
basicValue = BigDecimal.valueOf(1_000_000_000_000_000)
|
||||||
|
assertEquals("500µs", Formatter.formatTime("0.5", basicValue))
|
||||||
|
assertEquals("50µs", Formatter.formatTime("0.05", basicValue))
|
||||||
|
assertEquals("5µs", Formatter.formatTime("0.005", basicValue))
|
||||||
|
assertEquals("28ms", Formatter.formatTime("28", basicValue))
|
||||||
|
assertEquals("90ms", Formatter.formatTime("90", basicValue))
|
||||||
|
assertEquals("90ms 500µs", Formatter.formatTime("90.5", basicValue))
|
||||||
|
assertEquals("90ms 5µs", Formatter.formatTime("90.005", basicValue))
|
||||||
|
|
||||||
|
// MICROSECONDS
|
||||||
|
basicValue = BigDecimal.valueOf(1_000_000_000_000)
|
||||||
|
assertEquals("500ns", Formatter.formatTime("0.5", basicValue))
|
||||||
|
assertEquals("50ns", Formatter.formatTime("0.05", basicValue))
|
||||||
|
assertEquals("5ns", Formatter.formatTime("0.005", basicValue))
|
||||||
|
assertEquals("28µs", Formatter.formatTime("28", basicValue))
|
||||||
|
assertEquals("90µs", Formatter.formatTime("90", basicValue))
|
||||||
|
assertEquals("90µs 500ns", Formatter.formatTime("90.5", basicValue))
|
||||||
|
assertEquals("90µs 5ns", Formatter.formatTime("90.005", basicValue))
|
||||||
|
|
||||||
|
// NANOSECONDS
|
||||||
|
basicValue = BigDecimal.valueOf(1_000_000_000)
|
||||||
|
assertEquals("500 000 000as", Formatter.formatTime("0.5", basicValue))
|
||||||
|
assertEquals("50 000 000as", Formatter.formatTime("0.05", basicValue))
|
||||||
|
assertEquals("5 000 000as", Formatter.formatTime("0.005", basicValue))
|
||||||
|
assertEquals("28ns", Formatter.formatTime("28", basicValue))
|
||||||
|
assertEquals("90ns", Formatter.formatTime("90", basicValue))
|
||||||
|
assertEquals("90ns 500 000 000as", Formatter.formatTime("90.5", basicValue))
|
||||||
|
assertEquals("90ns 5 000 000as", Formatter.formatTime("90.005", basicValue))
|
||||||
|
|
||||||
|
// ATTOSECONDS
|
||||||
|
basicValue = BigDecimal.valueOf(1)
|
||||||
|
assertEquals("0.5", Formatter.formatTime("0.5", basicValue))
|
||||||
|
assertEquals("0.05", Formatter.formatTime("0.05", basicValue))
|
||||||
|
assertEquals("0.005", Formatter.formatTime("0.005", basicValue))
|
||||||
|
assertEquals("28", Formatter.formatTime("28", basicValue))
|
||||||
|
assertEquals("90", Formatter.formatTime("90", basicValue))
|
||||||
|
assertEquals("90.5", Formatter.formatTime("90.5", basicValue))
|
||||||
|
assertEquals("90.005", Formatter.formatTime("90.005", basicValue))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -21,7 +21,7 @@ package com.sadellie.unitto.data
|
|||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
fun <T1, T2, T3, T4, T5, T6, T7, R> combine(
|
fun <T1, T2, T3, T4, T5, T6, T7, T8, R> combine(
|
||||||
flow: Flow<T1>,
|
flow: Flow<T1>,
|
||||||
flow2: Flow<T2>,
|
flow2: Flow<T2>,
|
||||||
flow3: Flow<T3>,
|
flow3: Flow<T3>,
|
||||||
@ -29,9 +29,10 @@ fun <T1, T2, T3, T4, T5, T6, T7, R> combine(
|
|||||||
flow5: Flow<T5>,
|
flow5: Flow<T5>,
|
||||||
flow6: Flow<T6>,
|
flow6: Flow<T6>,
|
||||||
flow7: Flow<T7>,
|
flow7: Flow<T7>,
|
||||||
transform: suspend (T1, T2, T3, T4, T5, T6, T7) -> R
|
flow8: Flow<T8>,
|
||||||
|
transform: suspend (T1, T2, T3, T4, T5, T6, T7, T8) -> R
|
||||||
): Flow<R> =
|
): Flow<R> =
|
||||||
kotlinx.coroutines.flow.combine(flow, flow2, flow3, flow4, flow5, flow6, flow7) { args: Array<*> ->
|
kotlinx.coroutines.flow.combine(flow, flow2, flow3, flow4, flow5, flow6, flow7, flow8) { args: Array<*> ->
|
||||||
transform(
|
transform(
|
||||||
args[0] as T1,
|
args[0] as T1,
|
||||||
args[1] as T2,
|
args[1] as T2,
|
||||||
@ -40,5 +41,6 @@ fun <T1, T2, T3, T4, T5, T6, T7, R> combine(
|
|||||||
args[4] as T5,
|
args[4] as T5,
|
||||||
args[5] as T6,
|
args[5] as T6,
|
||||||
args[6] as T7,
|
args[6] as T7,
|
||||||
|
args[7] as T8,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -83,6 +83,7 @@ internal fun MainScreen(
|
|||||||
processInput = { viewModel.processInput(it) },
|
processInput = { viewModel.processInput(it) },
|
||||||
deleteDigit = { viewModel.deleteDigit() },
|
deleteDigit = { viewModel.deleteDigit() },
|
||||||
clearInput = { viewModel.clearInput() },
|
clearInput = { viewModel.clearInput() },
|
||||||
|
onOutputTextFieldClick = { viewModel.toggleFormatTime() }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ -108,6 +109,7 @@ private fun MainScreenContent(
|
|||||||
processInput: (String) -> Unit = {},
|
processInput: (String) -> Unit = {},
|
||||||
deleteDigit: () -> Unit = {},
|
deleteDigit: () -> Unit = {},
|
||||||
clearInput: () -> Unit = {},
|
clearInput: () -> Unit = {},
|
||||||
|
onOutputTextFieldClick: () -> Unit
|
||||||
) {
|
) {
|
||||||
PortraitLandscape(
|
PortraitLandscape(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
@ -125,6 +127,8 @@ private fun MainScreenContent(
|
|||||||
navigateToRightScreen = navigateToRightScreen,
|
navigateToRightScreen = navigateToRightScreen,
|
||||||
swapUnits = swapMeasurements,
|
swapUnits = swapMeasurements,
|
||||||
converterMode = mainScreenUIState.mode,
|
converterMode = mainScreenUIState.mode,
|
||||||
|
formatTime = mainScreenUIState.formatTime,
|
||||||
|
onOutputTextFieldClick = onOutputTextFieldClick
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
content2 = {
|
content2 = {
|
||||||
|
@ -33,6 +33,7 @@ import com.sadellie.unitto.data.units.AbstractUnit
|
|||||||
* @property unitFrom Unit on the left.
|
* @property unitFrom Unit on the left.
|
||||||
* @property unitTo Unit on the right.
|
* @property unitTo Unit on the right.
|
||||||
* @property mode
|
* @property mode
|
||||||
|
* @property formatTime If true will format output when converting time.
|
||||||
*/
|
*/
|
||||||
data class MainScreenUIState(
|
data class MainScreenUIState(
|
||||||
val inputValue: String = KEY_0,
|
val inputValue: String = KEY_0,
|
||||||
@ -43,6 +44,7 @@ data class MainScreenUIState(
|
|||||||
val unitFrom: AbstractUnit? = null,
|
val unitFrom: AbstractUnit? = null,
|
||||||
val unitTo: AbstractUnit? = null,
|
val unitTo: AbstractUnit? = null,
|
||||||
val mode: ConverterMode = ConverterMode.DEFAULT,
|
val mode: ConverterMode = ConverterMode.DEFAULT,
|
||||||
|
val formatTime: Boolean = true
|
||||||
)
|
)
|
||||||
|
|
||||||
enum class ConverterMode {
|
enum class ConverterMode {
|
||||||
|
@ -129,6 +129,8 @@ class MainViewModel @Inject constructor(
|
|||||||
*/
|
*/
|
||||||
private val _showError: MutableStateFlow<Boolean> = MutableStateFlow(false)
|
private val _showError: MutableStateFlow<Boolean> = MutableStateFlow(false)
|
||||||
|
|
||||||
|
private val _formatTime: MutableStateFlow<Boolean> = MutableStateFlow(true)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Current state of UI.
|
* Current state of UI.
|
||||||
*/
|
*/
|
||||||
@ -139,8 +141,9 @@ class MainViewModel @Inject constructor(
|
|||||||
_calculated,
|
_calculated,
|
||||||
_result,
|
_result,
|
||||||
_showLoading,
|
_showLoading,
|
||||||
_showError
|
_showError,
|
||||||
) { inputValue, unitFromValue, unitToValue, calculatedValue, resultValue, showLoadingValue, showErrorValue ->
|
_formatTime
|
||||||
|
) { inputValue, unitFromValue, unitToValue, calculatedValue, resultValue, showLoadingValue, showErrorValue, formatTime ->
|
||||||
return@combine MainScreenUIState(
|
return@combine MainScreenUIState(
|
||||||
inputValue = inputValue,
|
inputValue = inputValue,
|
||||||
calculatedValue = calculatedValue,
|
calculatedValue = calculatedValue,
|
||||||
@ -153,7 +156,8 @@ class MainViewModel @Inject constructor(
|
|||||||
* If there will be more modes, this should be a separate value which we update when
|
* If there will be more modes, this should be a separate value which we update when
|
||||||
* changing units.
|
* changing units.
|
||||||
*/
|
*/
|
||||||
mode = if (_unitFrom.value is NumberBaseUnit) ConverterMode.BASE else ConverterMode.DEFAULT
|
mode = if (_unitFrom.value is NumberBaseUnit) ConverterMode.BASE else ConverterMode.DEFAULT,
|
||||||
|
formatTime = formatTime
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
.stateIn(
|
.stateIn(
|
||||||
@ -389,6 +393,10 @@ class MainViewModel @Inject constructor(
|
|||||||
return _calculated.value ?: _input.value
|
return _calculated.value ?: _input.value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun toggleFormatTime() {
|
||||||
|
_formatTime.update { !it }
|
||||||
|
}
|
||||||
|
|
||||||
private suspend fun convertInput() {
|
private suspend fun convertInput() {
|
||||||
// Loading don't do anything
|
// Loading don't do anything
|
||||||
if ((_unitFrom.value == null) or (_unitTo.value == null)) return
|
if ((_unitFrom.value == null) or (_unitTo.value == null)) return
|
||||||
|
@ -21,6 +21,7 @@ package com.sadellie.unitto.feature.converter.components
|
|||||||
import androidx.compose.animation.core.FastOutSlowInEasing
|
import androidx.compose.animation.core.FastOutSlowInEasing
|
||||||
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.foundation.clickable
|
||||||
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.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
@ -43,6 +44,7 @@ import androidx.compose.ui.unit.dp
|
|||||||
import com.sadellie.unitto.core.ui.Formatter
|
import com.sadellie.unitto.core.ui.Formatter
|
||||||
import com.sadellie.unitto.data.units.AbstractUnit
|
import com.sadellie.unitto.data.units.AbstractUnit
|
||||||
import com.sadellie.unitto.core.ui.R
|
import com.sadellie.unitto.core.ui.R
|
||||||
|
import com.sadellie.unitto.data.units.UnitGroup
|
||||||
import com.sadellie.unitto.feature.converter.ConverterMode
|
import com.sadellie.unitto.feature.converter.ConverterMode
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -62,6 +64,8 @@ import com.sadellie.unitto.feature.converter.ConverterMode
|
|||||||
* @param navigateToRightScreen Function that is called when clicking right unit selection button.
|
* @param navigateToRightScreen Function that is called when clicking right unit selection button.
|
||||||
* @param swapUnits Method to swap units.
|
* @param swapUnits Method to swap units.
|
||||||
* @param converterMode [ConverterMode.BASE] doesn't use formatting for input/output.
|
* @param converterMode [ConverterMode.BASE] doesn't use formatting for input/output.
|
||||||
|
* @param formatTime If True will use [Formatter.formatTime].
|
||||||
|
* @param onOutputTextFieldClick Action to be called when user clicks on output text field.
|
||||||
*/
|
*/
|
||||||
@Composable
|
@Composable
|
||||||
internal fun TopScreenPart(
|
internal fun TopScreenPart(
|
||||||
@ -77,6 +81,8 @@ internal fun TopScreenPart(
|
|||||||
navigateToRightScreen: (unitFrom: String, unitTo: String, input: String) -> Unit,
|
navigateToRightScreen: (unitFrom: String, unitTo: String, input: String) -> Unit,
|
||||||
swapUnits: () -> Unit,
|
swapUnits: () -> Unit,
|
||||||
converterMode: ConverterMode,
|
converterMode: ConverterMode,
|
||||||
|
formatTime: Boolean,
|
||||||
|
onOutputTextFieldClick: () -> Unit
|
||||||
) {
|
) {
|
||||||
var swapped by remember { mutableStateOf(false) }
|
var swapped by remember { mutableStateOf(false) }
|
||||||
val swapButtonRotation: Float by animateFloatAsState(
|
val swapButtonRotation: Float by animateFloatAsState(
|
||||||
@ -101,12 +107,20 @@ internal fun TopScreenPart(
|
|||||||
textToCopy = calculatedValue ?: inputValue,
|
textToCopy = calculatedValue ?: inputValue,
|
||||||
)
|
)
|
||||||
MyTextField(
|
MyTextField(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.clickable(onClick = onOutputTextFieldClick),
|
||||||
primaryText = {
|
primaryText = {
|
||||||
when {
|
when {
|
||||||
networkLoading -> stringResource(R.string.loading_label)
|
networkLoading -> stringResource(R.string.loading_label)
|
||||||
networkError -> stringResource(R.string.error_label)
|
networkError -> stringResource(R.string.error_label)
|
||||||
converterMode == ConverterMode.BASE -> outputValue.uppercase()
|
converterMode == ConverterMode.BASE -> outputValue.uppercase()
|
||||||
|
formatTime and (unitTo?.group == UnitGroup.TIME) -> {
|
||||||
|
Formatter.formatTime(
|
||||||
|
input = calculatedValue ?: inputValue,
|
||||||
|
basicUnit = unitFrom?.basicUnit
|
||||||
|
)
|
||||||
|
}
|
||||||
else -> Formatter.format(outputValue)
|
else -> Formatter.format(outputValue)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -40,6 +40,8 @@ org-jetbrains-kotlinx-coroutines-test = { group = "org.jetbrains.kotlinx", name
|
|||||||
androidx-compose-ui = { group = "androidx.compose.ui", name = "ui", version.ref = "androidxComposeUi" }
|
androidx-compose-ui = { group = "androidx.compose.ui", name = "ui", version.ref = "androidxComposeUi" }
|
||||||
androidx-compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview", version.ref = "androidxComposeUi" }
|
androidx-compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview", version.ref = "androidxComposeUi" }
|
||||||
androidx-compose-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling", version.ref = "androidxComposeUi" }
|
androidx-compose-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling", version.ref = "androidxComposeUi" }
|
||||||
|
androidx-compose-ui-test-junit4 = { group= "androidx.compose.ui", name = "ui-test-junit4", version.ref = "androidxCompose" }
|
||||||
|
androidx-compose-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest", version.ref = "androidxCompose" }
|
||||||
androidx-navigation = { group = "androidx.navigation", name = "navigation-compose", version.ref = "androidxNavigation" }
|
androidx-navigation = { group = "androidx.navigation", name = "navigation-compose", version.ref = "androidxNavigation" }
|
||||||
androidx-lifecycle-runtime-compose = { group = "androidx.lifecycle", name = "lifecycle-runtime-compose", version.ref = "androidxLifecycleRuntimeCompose" }
|
androidx-lifecycle-runtime-compose = { group = "androidx.lifecycle", name = "lifecycle-runtime-compose", version.ref = "androidxLifecycleRuntimeCompose" }
|
||||||
androidx-compose-material3 = { group = "androidx.compose.material3", name = "material3", version.ref = "androidxComposeMaterial3" }
|
androidx-compose-material3 = { group = "androidx.compose.material3", name = "material3", version.ref = "androidxComposeMaterial3" }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user