Передайте параметр от Navhost To initAndroid

Форум для тех, кто программирует под Android
Ответить
Anonymous
 Передайте параметр от Navhost To init

Сообщение Anonymous »

Я занимаюсь обучением, изменяя курс Android от https://developer.android.com/codelabs/ ... athways%2F Android-Basics-Compose-Unit-4-Pathway-1%23Codelab-HTTPS%3A%2f%2fdeveloper.Android.com%2fcodelabs%2fbasic-android-kotlin-compose-viewmodel-and#0
Я добавил компонент Navhost, чтобы выбрать «уровень», и мне нужно передать значение уровня следующему вызовому компостируемому. Проблема в том, что мне нужно это значение для правильной инициализации расчета, показанного на экране. Я не знаю, как это достичь. Если пользователь выбирает «Medium», приложение поднимет другие числа .. и т. Д. Значение по умолчанию «простое», я не знаю, как обновить его для приложения Использовать новое значение во время инициализации. < /P>
Спасибо за помощь < /p>
Вот код < /p>
package com.example.calcul.ui

import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import androidx.navigation.toRoute
import com.example.calcul.AppViewModel
import com.example.calcul.data.AppUiState
import kotlinx.serialization.Serializable

@Serializable
private data object ChooseLevelRoute

@Serializable
private data class AdditionRoute(val level: String)

@Composable
fun ActivityChoice(
navController: NavHostController = rememberNavController(),
calculationViewModel: AppViewModel = viewModel()
) {
Scaffold() { innerPadding ->

NavHost(
navController = navController,
startDestination = ChooseLevelRoute,
) {
composable {
ChooseLevel(
onButtonLevelEasyClicked = {
navController.navigate(AdditionRoute("Easy"))
},
onButtonLevelMediumClicked = {
navController.navigate(AdditionRoute("Medium"))
},
onButtonLevelHardClicked = {
navController.navigate(AdditionRoute("Hard"))
},
modifier = Modifier
.fillMaxSize()
.padding(innerPadding)
)
}

composable {
val additionRoute = it.toRoute()
AdditionScreen(
level = additionRoute.level,
modifier = Modifier
.fillMaxSize()
.padding(innerPadding)
)
}
}

}
}
< /code>
package com.example.calcul.ui

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.widthIn
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.example.calcul.AppViewModel

@Composable
fun ChooseLevel(
// calculationViewModel: AppViewModel = viewModel(),
onButtonLevelEasyClicked: () -> Unit,
onButtonLevelMediumClicked: () -> Unit,
onButtonLevelHardClicked: () -> Unit,
modifier: Modifier = Modifier
) {

Column(
modifier = modifier,
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Button(
onClick = onButtonLevelEasyClicked,
Modifier.widthIn(min = 250.dp)
) {
Text("Easy")
}
Button(
onClick = onButtonLevelMediumClicked,
Modifier.widthIn(min = 250.dp)
) {
Text("Medium")
}
Button(
onClick = onButtonLevelHardClicked,
Modifier.widthIn(min = 250.dp)
) {
Text("Hard")
}
}
}
< /code>
package com.example.calcul.ui

import android.app.Activity
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeDrawingPadding
import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Clear
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme.colorScheme
import androidx.compose.material3.MaterialTheme.shapes
import androidx.compose.material3.MaterialTheme.typography
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
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 androidx.lifecycle.viewmodel.compose.viewModel
import com.example.calcul.AppViewModel
import com.example.calcul.R
import com.example.calcul.data.MAX_NUMBER_OF_CALCULATION
import com.example.calcul.data.SCORE_INCREASE

