geoFire .getLocation using Firebase and need an observe to monitor changes as they occur, Swift - swift

I am using GeoFire in Swift and am able to .setLocation for a user and .getLocation I can retrieve their location and it all works good, i can then create an annotation and also create a poly line to a destination.
What I would now like to do is to move the user location along the polyline as the user travels.
To do this I was wondering how can I setup a Firebase.observe to let me know when the user moves and the map will auto update
The code I use for getLocation (snippet)
func fetchTradeLocationTest() {
guard let uid = tradeUser?.uid else { return }
let geoFire = GeoFire(firebaseRef: DB_REF.child("tradelocation"))
geoFire.getLocationForKey(uid) { (location, error) in
if (error != nil) {
print("DEBUG: An error occurred getting the location for \"tradeLocation\": \(error?.localizedDescription)")
} else if (location != nil) {
print("DEBUG: location = \(location)")
} else {
print("DEBUG: GeoFire does not contain a location for \"tradeLocation\"")
}
}
}
Wonder if anyone can guide me on how to set it up as an observer such that i get updated position.
Appreciate any help

GeoFire adds the ability to run geoqueries on Firebase, which means that you can find the keys that are in a certain geographic range and detect the data in it, and changes to that data.
In your specific use-case, you already know the key that you want to monitor. This mens you don't need a geoquery, but instead can use the regular observe API of the Realtime Database to monitor that specific key:

Related

Is there a way to let a user change their location by searching for a place?

I'm making an app in XCode similar to Yelp where it displays nearby restaurants based on the user's location. I would like to add a feature where the user can search for a location and the app will respond by showing restaurants at that location instead of the user's current location. The app pulls the user's location and displays restaurants with this code: locationService.newLocation = { [weak self] result in switch result { case .success(let location): self?.loadBusinesses(with: location.coordinate) case .failure(let error): print(error.localizedDescription) }
"coordinate" is a var: open var coordinate: CLLocationCoordinate2D { get }
Is there a way to let the user search for a location to change "coordinate" and replace it with the location they searched? I'm somewhat new to coding, so this might not be enough information, please let me know if I'm missing some information.

Health Kit: How to set 'totalEnergyBurned' for workout?

Today I worked for the first time with Apple Health Kit and successfully saved a workout in Health with the basic informations (activityType, start and end).
My app is in basic function an interval timer where you can create your own workout. Now in the next step I want to add the calories burned in the workout. This information is stored in the attribute 'totalEnergyBurned'.
Do I need to calculate this value myself or can I query this value directly if the user is wearing an Apple Watch? Or maybe the value is even automatically added to the workout if there is the corresponding record? (So far I have only tested the app in the simulator, which is why I can't answer this possibility).
My current code:
func saveToHealthKit(entryID: String){
if HKHealthStore.isHealthDataAvailable() {
let healthStore = HKHealthStore()
if(healthStore.authorizationStatus(for: HKObjectType.workoutType()) == .sharingAuthorized && healthStore.authorizationStatus(for: HKObjectType.quantityType(forIdentifier: HKQuantityTypeIdentifier.activeEnergyBurned)!) == .sharingAuthorized){
let newWorkout = HKWorkout(activityType: HKWorkoutActivityType.highIntensityIntervalTraining, start: entry.date!, end: Date())
healthStore.save(newWorkout) { success, error in
guard success else {
// Perform proper error handling here.
return
}
// Add detail samples here.
}
}
}
}
}
Thanks :)
I am not sure I understood your case correctly, but if the user is using an Apple Watch and does a workout you can query HealthKit for an HKWorkout object, which holds a totalEnergyBurned attribute.
If you are not querying this HKWorkout object, then I believe you can query for the activeEnergyBurned quantity type using the start and end date-time of the user workout in the predicate.

How to make app automatically recognise current user Firestore document ID when signed in?

