I have configured firebase Notifications for my app. Inside the app delegate function that receives and shows the notification content when the notification is received, i have a logic of a timer, after the times went off, the value of my observable object haveOnGoingCall is set to false. This is important for checking the value of haveOnGoingCall on another view and decide to render it or not further more.
MainContentView:
import SwiftUI
import Foundation
class ClientCallDefinitionsRepro: ObservableObject{
@Published var haveOnGoingCall: Bool = false
}
struct MainContentView: View {
@StateObject var newCall: ClientCallDefinitionsRepro = ClientCallDefinitionsRepro()
@State private var isOnGoingCall: Bool = false
var body: some View {
ZStack{
Button(action: {
print(self.newCall.haveOnGoingCall)
}){Text("click")}
if newCall.haveOnGoingCall{
ClientCallInfoViewRepro()
.frame(width: 400)
.background(Color.yellow)
.padding([.bottom], 450)
.transition(.slide) // Optional: Add transition animation
.onDisappear {
DispatchQueue.main.async {
self.newCall.haveOnGoingCall = false
}
}
}
}
}
}
Then here’s the code for the function inside for the firebase notification detect and the timer logic is inside of it:
@State private var timeRemaining = 100
let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
@ObservedObject var newCall: ClientCallDefinitionsRepro = ClientCallDefinitionsRepro()
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
// Handle the push notification payload
var timer: Timer?
var elapsedTime: TimeInterval = 0.0
let oneMinute: TimeInterval = 10.0 // One minute in seconds
// print("Before setting haveOnGoingCall to true")
// print(self.newCall.haveOnGoingCall)
DispatchQueue.main.async {
self.newCall.haveOnGoingCall = true
print(self.newCall.haveOnGoingCall, "see here if the notification changed the value of haveOnGoingCall")
}
DispatchQueue.main.async {
NotificationCenter.default.post(name: Notification.Name("DidReceiveRemoteNotification"), object: nil)
}
// print("After setting haveOnGoingCall to true")
// print(self.newCall.haveOnGoingCall)
// Start a timer
print(self.newCall.haveOnGoingCall, "see here if the notification changed the value of haveOnGoingCall after")
timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { timer in
elapsedTime += 1.0
// Check if one minute has passed
if elapsedTime < oneMinute && self.newCall.haveOnGoingCall{
DispatchQueue.main.async {
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate)
AudioServicesPlayAlertSound(SystemSoundID(1322))
}
} else{
// One minute has passed, invalidate the timer and set the condition
timer.invalidate()
DispatchQueue.main.async {
self.newCall.haveOnGoingCall = false
print(self.newCall.haveOnGoingCall)
print("newCall setted to false here")
}
}
}
print("Received push notification: \(userInfo)")
DispatchQueue.main.async {
NotificationCenter.default.post(name: Notification.Name("DidReceiveRemoteNotification"), object: nil)
}
// Perform background tasks or update UI based on the received payload
print(self.newCall.haveOnGoingCall)
completionHandler(.newData)
}
@main
struct Coonnecta_ClientApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var delegate
@ObservedObject var newCall: ClientCallDefinitionsRepro = ClientCallDefinitionsRepro()
var body: some Scene {
WindowGroup {
NavigationView {
MainContentView(newCall: newCall)
.environmentObject(LoginSettings())
.onReceive(NotificationCenter.default.publisher(for: Notification.Name("DidReceiveRemoteNotification"))) { _ in
// Handle the notification, update your @StateObject
self.newCall.haveOnGoingCall = true
}
}
.environmentObject(newCall) // Pass the newCall instance
}
}
}
}
Issue is, after i receive the notification, i set the value of haveOnGoingCall to true, this works fine, and the ClientCallInfoViewRepro in MainContentView is showed correctly and by using the button in the view, i can see that the value of haveOnGoingCall is set fine. After the time goes off, the value of haveOnGoingCall will still be true, altho i set it to be false in the timer logic, and the view ClientCallInfoViewRepro is not closed.
ClientCallInfoViewRepro code:
//
// ClientCallInfoViewRepro.swift
// Coonnecta Client
//
// Created by Anilton on 19/01/2024.
//
import SwiftUI
struct ClientCallInfoViewRepro: 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 ClientCallInfoViewRepro_Previews: PreviewProvider {
static var previews: some View {
ClientCallInfoViewRepro()
}
}
How to fix this issue?
If needed the complete code for the app delegate i will provide, thanks in advance.