Reputation: 131
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
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
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