'Jetpack Compose - Issues by passing down States

I am new to Kotlin and jetpack compose. So while I get startig, I got my first problem and I can't solve it on my own. The Problem appears, when I started to put the States up in the MainContent-function and pass the States as Arguments to TipCalcSurface. Now I got the following problems:

Type mismatch: inferred type is Int but MutableState<Int> was expected

The other problems are consequential problems of the wrong Type, but why? If I change the type to an Int, the whole function doesn't work. Below my practiceing code.

package com.example.customtippcalc

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.*
import androidx.compose.material.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.sharp.KeyboardArrowDown
import androidx.compose.material.icons.sharp.KeyboardArrowUp
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.example.customtippcalc.ui.theme.CustomTippCalcTheme
import com.example.customtippcalc.util.calculateTipPrice
import com.example.customtippcalc.util.calculateTotalPricePerPerson

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            CustomTippCalcTheme {
                // A surface container using the 'background' color from the theme
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colors.background
                ) {
                    MainContent()
                }
            }
        }
    }
}

@Composable
fun MainContent() {
    var totalPricePerPerson by remember { mutableStateOf(0.0)}
    var personCount by remember { mutableStateOf(1)} // Problem starts here

    Column() {
        TipCalcHeader(totalPrice = totalPricePerPerson)
        TipCalcSurface(
            personCount = personCount,
            onPriceCalculate = { totalPricePerPerson = it }
        )
    }
}

@Composable
fun TipCalcHeader(totalPrice: Double = 0.0) {
    Column {
        Text(text = "Price per person:")
        Text(
            modifier = Modifier.fillMaxWidth().padding(top = 28.dp, bottom = 28.dp),
            textAlign = TextAlign.Center,
            fontSize = 24.sp,
            fontWeight = FontWeight.Bold,
            text = "$totalPrice €"
        )
    }
}

@Preview(showBackground = true)
@Composable
fun TipCalcSurface(
    personCount: MutableState<Int>, // And problem here
    onPriceCalculate: (Double) -> Unit = {}
) {
    var totalPrice by remember { mutableStateOf(0.0) }
    var invoiceAmount by remember { mutableStateOf("")}

    var totalTip by remember { mutableStateOf(0.0)}
    var sliderAmount by remember { mutableStateOf(0f) }
    var sliderAmountAtPercent by remember { mutableStateOf(0)}

    Column(modifier = Modifier
        .fillMaxWidth()
        .padding(13.dp)) {
        TextField(
            modifier = Modifier.fillMaxWidth(),
            value = invoiceAmount,
            onValueChange = {invoiceAmount = it},
            label = { Text( text = "Totalprice") }
            )
        Spacer(modifier = Modifier.height(20.dp))

        // Person Count Row
        Row(modifier = Modifier.fillMaxWidth(),
            horizontalArrangement = Arrangement.SpaceBetween,
            verticalAlignment = Alignment.CenterVertically
            ) {
            Text( text = "Person:")
            Row(verticalAlignment = Alignment.CenterVertically) {
                Button(onClick = {
                    personCount ++
                    totalPrice = calculateTotalPricePerPerson(
                        personAmount = personCount,
                        invoiceAmount = invoiceAmount.toDouble(),
                        tipAmount = totalTip
                    )
                    onPriceCalculate(totalPrice)
                } ) {
                    Icon(imageVector = Icons.Sharp.KeyboardArrowUp, contentDescription = "+")
                }
                Text( modifier = Modifier
                    .padding(start = 13.dp, end = 13.dp),
                    text = "$personCount")
                Button(
                    onClick = {
                        if (personCount > 1) personCount --
                        totalPrice = calculateTotalPricePerPerson(
                            personAmount = personCount,
                            invoiceAmount = invoiceAmount.toDouble(),
                            tipAmount = totalTip
                        )
                        onPriceCalculate(totalPrice)
                }) {
                    Icon(imageVector = Icons.Sharp.KeyboardArrowDown, contentDescription = "-")
                }
            }
        }
        Spacer(modifier = Modifier.height(20.dp))

        // Tip Amount Row
        Row(modifier = Modifier
            .fillMaxWidth(),
            horizontalArrangement = Arrangement.SpaceBetween) {
            Text( text = "Tip in €:")
            Text( text = "$totalTip €")
        }
        Spacer(modifier= Modifier.height(20.dp))

        // Tip Percentage Slider
        Row(modifier = Modifier.fillMaxWidth(),
            horizontalArrangement = Arrangement.SpaceBetween
            ) {
            Text( text = "Tip in %:")
            Text( text = "$sliderAmountAtPercent")
        }
        Slider(
            value = sliderAmount,
            onValueChange = {
                sliderAmount = it //(it * 100).toInt()
                sliderAmountAtPercent = (sliderAmount*100).toInt()
                totalTip = calculateTipPrice(
                    totalPrice = invoiceAmount.toDouble(), // Fehler bei kovertierung zu Double wenn Wert leer
                    tipAtPercent = sliderAmountAtPercent)
                totalPrice = calculateTotalPricePerPerson(
                    personAmount = personCount,
                    invoiceAmount = invoiceAmount.toDouble(),
                    tipAmount = totalTip
                )
                onPriceCalculate(totalPrice)
            })
    }
}

Thanks for help!



Solution 1:[1]

When you do var personCount by remember { mutableStateOf(1)}, then the type of personCount is Int. You are not assigning the MutableState<Int> to personCount, but delegating to it.

In order to make it work, you should pass the personCount as an Int to TipCalcSurface, as well as adding a updatePersonCount: (Int) -> Unit function to it. You can then call that function when you want to update personCount.

Like this:

fun TipCalcSurface(
    personCount: Int,
    updatePersonCount: (Int) -> Unit = {},
    onPriceCalculate: (Double) -> Unit = {}
) {
  // Fix the code mutating personCount to instead call updatePersonCount.
}

@Composable
fun MainContent() {
    var totalPricePerPerson by remember { mutableStateOf(0.0) }
    var personCount by remember { mutableStateOf(1) }

    Column() {
        TipCalcHeader(totalPrice = totalPricePerPerson)
        TipCalcSurface(
            personCount = personCount,
            updatePersonCount = { personCount = it }
            onPriceCalculate = { totalPricePerPerson = it }
        )
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 marstran