Changing View Controller After Google Place Picker - swift

Does anyone know how to go to a different view controller after selecting a place in Google Place Picker other than the one that called the place picker?

according to google place picker documentation
#IBAction func pickPlace(_ sender: UIButton) {
let config = GMSPlacePickerConfig(viewport: nil)
let placePicker = GMSPlacePicker(config: config)
placePicker.pickPlace(callback: { (place, error) -> Void in
if let error = error {
print("Pick Place error: \(error.localizedDescription)")
return
}
if let place = place {
DispatchQueue.main.async {
//code to push or present a viewController
}
} else {
print("No place selected")
return
}
print("Place name \(place.name)")
print("Place address \(place.formattedAddress)")
print("Place attributions \(place.attributions)")
})
}
Hope this helps

Related

How to make the page transition after clicking the button [duplicate]

This question already has answers here:
Passing data between view controllers
(45 answers)
Closed 1 year ago.
I'm developing an app to log book that children have read. So I would like to know how to make the page transition back to the menu page after clicking the "save" button. I also want to make the alert that shows "Data has been saved!". Below are my codes.
#IBOutlet weak var newBookSaveButton: UIButton!
#IBAction func newBookTapped(_ sender: Any) {
guard let uid = Auth.auth().currentUser?.uid,
let data = bookData() else {
return
}
db.collection("new reading").document(uid).setData(data)
}
func bookData() -> [String: Any]? {
guard let title = bookTitleTextField.text,
let author = bookAuthorTextField.text,
let summary = bookSummaryTextField.text else {
return nil
}
let data: [String: Any] = [
"bookTitle": title,
"bookAuthor": author,
"bookSummary": summary
]
return data
self.transitionToMenu()
}
func transitionToMenu() {
let MenuViewController = storyboard?.instantiateViewController(withIdentifier: Constants.Storyboard.MenuViewController) as? MenuViewController
view.window?.rootViewController=MenuViewController
view.window?.makeKeyAndVisible()
}
}
With this code, I still unable to transition back to the Menu page. Your help are very much appreciated.
You can use this function:
func transitionToMenu() {
let alert = UIAlertController(title: nil, message: "Data has been saved!", preferredStyle: .alert)
alert.view.alpha = 0.5
alert.view.layer.cornerRadius = 15
self.present(alert, animated: true)
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 2) {
alert.dismiss(animated: true)
if let navController = self.navigationController {
navController.popViewController(animated: true)
} else {
self.dismiss(animated: true, completion: {})
}
}
}

Problems with saving an image from UIDocumentPickerViewController / .stopAccessingSecurityScopedResource()

I have a viewcontroller that presents my custom ImagePicker class. One of the presented options is to select an image from 'Files', using UIDocumentPickerViewController. Picking an image works fine, but i want to close the security resources conform the recommendations.
ProjectimagePicker {
(...)
let documentsPicker = UIDocumentPickerViewController(documentTypes: ["public.image", "public.jpeg", "public.png"], in: .open)
documentsPicker.delegate = self
documentsPicker.allowsMultipleSelection = false
documentsPicker.modalPresentationStyle = .fullScreen
self.presentationController?.present(documentsPicker, animated: true, completion: nil)
}
//MARK: - Ext. Delegate DocumentPicker
extension ProjectImagePicker: UIDocumentPickerDelegate {
public func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
guard controller.documentPickerMode == .open, let url = urls.first, url.startAccessingSecurityScopedResource() else { return }
defer {
DispatchQueue.main.async {
url.stopAccessingSecurityScopedResource()
}
}
guard let image = UIImage(contentsOfFile: url.path) else { return }
self.delegate?.didSelect(image: image)
controller.dismiss(animated: true)
}
public func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) {
controller.dismiss(animated: true)
}
}
And in the viewController that called the picker class:
//MARK: - Delegate ProjectImagePicker
extension ProjectDetailsViewController: ProjectImagePickerDelegate {
func didSelect(image: UIImage?) {
if let image = image {
selectedImage = image
projectImageView.image = image
}
}
}
Part of the problem I circumvent by wrapping a dispatch call around stopAccessingSecurityScopedResource(). The image gets send back (delegate) and presented
in the viewController. But when I eventually save (write to documents directory) my project and that image (selectedImage), I get the security error
2020-05-08 13:54:04.429936+0200 ProjectS[3482:1339708] [ProjectS] createDataWithMappedFile:1524: 'open' failed '/private/var/mobile/Library/Mobile Documents/com~apple~CloudDocs/10.JPEG' error = 1 (Operation not permitted)
So, apparently the image is still referencing the URL from the Documents picker. I could try and save the image temporarily in the didPickDocumentsAt method, but that seems ugly. Or I can omit calling stopAccessingSecurityScopedResource() all together, but that may cause problems?
Any ideas on how to handle this the best possible way ?
If I update my code for didPickDocumentsAt in the way that I make a copy of the image, all works as intended
//MARK: - Ext. Delegate DocumentPicker
extension ProjectImagePicker: UIDocumentPickerDelegate {
public func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
guard controller.documentPickerMode == .open, let url = urls.first, url.startAccessingSecurityScopedResource() else { return }
defer {
DispatchQueue.main.async {
url.stopAccessingSecurityScopedResource()
}
}
//Need to make a new image with the jpeg data to be able to close the security resources!
guard let image = UIImage(contentsOfFile: url.path), let imageCopy = UIImage(data: image.jpegData(compressionQuality: 1.0)!) else { return }
self.delegate?.didSelect(image: imageCopy)
controller.dismiss(animated: true)
}
Good solution, or better ideas?

