So I have Two ViewModels in my Calculator App in which I all reference in my Compose NavGraph so I can use the same ViewModel instance. I set a Boolean State(historyCheck) in the first ViewModel and I set it too true to "Clear" the History I set which is a history of Calculations I am trying to retrieve from both ViewModels. The issue now is that the Boolean State "strCalcViewModel.historyCheck" changes before the variable above it get's assigned which then makes the 'if' statement I setup fail which in turns makes the whole Implementation also fail as it is always set to false.
This is my code Below... My Compose NavGraph.
@Composable
fun ComposeNavigation(
navController: NavHostController,
) {
/**
* Here We declare an Instance of our Two ViewModels, their states and History States. This is because we don't want to have the same States for the two Screens.
*/
val strCalcViewModel = viewModel<CalculatorViewModel>()
val sciCalcViewModel = viewModel<ScientificCalculatorViewModel>()
val strCalcState = strCalcViewModel.strState
val sciCalcState = sciCalcViewModel.sciState
val strHistoryState = strCalcViewModel.historyState
val sciHistoryState = sciCalcViewModel.historyState
// This holds our current available 'HistoryState' based on where the Calculation was performed(Screens) by the USER.
var currHistory by remember { mutableStateOf(CalculatorHistoryState()) }
if(strCalcViewModel.historyCheck) {
currHistory = strHistoryState
strCalcViewModel.historyCheck = false // this gets assigned before the 'currHistory' variable above thereBy making the the if to always be false
} else {
currHistory = sciHistoryState
}
NavHost(
navController = navController,
startDestination = "main_screen",
) {
composable("main_screen") {
MainScreen(
navController = navController, state = strCalcState, viewModel = strCalcViewModel
)
}
composable("first_screen") {
FirstScreen(
navController = navController, state = sciCalcState, viewModel = sciCalcViewModel
)
}
composable("second_screen") {
SecondScreen(
navController = navController, historyState = currHistory, viewModel = strCalcViewModel
)
}
}
}
Then my ViewModel
private const val TAG = "CalculatorViewModel"
class CalculatorViewModel : ViewModel() {
var strState by mutableStateOf(CalculatorState())
// This makes our state accessible by outside classes but still readable
private set
var historyState by mutableStateOf(CalculatorHistoryState())
private set
private var leftBracket by mutableStateOf(true)
private var check = 0
var checkState by mutableStateOf(false)
var historyCheck by mutableStateOf(false)
// Function to Register our Click events
fun onAction(action : CalculatorAction) {
when(action) {
is CalculatorAction.Number -> enterNumber(action.number)
is CalculatorAction.Decimal -> enterDecimal()
is CalculatorAction.Clear -> {
strState = CalculatorState()
check = 0
}
is CalculatorAction.ClearHistory -> checkState = true
is CalculatorAction.Operation -> enterStandardOperations(action.operation)
is CalculatorAction.Calculate -> performStandardCalculations()
is CalculatorAction.Delete -> performDeletion()
is CalculatorAction.Brackets -> enterBrackets()
}
}
// We are Basically making the click events possible by modifying the 'state'
private fun performStandardCalculations() {
val primaryStateChar = strState.primaryTextState.last()
val primaryState = strState.primaryTextState
val secondaryState = strState.secondaryTextState
if (!(primaryStateChar == '(' || primaryStateChar == '%')) {
strState = strState.copy(
primaryTextState = secondaryState
)
strState = strState.copy(secondaryTextState = "")
// Below, we store our Calculated Values in the History Screen after it has been Calculated by the USER.
historyState = historyState.copy(
historySecondaryState = secondaryState
)
historyState = historyState.copy(
historyPrimaryState = primaryState
)
historyCheck = true // this is where I assign it to true when I complete my Calculations and pass it to the history State
} else {
strState = strState.copy(
secondaryTextState = "Format error"
)
strState = strState.copy(
color = ferrari
)
}
}
}
CodePudding user response:
You're checking the if condition and assigning a new value to your viewModel variable in the Compose function, it's not correct! you should use side-effects
LaunchedEffect(strCalcViewModel.historyCheck) {
if(strCalcViewModel.historyCheck) {
currHistory = strHistoryState
strCalcViewModel.historyCheck = false
} else {
currHistory = sciHistoryState
}}
Whenever there is a new change in strCalcViewModel.historyCheck
this block will run
you can check out here for more info Side-effects in Compose
CodePudding user response:
Based on Sadegh.t's Answer I got it working but didn't write it the exact same way and used a different Implementation which I will post now.
I Still used a side-effect but instead of checking for a change in the "historyCheck", I checked for a change in the 'State' itself and also instead of using a Boolean variable, I used the State itself for the basis of the Condition. So here is my answer based on Sadegh.t's original answer.
var currHistory by remember { mutableStateOf(CalculatorHistoryState()) }
LaunchedEffect(key1 = strCalcState) {
if(strCalcState.secondaryTextState.isEmpty()) {
currHistory = strHistoryState
}
}
LaunchedEffect(key1 = sciCalcState) {
if(sciCalcState.secondaryTextState.isEmpty()) {
currHistory = sciHistoryState
}
}