IOS Swift CNContactViewController Navigation Bar Not Showing UINavigation Controller - ios

I have been working on this problem for a bit but can't get anything to work.
I have a view controller that effectively stands along in the main story board. Inside that view controller, when a specific action occurs that passes a contact type to the action.
The action opens a new contact view controller for the contact passed, and allows the user to interact with the contact per the CNContactViewController.
Once the user is done with the contact, it will close, because of the didCompleteWith method, but there is no way to exit the contact controller, without actually creating the contact.
//change to new contact screen
let con = CNMutableContact()
con.givenName = familyComponents[0]
con.familyName = familyComponents[1]
let newEmail = CNLabeledValue(label: "Personal", value: objectComponents[2]
as NSString)
con.emailAddresses.append(newEmail)
con.phoneNumbers.append(CNLabeledValue(
label: "Home", value: CNPhoneNumber(stringValue: objectComponents[3])))
let newScreen = CNContactViewController(forUnknownContact: con)
newScreen.message = "Made using app"
newScreen.contactStore = CNContactStore()
newScreen.delegate = self
newScreen.allowsActions = true
let navigationController = UINavigationController(rootViewController:
newScreen)
self.present(navigationController, animated: true, completion: nil)
I have tried everything from navigationItems to navigationItems, it seems to me that the navigation bar is there, because it is possible to change its translucency with this line of code:
navigationController.navigationBar.isTranslucent = true
Methods Below:
func contactViewController(_ viewController: CNContactViewController,
didCompleteWith contact: CNContact?) {
viewController.dismiss(animated: true, completion: nil)
inContact = false
}
func contactViewController(_ shouldPerformDefaultActionForviewController:
CNContactViewController, shouldPerformDefaultActionFor property:
CNContactProperty) -> Bool {
return false
}
Any suggestions would be greatly appreciated, I have been struggling with this problem for too long.
Thanks!
SOLVED:
Got it to work. Turns out that this is a bug in apples framework. To solve this problem I just switched it from Unknown Contact to New Contact, which apparently does not have this bug.
Part of new code:
let newScreen = CNContactViewController(forNewContact: con)
newScreen.delegate = self
let navigationController = UINavigationController(rootViewController: newScreen)
self.present(navigationController, animated: true, completion: nil)
Thanks

can you try with this code
let con = CNMutableContact()
con.givenName = familyComponents[0]
con.familyName = familyComponents[1]
let newEmail = CNLabeledValue(label: "Personal", value: objectComponents[2]
as NSString)
con.emailAddresses.append(newEmail)
con.phoneNumbers.append(CNLabeledValue(
label: "Home", value: CNPhoneNumber(stringValue: objectComponents[3])))
let unkvc = CNContactViewController(forUnknownContact: con)
unkvc.delegate = self
unkvc.allowsEditing = true
unkvc.allowsActions = true
unkvc.title = "Edit Contact"
self.navigationController?.isNavigationBarHidden = false
self.navigationController?.navigationItem.hidesBackButton = true
self.navigationController?.pushViewController(unkvc, animated: false)

Related

How to make a button modify another button functions