@Composable
fun AdditionScreen(
calculationViewModel: AppViewModel = viewModel(),
level: String,
modifier: Modifier = Modifier
) {

// whenever there is a change in the uiState value, recomposition occurs for the
// composables using the appUiState value
val appUiState by calculationViewModel.uiState.collectAsState()

println("Debut AdditionScreen avec level = " + appUiState.difficulty)

// Next line have to be removed
// It updates num1 and num2, recomposition occurs and enters in a loop
calculationViewModel.updateGameDifficulty(level)

//println("Debut AdditionScreen avec level mis à jour = " + appUiState.difficulty)

//val mediumPadding = dimensionResource(R.dimen.padding_medium)
val mediumPadding = 16.dp

Column(
modifier = Modifier
.statusBarsPadding()
.verticalScroll(rememberScrollState())
.safeDrawingPadding()
.padding(mediumPadding),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {

Text(
text = stringResource(R.string.app_name) + " - " + appUiState.difficulty,
style = typography.titleLarge,
)
AppLayout(
onUserGuessChanged = { calculationViewModel.updateUserGuess(it) },
wordCount = appUiState.currentCalculationCount,
currentWrongCalculation = appUiState.currentWrongCalculationCount,
userGuess = calculationViewModel.userGuess,
onKeyboardDone = { calculationViewModel.checkUserGuess() },
//currentScrambledWord = appUiState.currentScrambledWord,
num1 = appUiState.num1,
num2 = appUiState.num2,
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
.padding(mediumPadding)
)
Column(
modifier = Modifier
.fillMaxWidth()
.padding(mediumPadding),
verticalArrangement = Arrangement.spacedBy(mediumPadding),
horizontalAlignment = Alignment.CenterHorizontally
) {
Button(
modifier = Modifier.fillMaxWidth(),
onClick = { calculationViewModel.checkUserGuess() }
) {
Text(
text = stringResource(R.string.submit),
fontSize = 16.sp
)
}

OutlinedButton(
onClick = { calculationViewModel.skipCalculation() },
modifier = Modifier.fillMaxWidth()
) {
Text(
text = stringResource(R.string.skip),
fontSize = 16.sp
)
}
}

GameStatus(score = appUiState.score, modifier = Modifier.padding(20.dp))

if (appUiState.isGameOver) {
FinalScoreDialog(
score = appUiState.score,
onPlayAgain = { calculationViewModel.resetApp() }
)
}
}
}

@Composable
fun GameStatus(score: Int, modifier: Modifier = Modifier) {
Card(
modifier = modifier
) {
Text(
text = stringResource(R.string.score, score),
style = typography.headlineMedium,
modifier = Modifier.padding(8.dp)
)

}
}

@Composable
fun AppLayout(
//currentScrambledWord: String,
wordCount: Int,
currentWrongCalculation: Int,
userGuess: String,
onUserGuessChanged: (String) -> Unit,
onKeyboardDone: () -> Unit,
num1: Int,
num2: Int,
modifier: Modifier = Modifier
) {
val mediumPadding = dimensionResource(R.dimen.padding_medium)

Card(
modifier = modifier,
elevation = CardDefaults.cardElevation(defaultElevation = 5.dp)
) {
Column(
verticalArrangement = Arrangement.spacedBy(mediumPadding),
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.padding(mediumPadding)
) {
// Compteurs
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly
) {
Text(
modifier = Modifier
.clip(shapes.medium)
.background(colorScheme.surfaceTint)
.padding(horizontal = 10.dp, vertical = 4.dp),
//.weight(1f),
//.align(alignment = Alignment.Start),
text = stringResource(R.string.word_count, wordCount) + "/" + MAX_NUMBER_OF_CALCULATION,
style = typography.titleMedium,
color = colorScheme.onPrimary
)
Text(
modifier = Modifier
.clip(shapes.medium)
.background(Color.Red)
.padding(horizontal = 10.dp, vertical = 4.dp),
//.align(alignment = Alignment.End),
text = stringResource(R.string.word_count, currentWrongCalculation) + "/" + MAX_NUMBER_OF_CALCULATION,
style = typography.titleMedium,
color = colorScheme.onPrimary
)
}
/*
Text(
text = currentScrambledWord,
style = typography.displayMedium
)
*/
Text(
text = stringResource(R.string.instructions),
textAlign = TextAlign.Center,
style = typography.titleMedium
)
Row(
verticalAlignment = Alignment.CenterVertically
) {
Column(
//verticalArrangement = Arrangement.spacedBy(mediumPadding)
) {
Text(
text = "$num1 + $num2 = ",
style = typography.titleLarge
)
}
Column {
OutlinedTextField(
value = userGuess,
singleLine = true,
shape = shapes.small,
modifier = Modifier.fillMaxWidth(),
colors = TextFieldDefaults.colors(
focusedContainerColor = colorScheme.surface,
unfocusedContainerColor = colorScheme.surface,
disabledContainerColor = colorScheme.surface,
),
onValueChange = onUserGuessChanged,
label = { Text(stringResource(R.string.enter_your_word)) },
//isError = isGuessWrong,
keyboardOptions = KeyboardOptions.Default.copy(
imeAction = ImeAction.Done,
keyboardType = KeyboardType.Number
),
keyboardActions = KeyboardActions(
onDone = { onKeyboardDone() }
),
trailingIcon = {
Icon(
Icons.Filled.Clear,
contentDescription = "",
modifier = Modifier
.clickable {
onUserGuessChanged("")
}
)
}

)
}
}
}
}
}

/*
* Creates and shows an AlertDialog with final score.
*/
@Composable
private fun FinalScoreDialog(
score: Int,
onPlayAgain: () -> Unit,
modifier: Modifier = Modifier
) {
val activity = (LocalContext.current as Activity)

AlertDialog(
onDismissRequest = {
// Dismiss the dialog when the user clicks outside the dialog or on the back
// button. If you want to disable that functionality, simply use an empty
// onCloseRequest.
},
title = {
if (score > 70) {
Text(text = stringResource(R.string.congratulations))
} else {
Text(text = stringResource(R.string.not_congratulations))
}
},
text = { Text(
text = stringResource(R.string.you_scored, score) +
"/" + MAX_NUMBER_OF_CALCULATION * SCORE_INCREASE
) },
modifier = modifier,
dismissButton = {
TextButton(
onClick = {
activity.finish()
}
) {
Text(text = stringResource(R.string.exit))
}
},
confirmButton = {
TextButton(onClick = onPlayAgain) {
Text(text = stringResource(R.string.play_again))
}
}
)
}

