ios – Unable to display a view without making previous one close in swiftui


Swift newbie here. I’m developing an app, i have a basic screen, with a side menu that can be opened from a hamburger icon and in the main view there’s a map, showing my current location, also using firebase for notifications.
I want to show i view above the main view whenever an boolean ObservableObject haveOnGoingCall is changed, then in this new menus, if a button click occurs it should exit the new views and only show another
one containing couple buttons, which it should appear on the screen when another ObservableObject callPuttedOnHold is changed. I have few conditions in the main view to check if the value of the ObservableObject changed and show the views accordingly.

The main view:

import SwiftUI

struct ContentViews: View {
    @State var presentSideMenu = false
    @State var showMenu = false
    @State var path = NavigationPath()
    
    @ObservedObject var newCall = ClientCallDefinitions()
            
    @State var refresher = 0
    
    var body: some View {
        ZStack{
            MapContainerView()
                    .edgesIgnoringSafeArea(.all)
            
            VStack{
                MapView()
            }
            .frame(maxWidth: .infinity, maxHeight: .infinity)
            .overlay(alignment: .top){
                ZStack{
                    HStack{
                        Button(action: {
                            withAnimation{
                                self.presentSideMenu.toggle()
                            }
                        }) {
                            Image(systemName: "line.horizontal.3")
                                .imageScale(.large)
                                .foregroundColor(.gray)
                                .padding(.leading, 30)
                            
                            Spacer()
                        }
                        
                        Button(action: {
                            
                        }) {
                            Image(systemName: "paperplane")
                                .imageScale(.large)
                                .foregroundColor(.gray)
                                .padding(.leading, 30)
                                .frame(width: 10, height: 20)
                            
                            Spacer()
                        }
                        .padding(.leading, 140)
                    }
                    .frame(maxWidth: .infinity)
                    .frame(height: 56)
                    .background(Color.white)
                    .zIndex(1)
                    .shadow(radius: 0.5)
                    
                }
                Text("Coonnecta client")
                    .multilineTextAlignment(.center)
                
            }
            .frame(maxWidth: .infinity)
            SideMenu()
                .zIndex(3)
            
          if newCall.haveOnGoingCall && !newCall.callPuttedOnHold {
                            clientCallViews()
                        } else if newCall.callPuttedOnHold {
                            CallPutOnHoldButtons()
                                .padding([.top], 600)
                                .zIndex(2)
                        }
                    }.refreshable {
                        refresher += 1
                    }
    }
    
    @ViewBuilder
    private func clientCallPutOnHold() -> some View{
        CallPutOnHoldButtons()
    }
    
    @ViewBuilder
    private func clientCallViews() -> some View{
        ClientCallInfoView()
            .frame(width: 400)
            .background(.white)
            .padding([.bottom], 150)
            
        ClientCallEmergencyInfoView()
            .background(.white)
            .padding([.top], 310)
        
        ClientCallButtonsView()
            .padding([.top], 580)
    }
    
    @ViewBuilder
    private func SideMenu() -> some View {
        Coonnecta_Client.SideMenu(isSideMenuShowing: $presentSideMenu, direction: .leading){
            SideMenuContents(presentSideMenu: $presentSideMenu)
                .frame(width: 300)
        }
    }
    
    @ViewBuilder
    private func MapView() -> some View {
        MapContainerView()
    }
}

struct ContentViews_Previews: PreviewProvider {
    static var previews: some View {
        ContentViews()
    }
}

The first 3 views that are called when the haveOnGoingCall boolean is changed:

import SwiftUI