I have two UIViewController. In the first one, I have a button that adds some views, one at a time, to the main view. In the second one, I set up a store, so that when I press on a button I unlock some features of my app. Now, I perfectly know (I hope) how to handle the part where I make the VCs comunicate and I trigger some other easy functions, what I don't know is how to make the store button increase the button's functions.
WHAT I NEED:
Right now the button adds a maximum of 10 views (complete version). I want that before the user buys my app, he gets to add a maximum of 3 views and then, when he buys it, the function I already have (the one to add 10 views)starts to work and replaces the other one.
MAIN VIEW CONTROLLER
var messageArray = [UIView] ()
I attached all of my UIView from the storyboard and I appended them to my array in the viewDid load like this: messageArray.append(View1)
#IBAction func addMessageViewButton(_ sender: Any) {
let hiddenViews = messageArray.filter { $0.isHidden }
guard !hiddenViews.isEmpty else {
let sheet = UIAlertController(title: "max reached", message: nil, preferredStyle: .actionSheet)
let ok = UIAlertAction(title: "OK", style: .cancel, handler: nil)
let closeAll = UIAlertAction(title: "Close all", style: .destructive) { (addMessage) in
view1.isHidden = true
view2.isHidden = true
view3.isHidden = true
view4.isHidden = true
view5.isHidden = true
view6.isHidden = true
view7.isHidden = true
view8.isHidden = true
view9.isHidden = true
view10.isHidden = true
}
sheet.addAction(ok)
sheet.addAction(closeAll)
present(sheet, animated: true, completion: nil)
return
}
let randomHiddenView = hiddenViews.randomElement()
randomHiddenView?.isHidden = false
}
SHOP VIEW CONTROLLER
Here I won't post all of the code because it would be too much and of course unnecessary, since the important thing to know here is that there's a button and if the user presses it and he proceeds with the purchase, he will get the function I posted up here working instead of the one that allows him to have just 3 views.
func unlock() {
let appdelegate = UIApplication.shared.delegate
as! AppDelegate
appdelegate.viewController!.functionToHave10Views()
//viewControlled is declared in the app delegate like this ` var viewController: ViewController?`
//I know I don't physically have `functionToHave10Views()`, but I guess I'll turn the code of my button into a function, so just to be clear, I'm referring to that function.
buyButton.isEnabled = false
}
In your main view controller:
var isLocked = true
#IBAction func addMessageViewButton(_ sender: Any) {
if isLocked {
// Do something for when is locked
} else {
// Do something for when is unlocked
}
}
Then in your shop view controller:
func unlock() {
let appdelegate = UIApplication.shared.delegate as! AppDelegate
appdelegate.viewController!.isLocked = false
buyButton.isEnabled = false
}

Getting Black Screen with navigationController?.pushViewController (Swift 3.0)

I am having problems programmatically sending a user from one view controller to another. I am posting the code associated with he flow below. In addition to letting me know what the correct code is (which I would appreciate) I'd also be interested if the logic/design itself seems OK.
I am controlling my UI programmatically. Accordingly, in my app delegate didfinnishlaunchingwithoptions I have
window = UIWindow(frame: UIScreen.main.bounds)
window?.makeKeyAndVisible()
FIRApp.configure()
window?.rootViewController = SigninController()
When the user opens the app, they are redirected to the SigninController.
Then, inside of SigninController, I am handling all of the social authentication stuff against Firebase. I have a listener in my code to confirm that the user is (or is not) authenticated and sends him along:
let provider: [FUIAuthProvider] = [FUIGoogleAuth(), FUIFacebookAuth()]
FUIAuth.defaultAuthUI()?.providers = provider
// listen for changes in the authorization state
_authHandle = FIRAuth.auth()?.addStateDidChangeListener { (auth: FIRAuth, user: FIRUser?) in
// check if there is a current user
if let activeUser = user {
// check if the current app user is the current FIRUser
if self.user != activeUser {
self.user = activeUser
self.signedInStatus(isSignedIn: true)
print("user session is active, redirecting...")
let nextViewController = CustomTabBarController()
self.navigationController?.pushViewController(nextViewController, animated: true)
}
} else {
// user must sign in
self.signedInStatus(isSignedIn: false)
self.loginSession()
}
}
}
In the above code, if the user is confirmed as signed in, then I use the below code to send them along. This is where I am having the problem. Right now I just see a black screen but no error message.
let nextViewController = CustomTabBarController()
self.navigationController?.pushViewController(nextViewController, animated: true)
And here is the code for the CUstomTabBarController class.
class CustomTabBarController : UITabBarController
{
override func viewDidLoad()
{
super.viewDidLoad()
let home = createNavController(imageName: "gen-home", rootViewController: HomeController(collectionViewLayout: UICollectionViewFlowLayout()))
let loc = createNavController(imageName: "loc-map-route", rootViewController: LocController(collectionViewLayout: UICollectionViewFlowLayout()))
let stats = createNavController(imageName: "pre-bar-chart", rootViewController: StatsController(collectionViewLayout: UICollectionViewFlowLayout()))
let profile = createNavController(imageName: "account", rootViewController: ProfileController(collectionViewLayout: UICollectionViewFlowLayout()))
viewControllers = [home, loc, stats, profile]
}
private func createNavController(imageName: String, rootViewController: UIViewController) -> UINavigationController
{
let navController = UINavigationController(rootViewController: rootViewController)
navController.tabBarItem.image = UIImage(named: imageName)
return navController
}
}
I am sure I am overlooking something silly, but sometimes it takes another pair of eyes to point it out.
Thanks in advance.
Here
self.navigationController?.pushViewController(nextViewController, animated: true)
there is no navigationController.
In your AppDelegate you need to do this:
let rootViewController = SigninController()
let navController: UINavigationController = UINavigationController(rootViewController: rootViewController)
FIRApp.configure()
self.window?.rootViewController = navController
self.window?.makeKeyAndVisible()
It's better to assign rootViewController to the window before making it visible. Otherwise there may be screen blinks.

