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\$
0

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