@Preview (showBackground = true)
@Composable
fun AppScreenPreview() {
AdditionScreen(level = "Easy")
}
< /code>
package com.example.calcul.data

/**
* To store the state (like variables) of the app
*/

data class AppUiState(
val score: Int = 0,
val num1: Int = 0,
val num2: Int =0,
val currentScrambledWord: String = "",
val currentCalculationCount: Int = 1,
val currentWrongCalculationCount: Int = 0,
val currentRightCalculationCount: Int = 0,
val isGameOver: Boolean = false,
val difficulty: String = "Easy"
)
< /code>
package com.example.calcul

import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
import com.example.calcul.data.AppUiState
import com.example.calcul.data.MAX_NUMBER_OF_CALCULATION
import com.example.calcul.data.SCORE_INCREASE
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlin.random.Random

class AppViewModel : ViewModel() {

// App UI State
// _uiState is accessible and editable only within the AppViewModel class
private val _uiState = MutableStateFlow(AppUiState())

// The UI can read its value using the read-only property, uiState
val uiState: StateFlow = _uiState.asStateFlow()

var userGuess by mutableStateOf("")
private set

private fun pickUpRandomNumberEasy(): Int {
return Random.Default.nextInt(0, 10)
}

private fun pickUpRandomNumberMedium(): Int {
return Random.Default.nextInt(10, 20)
}

fun resetApp() {
println("Entrée dans resetApp avec uiState.value.difficulty = " + uiState.value.difficulty)
println("Entrée dans resetApp avec uiState.value.difficulty = " )
_uiState.value = AppUiState(
score = 0,
//num1 = pickUpRandomNumberEasy(),
num1 = when (uiState.value.difficulty) {
"Easy" -> pickUpRandomNumberEasy()
"Medium" -> pickUpRandomNumberEasy()
"Hard" -> pickUpRandomNumberMedium()
else -> 0
},
//num2 = pickUpRandomNumberEasy()
num2 = when (uiState.value.difficulty) {
"Easy" -> pickUpRandomNumberEasy()
"Medium" -> pickUpRandomNumberMedium()
"Hard" -> pickUpRandomNumberMedium()
else -> 0
},
)
}

init {
println("Entrée dans init")
resetApp()
println("Sortie init")
}

fun updateUserGuess(guessedResult: String){
userGuess = guessedResult.toString()
//println("2 fin updateUserGuess " + _uiState.value)
//println("2 fin updateUserGuess " + currentAppUiState)
}

fun checkUserGuess() {
val addResult = _uiState.value.num1 + _uiState.value.num2

if (userGuess.toInt() == addResult) {
val updatedScore = _uiState.value.score.plus(SCORE_INCREASE)
//println("->checkUserGuess: egalité")
updateAppState(updatedScore)
} else {
/**
println("On entre dans la branche else car réponse incorrecte")
*/
skipCalculation()
}
//println("4 Fin checkUserGuess: " + _uiState.value)
}

fun skipCalculation() {
// Increment the currentWrongCalculationCount counter
_uiState.update { currentState ->
currentState.copy(
currentWrongCalculationCount = currentState.currentWrongCalculationCount.inc(),
)
}
// Call to updateAppState to init interface for next calculation
updateAppState(_uiState.value.score)
}

fun updateGameDifficulty(level : String) {
println("Entrée dans updateGameDifficulty : $level")
_uiState.update { currentState ->
currentState.copy(
difficulty = level,
num1 = when (uiState.value.difficulty) {
"Easy" -> pickUpRandomNumberEasy()
"Medium" -> pickUpRandomNumberEasy()
"Hard" -> pickUpRandomNumberMedium()
else -> 0
},
//num2 = pickUpRandomNumberEasy()
num2 = when (uiState.value.difficulty) {
"Easy" -> pickUpRandomNumberEasy()
"Medium" -> pickUpRandomNumberMedium()
"Hard" -> pickUpRandomNumberMedium()
else -> 0
}
)
}
println("Sortie dans updateGameDifficulty : $level")
}

private fun updateAppState(updatedScore: Int) {
/** Si on a atteint le nb max de calculs, on s'arrête
* Sinon on continue
* Pour continuer, il faut 2 nouveaux nombres num1 et num2
*/
if (_uiState.value.currentCalculationCount == MAX_NUMBER_OF_CALCULATION) {
_uiState.update { currentState ->
currentState.copy(
isGameOver = true,
score = updatedScore
)
}
} else {
// On continue
//println("résultat, mise à jour du score..")
_uiState.update { currentState ->
currentState.copy(
num1 = pickUpRandomNumberEasy(),
num2 = pickUpRandomNumberEasy(),
score = updatedScore,
currentCalculationCount = currentState.currentCalculationCount.inc(),
currentRightCalculationCount = currentState.currentRightCalculationCount.inc(),
)
}
// On efface le formulaire
updateUserGuess("")
//println("3 updateAppState : " + _uiState.value)
}
}
}


Подробнее здесь: https://stackoverflow.com/questions/796 ... st-to-init
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Android»