When a user is signed up through my form, a document gets created associated with that user. My main goal is to create a global function that can recognize the user that is signed in and get their document ID. I have a function setup for adding documents to a subcollection of the user document which is perfectly setup, the only downfall is that when I'm testing with multiple accounts, I have to manually switch the collection path. Here is what I mean.
#IBAction public func createEventButton(_ sender: UIButton) {
let error = validateFields()
if error != nil {
showError(error!)
} else {
db.collection("school_users/\(stThomas)/events").addDocument(data: ["event_name": nameTextField.text, "event_date": dateTextField.text, "event_cost": costTextField.text, "for_grades": gradesTextField.text]) { (error) in
if error != nil {
self.showError("There was an error trying to add user data to the system.")
} else {
self.dismiss(animated: true, completion: nil)
}
}
}
So as you can see here, I am using string interpolation with the "stThomas" constant I used to store a document ID. I basically want to create a function that will recognize the document ID of the user signed in so I can use my Constants instead of string interpolation and having to manually switch the user collection path each time, which would be eventually impossible during production.
Not to mention, I do have a function to grab the document ID, say for instance an event is clicked, but as a beginner in Swift, I can't seem to connect the dots. I will also show this function for clarification.
func getDocID() {
db.collection("school_users/\(notreDame)/events").getDocuments() { (querySnapshot, error) in
if let error = error {
print("There was an error getting the documents: \(error)")
} else {
self.documentsID = querySnapshot!.documents.map { document in
return DocID(docID: (document.documentID))
}
self.tableView.reloadData()
}
}
}
And in this function you can see my other constant "notreDame" with another stored document ID. If anybody knows a simple way to do this that would be great. And yes, I checked the Firebase documents, thank you for asking.
I've did some extra research and realized that I can use User IDs in collection paths. My problem is now solved. Many more problems to come though.

Swift 3 Completion Handler on Google Places Lookup. Due to delay how do I know when Im "done"?

Sorry, newbie here and Ive read extensively about completion handlers, dispatch queues and groups but I just can't get my head around this.
My app loads an array of Google Place IDs and then wants to query Google to get full details on each place. The problem is, due to async processing the Google Lookup Place returns immediately and the callback happens much further down the line so whats the "proper way" to know when the last bit of data has come in for my inquiries because the function ends almost immedately ?
Code is attached. Thanks in advance.
func testFunc() {
let googlePlaceIDs = ["ChIJ5fTXDP8MK4cRjIKzek6L6NM", "ChIJ9Wd6mGYGK4cRiWd0_bkohHg", "ChIJaeXT08ASK4cRkCGpGgzYpu8", "ChIJkRkS4BapK4cRXCT8-SJxNDI", "ChIJ3wDV_2zX5IkRtd0hg2i1LhE", "ChIJb4wUsI5w44kRnERe7ywQaJA"]
let placesClient = GMSPlacesClient()
for placeID in googlePlaceIDs {
placesClient.lookUpPlaceID(placeID, callback: { (place, error) in
if let error = error {
print("lookup place id query error: \(error.localizedDescription)")
return
}
guard let place = place else {
print("No place details for \(placeID)")
return
}
print("Place Name = \(place.name)")
})
}
print("Done")
}

GeoFire with Swift

I plan to use GeoFire to filter my firebase data based on location. Not sure how to get started with this because I just started developing. I have a pic and a caption etc that I create in one Class with:
#IBAction func shareDidTap(_ sender: Any) {
if let image = image, let caption = textView.text {
let newMedia = Media(type: "image", caption: caption, createdBy: user, image: image)
newMedia.save(completion: { (error) in
if let error = error {
self.alert(title: "Oops!", message: error.localizedDescription, buttonTitle: "OK")
} else {
self.user.share(newMedia: newMedia)
in a separate "User" class (MVC) I save it into Firebase with
func share(newMedia: Media) {
DatabaseReference.users(uid: uid).reference().child("media").childByAutoId().setValue(newMedia.uid)
}
Where do I instantiate the GeoFire reference? Do I have to use Core Location to get my own Lat and Lon? Any help would be appreciated. Thank you.
Adding GeoFire
Install with pods
pod 'GeoFire', :git => 'https://github.com/firebase/geofire-objc.git'
Then import to project import GeoFire
Create a reference to it using
let rootRef = Database.database().reference()
let geoRef = GeoFire(firebaseRef: rootRef.child("user_locations"))
To get the current user location you can use Location manager via cocoa pods: https://github.com/varshylmobile/LocationManager
I am guessing you want the media saved on the database to have a location. You then use GeoFire to save the location using GeoFire.setlocation
Call this when you save your post to the database, GeoFire handles the database structure of adding locations using your post ID.
an example:
geoFire!.setLocation(myLocation, forKey: userID) { (error) in
if (error != nil) {
debugPrint("An error occured: \(error)")
} else {
print("Saved location successfully!")
}
}
You then query the database of locations using CircleQuery
You can give a radius of how far you want to query the database within from a given location (user location)
an example:
let query = geoRef.query(at: userLocation, withRadius: 1000)
query?.observe(.keyEntered, with: { key, location in
guard let key = key else { return }
print("Key: " + key + "entered the search radius.")
})
A really good tutorial that I used was:
https://www.youtube.com/watch?v=wr19iKENC-k&t=600s
Look on their channel and query GeoFire for other videos that might help you further.