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.