FirebaseUI not showing any input fields or buttons

I want to implement FirebaseUIin my project, but the login page is not showing any input fields or buttons:
Code for showing FUIAuth:
#IBAction func logInButtonTapped(_ sender: Any) {
let authUI = FUIAuth.defaultAuthUI()
guard authUI != nil else {
//Log error
return
}
authUI?.delegate = self
authUI?.providers = [FUIEmailAuth]()
let authViewController = authUI!.authViewController()
present(authViewController, animated: true, completion: nil)
}
}
extension LogInViewController: FUIAuthDelegate {
func authUI(_ authUI: FUIAuth, didSignInWith authDataResult: AuthDataResult?, error: Error?) {
if error != nil {
return
}
performSegue(withIdentifier: "ToHomeVCSegue", sender: self)
}
}
I have tried lots of different options in the podfile:
pod 'Firebase/Core'
pod 'Firebase/Auth'
pod 'Firebase/Database'
pod 'FirebaseUI'
pod 'FirebaseUI/Email'
I just ran into this same issue and it seems that all of the examples out there are missing some aspect of the steps required to make the providers appear. The first answer was correct but didnt give examples. In the code below I am just suing email and Google auth. This code is embedded in a login button pressed event.
let authUI = FUIAuth.defaultAuthUI()
guard authUI != nil else {
print("authUI error")
return
}
authUI?.delegate = self
let providers: [FUIAuthProvider] = [
FUIEmailAuth(),
FUIGoogleAuth()
]
authUI?.providers = providers
let authViewController = authUI!.authViewController()
present(authViewController, animated: true)
Hopefully it's not too late. But the problem looks to be with this line of code here
authUI?.providers = [FUIEmailAuth]()
The '.providers' property requires an array of type FUIAuthProviders.
Your code is basically trying to pass an array of type FUIEmailAuth, which the '.providers' property doesn't understand.
Here's an example of initializing an array of type FUIAuthProviders
let authProviders: [FUIAuthProviders] = []

Removing Data on Maps with different view controllers

