I have a Flutter Application that regularly sends me “messages” with Data. In my ViewModel I have the code to decode the data and in my ContentView I make an @State private var viewModel = ViewModel, and pass variables from that viewModel Instance to my other Views through the NavigationLink in my ContentView. The ChallengeTabView (the simplified version that doesn’t work is below) accepts the currentChallenge and every time it gets changed I want the view to update.
struct ChallengeTabView: View {
let currentChallenge: CoreChallengeData
@State private var timer: Timer?
@State private var counter = 0
@State private var isRunning = false
@State private var showCancelAlert = false
private var editableButtons: Bool {
return currentChallenge.state.type != .DelayedChallengeState || currentChallenge.state.type != .NoActiveChallengeState
}
private var challengeIsActive: Bool {
currentChallenge.state.type != .NoActiveChallengeState
}
@State private var message = "No Message"
@State private var conter = 0
var body: some View {
NavigationStack{
Text(message)
TabView{
if challengeIsActive{
VStack(alignment: .leading){
Text("(DateUtilities.formatSecondsToString(duration: currentChallenge.state.data.duration - counter))")
.font(.largeTitle)
HStack{
ForEach(0..<currentChallenge.state.data.maxLives, id: .self){ life in
if life > currentChallenge.state.data.currentLives - 1{
Image(systemName: "heart.slash")
.resizable()
.scaledToFit()
.foregroundStyle(.tertiary)
} else{
Image(systemName: "heart.fill")
.resizable()
.scaledToFit()
.foregroundStyle(.red)
}
}
}
.frame(height: 30)
}
}
else {
Text("Keine Aktive Challenge")
}
}
.navigationTitle("Challenge")
.navigationBarTitleDisplayMode(.inline)
}
}
}
So if I get a new message the view gets updated, and for example the currentLives var of my struct gets updated in the View. But I also want to make a switch for one of the other Variables in my Struct, that is an Enum. Depending on the type I want to get different behavior. I tried putting that switch on .onAppear oder .task but neither of that worked, because I always had to navigate back to the content view and click on the NavLink again to have the code in the onAppear executed. So how can this switch be executed every time the currentChallenge variable gets changed/replaced.
My struct:
enum StateType: String, Codable{
case NoActiveChallengeState, DelayedChallengeState, PausedChallengeState, ActiveChallengeState, BelowThresholdState
}
struct CoreChallengeData: Codable{
let event: Event
let state: CurrentState
}
struct CurrentState: Codable {
let data: ChallengeInformation
let type: StateType
}
struct Event: Codable {
let type: String
}
struct ChallengeInformation: Codable {
let currentLives: Int
let duration: Int
let maxLives: Int
let reward: Int
let since: String
}
My ContentView:
struct ContentView: View {
@State private var viewModel: WatchViewModel = WatchViewModel()
@State private var vibrates = false
@State private var showBatterySheet = false
var body: some View {
NavigationStack{
NavigationLink("Challenge View"){
ChallengeTabView(currentChallenge: viewModel.challengeMessage)
}
ScoreTabView(liveScores: viewModel.liveScores)
.accessibilityLabel("Start")
.onAppear{
//viewModel.sendDataMessage(for: .syncRequest)
}
.sheet(isPresented: $showBatterySheet) {
VStack{
Text("Batterie:")
Text("99%")
.font(.title)
.foregroundStyle(.green)
}
}
}
}
}
I tried onAppear and .task but both didn’t work unless I navigated back to the ContentView and then clicked on the NavLink again.