return UIViewController from a class function

In my Restaurant model I have a function, that returns UINavigationController, I've implemented it to make my code more readable. But I am curious if it is ok to do it this way, or should I make a function of UIViewController, that takes Restaurant as a parameter.
func reserveTable(timeIndex: Int) -> UINavigationController {
let storyBoard = UIStoryboard(name: "Reservations", bundle: nil)
let targetVC = storyBoard.instantiateViewController(withIdentifier: "bookingNC") as! UINavigationController
let destinationVC = targetVC.topViewController as! BookingViewController
destinationVC.availabeleDates = self.schedule
destinationVC.timeRange = self.avaliableTimes
destinationVC.restaurantId = self.id
destinationVC.requestedTimeIndex = timeIndex
destinationVC.reservationType = "Бронирование"
return targetVC
}
I would do this differently, your model is supposed to handle data, not Views.
There are many ways in which you could do this, personally I would have a property on the booking controller for the reservation. Then you could just do something like:
let vc = BookingViewController()
vc.reservation = reservation
self.present(vc, animated: true)
wherever you needed to present the booking controller. Ensuring you have a reservation first.
In your init/viewDidLoad method of the BookingViewController you can do alot of the work above...
override func viewDidLoad() {
super.viewDidLoad()
if let reservation = self.reservation {
self.availabeleDates = reservation.schedule
self.timeRange = reservation.avaliableTimes
self.restaurantId = reservation.id
self.requestedTimeIndex = timeIndex
self.reservationType = "Бронирование"
}
}

CNContactViewController setEditing true before appear

I have a task to show the contact editing screen at once during his appearance (such as WhatsApp), I show him the following way.
#objc private func presentContactEditController() {
guard var contact = contactModel.contact else { return }
if !contact.areKeysAvailable([CNContactViewController.descriptorForRequiredKeys()]) {
do {
let contactStore = CNContactStore()
contact = try contactStore.unifiedContact(withIdentifier: contact.identifier, keysToFetch: [CNContactViewController.descriptorForRequiredKeys()])
} catch {
debugPrint("presentContactEditController error", error.localizedDescription)
}
}
let cnContactViewController = CNContactViewController(for: contact)
cnContactViewController.delegate = self
cnContactViewController.setEditing(true, animated: false)
let contactNaviController = UINavigationController(rootViewController: cnContactViewController)
present(contactNaviController, animated: true, completion: nil)
}
But there is a screen with information about this contact. So I tried to do it through the heir of CNContactViewController, different methods ViewController life cycle, but it works only in viewDidAppear method, but it will be visible to the user. How can I solve this problem? Thank you.
just change let cnContactViewController = CNContactViewController(for: contact)
to
let cvc = CNContactViewController(forNewContact: contact)
it will work for you
I came to the conclusion that that WhatsApp create a custom screen for this purpose. Just I saw the same screen in Telegram only with a modified design.

Present EditView of Contacts in ContactsUI

I have a TableView that present a contact.
When I click the cell i would like to do straight to Editable view, instead of going to the CNContactViewController and press "edit Button".
Now i have the following :
firstview
secondview
I would like to skip the second step. Is that possible?
the code I'm using is the same from apple's:
let contacts = try contactStore.unifiedContactWithIdentifier
(contactIdentifier!, keysToFetch: toFetch)
let controller = CNContactViewController(forContact: contacts)
controller.contactStore = contactStore
controller.delegate = self
controller.editing = true
navigationController?
.pushViewController(controller, animated: true)
print(controller.editButtonItem())
} catch {
print(error)
}
EDIT: More or less, to illustrate, what Im trying to do, is the same as WhatsApp has in their App!, thanks!!
Have you tried this approach ?
let toFetch = [CNContactViewController.descriptorForRequiredKeys()]
let contacts = try contactStore.unifiedContactWithIdentifier
(contactIdentifier!, keysToFetch: toFetch)
let contactsViewController = CNContactViewController(forNewContact: contacts)
contactsViewController.delegate = self
contactsViewController.title = "Edit contact"
contactsViewController.contactStore = contactStore
self.navigationController?.pushViewController(contactsViewController, animated: true)

Resources