[go: up one dir, main page]

Skip to content

ch4rl3x/textfield-unit

Repository files navigation

TextField with unit

Build CodeFactor Maven Central Maven Central

A simple to use Jetpack Compose TextField with automatically value transformations and user specific ui transformations. E.g. save temperature in °C, present as °F in ui

Dependency

Add the library to your module build.gradle

dependencies {
    implementation 'de.charlex.compose.material:material-textfield-unit:1.0.0-rc04'
}

or

dependencies {
    implementation 'de.charlex.compose.material3:material-textfield3-unit:1.0.0-rc04'
}

Usage

Declaring custom units

val LocalTemperatureType = compositionLocalOf<Temp.TemperatureType> {
    error("LocalTemperature not present")
}
@Immutable
class Temp(value: Float?, type: TemperatureType = TemperatureType.Celsius) : BaseUnit<Temp.TemperatureType, Float>(value, type) {

    enum class TemperatureType(val id: Int, @StringRes override val unit: Int) : UnitType {
        Celsius(0, R.string.einheit_celsius),
        Fahrenheit(1, R.string.einheit_fahrenheit)
    }

    override fun convertTo(targetType: TemperatureType): Temp {
        if (targetType == type) return this

        val celsius = when (type) {
            TemperatureType.Celsius -> value
            TemperatureType.Fahrenheit -> value?.let { Umrechnungen.convertFarToCel(value) }
        }

        val newValue = when (targetType) {
            TemperatureType.Celsius -> celsius?.round(1)
            TemperatureType.Fahrenheit -> celsius?.let { Umrechnungen.convertCelToFar(celsius) }?.round(1)
        }
        return Temp(newValue, targetType)
    }

    @Composable
    override fun getCurrentUnitType(): TemperatureType {
        return LocalTemperatureType.current
    }

    override val defaultSaveTargetType: TemperatureType
        get() = TemperatureType.Celsius

    override fun with(value: Float?, type: TemperatureType): IUnit<TemperatureType, Float> = Temp(value, type)

    override fun compareTo(other: IUnit<TemperatureType, Float>): Int {
        return compareValues(value, other.value)
    }

    override fun compareTo(value: Float): Int {
        return compareValues(this.value, value)
    }
}

/**
 * Create a [Temp] using an [Int]:
 *     val left = 10
 *     val x = left.temp
 *     // -- or --
 *     val y = 10.temp
 */
@Stable
inline val Int?.temp: Temp
    get() = Temp(value = this?.takeIf { it != -1 }?.toFloat())

/**
 * Create a [Temp] using a [Double]:
 *     val left = 10.0
 *     val x = left.temp
 *     // -- or --
 *     val y = 10.0.temp
 */
@Stable
inline val Double?.temp: Temp
    get() = Temp(value = this?.takeIf { it != -1.0 }?.toFloat())

/**
 * Create a [Temp] using a [Float]:
 *     val left = 10f
 *     val x = left.temp
 *     // -- or --
 *     val y = 10f.temp
 */
@Stable
inline val Float?.temp: Temp
    get() = Temp(value = this?.takeIf { it != -1f })

Using Preferences

/**
 * temperatureFromViewModel is always celsius
 */
val temperatureFromViewModel: Float? by remember { mutableStateOf(5f) }

/**
 * The provided LocalTemperatureType could be changed with settings from DataStore
 */
CompositionLocalProvider(
    LocalTemperatureType provides Temp.TemperatureType.Fahrenheit,
    LocalUiFormatPattern provides "#.#####",
) {
    /**
     * The user will see the fahrenheit value of the variable temperatureFromViewModel
     */
    TextFieldWithUnit(
        label = {
            Text(text = "Temperature")
        },
        unitedValue = temperatureFromViewModel.temp,
        onValueChange = { value ->
            /**
             * The user input will automatically be transformed back to celsius
             */
            temperatureFromViewModel = value
        },
        valueRepresentation = DefaultValueRepresentation(
            float = {
                it?.let { it.uiFormat("#.#") } ?: ""
            }
        )
    )
}

That's it!

License

Copyright 2023 Alexander Karkossa

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.