struct ClientCallInfoView: View {
    var body: some View {
        VStack(spacing: 20) {
            Text("Client")
                .frame(maxWidth: .infinity, alignment: .leading)
                .font(.system(size: 25, weight: .bold))
                .foregroundColor(.red)

                    HStack {
                        VStack(alignment: .leading, spacing: 3) {
                            Text("Client").font(.headline).bold()
                            Text("Ana Julia").font(.subheadline)
                        }
                        Spacer()
                        VStack(alignment: .leading, spacing: 3) {
                            Text("Device").font(.headline)
                            Text("DCs-DDS.FDGDF").font(.subheadline)
                        }
                    }

                    // Add a spacer to create space between rows

                    HStack {
                        VStack(alignment: .leading, spacing: 3) {
                            Text("Organization").font(.headline).bold()
                            Text("Lalala").font(.subheadline)
                        }
                        Spacer()
                        VStack(alignment: .leading, spacing: 3) { // Set alignment to .trailing
                            Text("Plan Type").font(.headline)
                            Text("Golden").font(.subheadline)
                        }
                        .padding(.leading, -120) // Manually adjust the position to the left
                    }
            
                    HStack {
                        VStack(alignment: .leading, spacing: 3) {
                            Text("Blood type").font(.headline).bold()
                            Text("-O").font(.subheadline)
                        }
                        Spacer()
                        VStack(alignment: .leading, spacing: 3) { // Set alignment to .trailing
                            Text("Allergy").font(.headline)
                            Text("No").font(.subheadline)
                        }
                        .padding(.leading, -120) // Manually adjust the position to the left
                    }
            
                    HStack{
                        VStack(alignment: .leading, spacing: 3) {
                            Text("Contacts").font(.headline).bold()
                            Text("2389548348").font(.subheadline)
                        }
                        Spacer()
                    }
                    
                }
                .padding()
            }
    
}
    
    
    struct ClientCallInfoView_Previews: PreviewProvider {
        static var previews: some View {
            ClientCallInfoView()
        }
    }


import SwiftUI

struct ClientCallEmergencyInfoView: View {
    var body: some View {
        VStack(spacing: 20){
            Text("Emergency Info")
                .frame(maxWidth: .infinity, alignment: .leading)
                .font(.system(size: 25, weight: .bold))
                .foregroundColor(.red)
            
            HStack {
                VStack(alignment: .leading, spacing: 3) {
                    Text("Type").font(.headline).bold()
                    Text("SOS-BLE").font(.subheadline)
                }
                Spacer()
                VStack(alignment: .leading, spacing: 3) {
                    Text("Contacts").font(.headline)
                    Text("2389432390").font(.subheadline)
                }
            }
        }
        .padding()
    }
}

struct ClientCallEmergencyInfoView_Previews: PreviewProvider {
    static var previews: some View {
        ClientCallEmergencyInfoView()
    }
}

import SwiftUI

struct ClientCallButtonsView: View {
    @ObservedObject var callOnHold = ClientCallDefinitions()
    
    @Environment(\.dismiss) var dismiss

    var body: some View {
        VStack{
            HStack{
                Button (action: {
                    ChangeCallDefinitionsState()
                    print(callOnHold.callPuttedOnHold)
                    print(callOnHold.haveOnGoingCall)
                    dismiss()

                }) {
                    Text("Put on hold")
                        .padding([.leading], 30)
                        .padding([.trailing], 30)

                }
                
                .padding()
                .background(.orange)
                .foregroundStyle(.white)
                .controlSize(.large)
                
                Button (action: {
                    
                }){
                    Text("Confirm Alert")
                        .padding([.leading], 30)
                        .padding([.trailing], 30)
                }
                .padding()
                .background(.green)
                .foregroundStyle(.white)
            }
            
            Button(action: {
                
            }){
                Text("Cancel")
                    .padding([.leading], 50)
                    .padding([.trailing], 50)
            }
            .padding()
            .background(.red)
            .foregroundStyle(.white)
        }
        
        if callOnHold.callPuttedOnHold{
            clientCallPutOnHold()
        }
    }
    
    @ViewBuilder
    private func clientCallPutOnHold() -> some View{
        CallPutOnHoldButtons()
    }

    func ChangeCallDefinitionsState(){
        DispatchQueue.main.async {
            callOnHold.callPuttedOnHold = true
            callOnHold.haveOnGoingCall = false
        }
    }
}

struct ClientCallButtonsView_Previews: PreviewProvider {
    static var previews: some View {
        ClientCallButtonsView()
    }
}

The observable object class where i store the booleans:

import Foundation

class ClientCallDefinitions: ObservableObject{
    @Published var haveOnGoingCall: Bool = true
    @Published var callPuttedOnHold: Bool = false
}

The issue is, whenever i click the button and it changes the ObservableObject value, and the views are suppose to not appear, only the new one CallPutOnHoldButtons should appear, the new one appears in the screen, but the other ones does not close, altho the value of the ObservableObject changed correctly.

In the console i’m getting a warning: “Publishing changes from within view updates is not allowed”.
Tried using DispachQueue and Task{…} but no results.
Tried these couple solutions to make it go away but didn’t seem to work. Like using the dismiss() function, using a condition in the main view where i show all the views.

How can i fix this?
If more information is needed to understand or replicate i can provide.

Latest articles

spot_imgspot_img

Related articles

Leave a reply

Please enter your comment!
Please enter your name here

spot_imgspot_img