I am really struggling on an issue that I think is rather interesting and quite difficult. My application lets the user create annotation locations within a Mapview. They also have the option to edit and delete these locations in another modal view controller.
The issue I am facing is that when the user presses delete, which removes the location from firebase, the annotation is still displayed upon the map. I cannot reload my annotation data within the view did appear as this does not suit my application. I cant have my annotations being reloaded every time I bring up the Mapview.
I need to figure out a way to implement an annotation reload when the delete button is pressed. However, as this happens within my delete view controller (which does not contain the mapView) I cannot use the reload function. Is there a way to connect view controllers so that I can apply the reload function when delete is pressed?
Updated Code **
This is my map view controller:
class ViewController: UIViewController, SideBarDelegate, MGLMapViewDelegate, DeleteVCDelegate {
let EditSaveSpotController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "EditVC") as! EditSaveSpotViewController
override func viewDidLoad() {
super.viewDidLoad()
EditSaveSpotController.delegate = self
}
func wholeRefresh() {
let uid = FIRAuth.auth()!.currentUser!.uid
let userLocationsRef = FIRDatabase.database().reference(withPath: "users/\(uid)/personalLocations")
userLocationsRef.observe(.value, with: { snapshot in
for item in snapshot.children {
guard let snapshot = item as? FIRDataSnapshot else { continue }
let newSkatepark = Skatepark(snapshot: snapshot)
self.skateparks.append(newSkatepark)
self.addAnnotation(park: newSkatepark)
}
})
if let annotations = mapView.annotations {
mapView.removeAnnotations(annotations)
}
for item in skateparks {
self.addAnnotation(park: item)
}
}
This is my delete view controller:
import UIKit
import Firebase
protocol DeleteVCDelegate {
func wholeRefresh()
}
class EditSaveSpotViewController: UIViewController {
var delegate: DeleteVCDelegate?
#IBAction func deleteSkateSpot(_ sender: Any) {
ref = FIRDatabase.database().reference(withPath: "users").child(Api.User.CURRENT_USER!.uid).child("personalLocations/\(parkId!)")
ref.observe(.value, with: { (snapshot) in
self.ref.setValue(nil)
self.dismiss(animated: true, completion: nil)
self.delegate?.wholeRefresh()
// self.delegate?.mainRefresh()
print("CheckWorking")
})
}
}
This is very high level and I did not have a chance to verify but it should be enough to get you going:
Modal Delete View
protocol DeleteVCDelegate {
func mainRefresh()
}
class DeleteVC: UIViewController {
var delegate: DeleteVCDelegate?
//your delete code
#IBAction func deleteSkateSpot(_ sender: Any) {
ref = FIRDatabase.database().reference(withPath: "users").child(Api.User.CURRENT_USER!.uid).child("personalLocations/\(parkId!)")
ref.observe(.value, with: { (snapshot) in
self.ref.setValue(nil)
//call to delegate
self.delegate?.mainRefresh()
})
}
}
MapView Class (implement DeleteVCDelegate)
class mapVC: MKMapViewDelegate, DeleteVCDelegate{
//when you present your DeleteVC set its delegate to the map view
let vc=(self.storyboard?.instantiateViewController(withIdentifier: "deleteVC"))! as! DeleteVC
//set the delegate
vc.delegate=self
//present deleteVC
self.present(vc, animated: true, completion:nil)
//implement delegate method of DeleteVC
func mainRefresh(){
//dismiss modal
self.dismiss(animated: true) {
//update view
self.loadLocations()
self.annotationRefresh()
}
}
}

Swift, core data, add item from modally presented view

I am updating an app into Swift and have a tableView to which items can be added from a modally presented view. This works fine when the Save button is pressed, but when cancel is pressed the table view is presented with a blank line at the top, showing that an empty item was added. What am I missing?
The AddViewController protocol is:
protocol NewGaugeDelegate {
func didFinish(viewController:AddGaugeViewController, didSave:Bool)
}
and the didSave function is:
extension AddGaugeViewController {
#IBAction func cancelButtonWasTapped(_ sender: AnyObject) {
delegate?.didFinish(viewController: self, didSave: false)
}
#IBAction func saveButtonWasTapped(_ sender: AnyObject) {
addGauge()
delegate?.didFinish(viewController: self, didSave: true)
}
}
in the tableView controller, the protocol is accessed like this:
extension GaugeTableViewController: NewGaugeDelegate {
func didFinish(viewController: AddGaugeViewController, didSave: Bool) {
guard didSave,
let context = viewController.context,
context.hasChanges else {
dismiss(animated: true)
return
}
context.perform {
do {
try context.save()
} catch let error as NSError {
fatalError("Error: \(error.localizedDescription)")
}
self.coreDataStack.saveContext()
}
dismiss(animated: true)
}
}
Suggestions as to why the cancel function is not working properly would be appreciated.