3
\$\begingroup\$

I have made a length-units converter with Jetpack Compose.

enter image description here

enter image description here

Here's the source-code:

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            LengthConverterTheme {
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colors.background
                ) {
                    MainUI()
                }
            }
        }
    }
}

fun convertInput(fromUnit: Units, toUnit: Units, fromValue: Double): Double {
    var lengthMeter = 0.0
    when (fromUnit) {
        Units.meter -> lengthMeter = fromValue * 1.0
        Units.kilometer -> lengthMeter = fromValue * 1000.0
        Units.feet -> lengthMeter = fromValue * 0.3048
        Units.yard -> lengthMeter = fromValue * 0.9144
        Units.miles -> lengthMeter = fromValue * 1609.34
    }

    var resultVal = 0.0
    when (toUnit) {
        Units.meter -> resultVal = lengthMeter
        Units.kilometer -> resultVal = lengthMeter / 1000.0
        Units.feet -> resultVal = lengthMeter * 3.28084
        Units.yard -> resultVal = lengthMeter * 1.09361
        Units.miles -> {
            resultVal = lengthMeter * 0.000621371
        }
    }

    return resultVal
}

@Composable
fun MainUI() {
    val context = LocalContext.current
    var isSelectedFrom by remember {
        mutableStateOf(Units.meter)
    }
    var isSelectedTo by remember {
        mutableStateOf(Units.meter)
    }
    var userInput by remember {
        mutableStateOf("0.0")
    }
    var currentResult by remember {
        mutableStateOf(0.0)
    }

    Column(modifier = Modifier
        .fillMaxWidth()
        .padding(
            top = 15.dp,
            start = 25.dp,
            end = 25.dp
        )) {
        TextField(value = userInput,
            modifier = Modifier
                .fillMaxWidth()
                .padding(top = 10.dp),
            placeholder = {
                Text("Enter value to convert")
            },
            colors = TextFieldDefaults.textFieldColors(
                backgroundColor = Color.White,
                textColor = Color.Black),
            onValueChange = {
                if (it.isNotEmpty()) {
                    userInput = it
                    currentResult = convertInput(isSelectedFrom, isSelectedTo, it.toDouble())
                }
            })
        UnitPicker(title = "Convert from: ",
            currentlySelected = isSelectedFrom) {
            isSelectedFrom = it
            currentResult = convertInput(isSelectedFrom, isSelectedTo, userInput.toDouble())
        }
        UnitPicker(title = "Convert to: ",
            currentlySelected = isSelectedTo) {
            isSelectedTo = it
            currentResult = convertInput(isSelectedFrom, isSelectedTo, userInput.toDouble())
        }
        Text("Result: ${currentResult.toString()}",
            modifier = Modifier.padding(top = 25.dp),
            fontSize = 20.sp,
            fontWeight = FontWeight.Bold)
    }
}


@Composable
fun UnitPicker(title: String, currentlySelected: Units, setUnit: (Units) -> Unit) {
    Text("Convert from: ", fontSize = 20.sp, fontWeight = FontWeight.Bold)
    Units.values().forEach {
        Row(
            Modifier.fillMaxWidth(),
            horizontalArrangement = Arrangement.Start,
            verticalAlignment = Alignment.CenterVertically) {
            Text(it.name.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.ROOT) else it.toString() })
            var isSelected = it == currentlySelected
            RadioButton(selected = isSelected,
                onClick = {
                    setUnit(it)
                })
        }
    }
    Divider()
}


enum class Units {
    meter,
    kilometer,
    feet,
    yard,
    miles
}

Could the central algorithm (within the function 'convertInput') become improved? Is there are more elegant solution?

What should me modified to accomplish a more Kotlin-ideomatic code?

Looking forward to reading your answers and comments?

\$\endgroup\$
0

1 Answer 1

3
\$\begingroup\$

Regarding making this more idiomatic Kotlin code you can take advantage of direct value assignment like so:

val lengthMeter = when (fromUnit) {
    Units.Meter -> fromValue * 1.0
    Units.Kilometer -> fromValue * 1000.0
    Units.Feet -> fromValue * 0.3048
    Units.Yard -> fromValue * 0.9144
    Units.Miles -> fromValue * 1609.34
}

Likewise you can return from a function in this way:

return when (toUnit) {
    Units.Meter -> lengthMeter
    Units.Kilometer -> lengthMeter / 1000.0
    Units.Feet -> lengthMeter * 3.28084
    Units.Yard -> lengthMeter * 1.09361
    Units.Miles -> lengthMeter * 0.000621371
}

The complete function then looks like this:

fun convertInput(fromUnit: Units, toUnit: Units, fromValue: Double):Double {
    val lengthMeter = when (fromUnit) {
    Units.Meter -> fromValue * 1.0
    Units.Kilometer -> fromValue * 1000.0
    Units.Feet -> fromValue * 0.3048
    Units.Yard -> fromValue * 0.9144
    Units.Miles -> fromValue * 1609.34
}

return when (toUnit) {
    Units.Meter -> lengthMeter
    Units.Kilometer -> lengthMeter / 1000.0
    Units.Feet -> lengthMeter * 3.28084
    Units.Yard -> lengthMeter * 1.09361
    Units.Miles -> lengthMeter * 0.000621371
  }
}

Also. The naming convention for enum values in Kotlin is to use uppercase as below

   enum class Units {
     Meter,
     Kilometer,
     Feet,
     Yard,
     Miles
   }
\$\endgroup\$
1
  • \$\begingroup\$ Great answer. Thanks a lot. \$\endgroup\$ Jan 17, 2023 at 5:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.