Mohamed Elsayed
Mohamed Elsayed

Reputation: 131

How to trigger notifications once depending on a constantly updated state

I'm making a Fleet management app for trucking companies in SwiftUI and right now I am having trouble notifying the employer everytime one of their drivers start driving or stop driving. I used the CMMotionActityManager to update driver motion to my firestore db. On the employers end I have them listening for updates in the drivers motion.

The problem is that I have the employer's listening code inside a snapshotListener closure. That means that if an employer has more than one driver, everytime one driver's motion state changes, instead of notifying the employer of the most recent change in their drivers motion, it notifies them of ALL the past changes in motion for ALL the drivers they employed.

Here is the function that sends the motion data to the database.

    func setMotionUpdates(){
    

    
    let motionDoc =  db.collection("driverData").document(email).collection("resources").document("userLocation")

    if CMMotionActivityManager.isActivityAvailable() {
        
        
        motionManager.startActivityUpdates(to: OperationQueue.main) { (motion) in
          
            
            
            
            if motion!.automotive{
            
                motionDoc.updateData(["isDriving": true, "isStopped" : false])
                
                
            }
            else if motion!.stationary{
                
                motionDoc.updateData(["isStopped": true, "isDriving" : false])

               
            }
            
           
            
    }
        
}
    
}

Here is the code that reads that data and notifies the employer

            db.collectionGroup("resources").whereField("control", isEqualTo: true).addSnapshotListener { (snapshot, err) in
            
           
            
            if err != nil{print("Error fetching motion status: \(err)")}
            
            if ((snapshot?.documents.isEmpty) != nil){print("4")}
            

// Gets all the driverLocation documents

            for doc in snapshot!.documents{
              
                let isDriving = doc.get("isDriving") as! Bool
                let isStopped = doc.get("isStopped") as! Bool
                
                if isDriving == false && isStopped == false{
     
                    
                }
                
                else{

// Gets the name of the driver

                    doc.reference.parent.parent?.getDocument(completion: { (snapshot, err) in
                        
                        if err != nil{print("Error parsing driver name: \(err)")}
                        
                        let firstName = snapshot?.get("firstName") as! String
                        let lastName = snapshot?.get("lastName") as! String
                        
                        self.notifiedDriver = "\(firstName) \(lastName)"
            
                    })
                
                    

// Logic

                    if isDriving{
                        
                        send(notiTitle: "MyFleet", notiBody: "\(notifiedDriver) is back on the road.")
                        
                        showDrivingToast.toggle()
                        
                    }else if isStopped{

                       send(notiTitle: "MyFleet", notiBody: "\(notifiedDriver) has stopped driving.")
                        
                        showStoppedToast.toggle()
                  
                        
                    }
                }
            }
            
        }

Upvotes: 1

Views: 74

Answers (2)

Mohamed Elsayed
Mohamed Elsayed

Reputation: 131

Yeah looks like I got it

What I did was I created a "notified" boolean field in my database that would be updated to the db with the motion activity. Whenever the CMMotionActivityManager updates the motion state, it sets notified to false along with all the other updates I need to make.

            motionManager.startActivityUpdates(to: OperationQueue.main) { (motion) in
          
            
            
            
            if motion!.automotive{
            
                motionDoc.updateData(["isDriving": true, "isStopped" : false, "notified": false])
                
                
            }
            else if motion!.stationary{
                
                motionDoc.updateData(["isStopped": true, "isDriving" : false, "notified": false])

               
            }
            
           
            
    }

Since I am listening for updates on the employers end, The snapshotListener code will rerun and will check if they have already been notified on the motion update.

                    if (isDriving == false && isStopped == false) || notified == true{
     
                    
                }

I added "|| notified == true" to check if the notified field that I am receiving from my drivers database == true. If it is true, I am not going to run the code that notifies my driver. If it is false, I will run that code.

Upvotes: 1

bze12
bze12

Reputation: 783

Do you need to listen for driver changes on the client? If not, you can use cloud functions with a firestore trigger. When a document is updated, you can set up a function to send a push notification to the employer.

Upvotes: 0

Related Questions