iOS14 CNContactViewController not showing delete button issue - ios

When I press Edit from contact card, my CNContactViewController is not showing the delete option in the bottom of the screen.
NB: the button remains shown for iOS 13.

import Foundation
import ContactsUI
import SwiftUI
struct CNContactViewControllerRepresentable: UIViewControllerRepresentable {
typealias UIViewControllerType = CNContactViewController
var contact: Binding<CNContact>
var presentingEditContact: Binding<Bool>
func makeCoordinator() -> CNContactViewControllerRepresentable.Coordinator {
Coordinator(self)
}
func makeUIViewController(context: UIViewControllerRepresentableContext<CNContactViewControllerRepresentable>) -> CNContactViewControllerRepresentable.UIViewControllerType {
let controller = CNContactViewController(forNewContact: contact.wrappedValue)
controller.delegate = context.coordinator
return controller
}
func updateUIViewController(_ uiViewController: CNContactViewControllerRepresentable.UIViewControllerType, context: UIViewControllerRepresentableContext<CNContactViewControllerRepresentable>) {
//
}
// Nested coordinator class, the prefered way stated in SwiftUI documentation.
class Coordinator: NSObject, CNContactViewControllerDelegate {
var parent: CNContactViewControllerRepresentable
init(_ contactDetail: CNContactViewControllerRepresentable) {
self.parent = contactDetail
}
func contactViewController(_ viewController: CNContactViewController, didCompleteWith contact: CNContact?) {
parent.contact.wrappedValue = contact ?? parent.contact.wrappedValue
parent.presentingEditContact.wrappedValue = false
}
func contactViewController(_ viewController: CNContactViewController, shouldPerformDefaultActionFor property: CNContactProperty) -> Bool {
return true
}
}
}

.sheet(isPresented: $viewModel.presentingEditContact) {
NavigationView {
if #available(iOS 14, *) {
return AnyView(CNContactViewControllerRepresentable(contact: self.$viewModel.contact, presentingEditContact: $viewModel.presentingEditContact)
.navigationBarTitle("Edit Contact")
.edgesIgnoringSafeArea(.top))
} else {
return AnyView(CNContactViewControllerRepresentable(contact: self.$viewModel.contact, presentingEditContact: $viewModel.presentingEditContact)
.edgesIgnoringSafeArea(.top))
}
}
}

Related

Use YPImagePikcer in swiftUI

I'm trying to use YPImagePicker in SwiftUI how can I do it??
https://github.com/Yummypets/YPImagePicker
how can I call this function in SwiftUI?
This can be done using UIViewControllerRepresentable like so...
struct PhotoPicker: UIViewControllerRepresentable {
func makeUIViewController(context: Context) -> some UIViewController {
var config = YPImagePickerConfiguration()
YPImagePickerConfiguration.shared = config
let picker = YPImagePicker(configuration: config)
picker.delegate = context.coordinator
picker.didFinishPicking { items, cancelled in
if !cancelled {
let images: [UIImage] = items.compactMap { item in
if case .photo(let photo) = item {
return photo.image
} else {
return nil
}
}
finishedPicking(images)
}
dismiss()
}
return picker
}
func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator: NSObject, UINavigationControllerDelegate {
let parent: PhotoPicker
init(_ parent: PhotoPicker) {
self.parent = parent
}
}
}
and then call it like this...
Text("SomeView")
.sheet(isPresented: $showPhotoPicker) {
PhotoPicker()
}

SwiftUI UIViewRepresentable with argument passed and delegate function

I am implementing a UIViewController with a ViewModel as an argument passed to the UIViewController, but I can't seem to make the delegate functions to work, what is the correct way of doing this?
CartView.swift
struct PaymentWrapper: UIViewControllerRepresentable {
typealias UIViewControllerType = CustomUIPaymentViewController
#ObservedObject var viewModel: CartViewModel
var vc: CustomUIPaymentViewController?
var foo: (String) -> Void
public init(viewModel: CartViewModel) {
self.viewModel = viewModel
self.vc = CustomUIPaymentViewController.init(token: self.viewModel.mtToken)
}
func makeUIViewController(context: Context) -> CustomUIPaymentViewController {
return vc!
}
func updateUIViewController(_ uiViewController: CustomUIPaymentViewController, context: Context) {
// code
}
func makeCoordinator() -> Coordinator {
Coordinator(vc: vc!, foo: foo)
}
class Coordinator: NSObject, CustomUIPaymentViewControllerDelegate, CustomUINavigationControllerDelegate {
var foo: (String) -> Void
init(vc: CustomUIPaymentViewController, foo: #escaping (String) -> Void) {
self.foo = foo
super.init()
vc.delegate = self
}
func paymentViewController(_ viewController: CustomUIPaymentViewController!, paymentFailed error: Error!) {
foo("FAILED")
}
func paymentViewController(_ viewController: CustomUIPaymentViewController!, paymentPending result: TransactionResult!) {
foo("PENDING")
}
func paymentViewController(_ viewController: CustomUIPaymentViewController!, paymentSuccess result: TransactionResult!) {
foo("SUCCESS")
}
func paymentViewController_paymentCanceled(_ viewController: CustomUIPaymentViewController!) {
foo("CANCEL")
}
//This delegate methods is added on ios sdk v1.16.4 to handle the new3ds flow
func paymentViewController(_ viewController: CustomUIPaymentViewController!, paymentDeny result: TransactionResult!) {
}
}
}
struct CartView: View {
#ObservedObject var viewModel = CartViewModel()
var body: some View {
VStack {
Header(title: "Cart", back: false)
}
.sheet(isPresented: $viewModel.showPayment) {
PaymentWrapper(viewModel: self.viewModel) { data in
print(data)
// This returns error "Extra trailing closure passed in call"
}
}
}
}
How do I get the delegate to work? what am I doing wrong? Thank you in advance.

How do I get information about the phone version and phone model? SwiftUI

I have a code that allows me to send an email message from the application. How to get phone model and IOS version data .. I am a new user at SwiftUi, would appreciate any help.
See the example in the screenshot
Example in the picture
Here is the code I have
import Foundation
import SwiftUI
import MessageUI
struct MailView: View {
#State private var showingMail = false
var body: some View {
VStack {
Button("Open Mail") {
self.showingMail.toggle()
}
}
.sheet(isPresented: $showingMail) {
MailComposeViewController(toRecipients: [""], mailBody: "Here is mail body") {
// Did finish action
}
}
}
}
struct MailComposeViewController: UIViewControllerRepresentable {
var toRecipients: [String]
var mailBody: String
var didFinish: ()->()
func makeCoordinator() -> Coordinator {
return Coordinator(self)
}
func makeUIViewController(context: UIViewControllerRepresentableContext<MailComposeViewController>) -> MFMailComposeViewController {
let mail = MFMailComposeViewController()
mail.mailComposeDelegate = context.coordinator
mail.setToRecipients(self.toRecipients)
mail.setMessageBody(self.mailBody, isHTML: true)
return mail
}
final class Coordinator: NSObject, MFMailComposeViewControllerDelegate {
var parent: MailComposeViewController
init(_ mailController: MailComposeViewController) {
self.parent = mailController
}
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
parent.didFinish()
controller.dismiss(animated: true)
}
}
func updateUIViewController(_ uiViewController: MFMailComposeViewController, context: UIViewControllerRepresentableContext<MailComposeViewController>) {
}
}
You can do that like this
struct ContentView: View {
var systemVersion = UIDevice.current.systemVersion
var device = UIDevice.current.name
var body: some View {
VStack {
Text("iOS Version: \(systemVersion)")
Text("Device: \(device)")
}
}
}
https://developer.apple.com/documentation/uikit/uidevice

Presenting UIDocumentInteractionController with UIViewControllerRepresentable in SwiftUI

I'm creating a new iOS app using SwiftUI where ever possible. However, I want to be able to generate a PDF with some data.
In a similar project without swiftUI I can do this
let docController = UIDocumentInteractionController.init(url: "PATH_TO_FILE")
docController.delegate = self
self.dismiss(animated: false, completion: {
docController.presentPreview(animated: true)
})
and as long as somewhere else in the view controller I have this:
func documentInteractionControllerViewControllerForPreview(_ controller: UIDocumentInteractionController) -> UIViewController {
return self
}
I'm good to go.
What I can't work out is how to apply this to a UIViewControllerRepresentable and have it working in SwiftUI. Should my UIViewControllerRepresentable be aiming to be a UIViewController? How do I then set the delegate and presentPreview? Will this overlay any view and display full screen over my SwiftUI app as it does for my standard iOS app?
Thanks
Here is possible approach to integrate UIDocumentInteractionController for usage from SwiftUI view.
Full-module code. Tested with Xcode 11.2 / iOS 13.2
import SwiftUI
import UIKit
struct DocumentPreview: UIViewControllerRepresentable {
private var isActive: Binding<Bool>
private let viewController = UIViewController()
private let docController: UIDocumentInteractionController
init(_ isActive: Binding<Bool>, url: URL) {
self.isActive = isActive
self.docController = UIDocumentInteractionController(url: url)
}
func makeUIViewController(context: UIViewControllerRepresentableContext<DocumentPreview>) -> UIViewController {
return viewController
}
func updateUIViewController(_ uiViewController: UIViewController, context: UIViewControllerRepresentableContext<DocumentPreview>) {
if self.isActive.wrappedValue && docController.delegate == nil { // to not show twice
docController.delegate = context.coordinator
self.docController.presentPreview(animated: true)
}
}
func makeCoordinator() -> Coordintor {
return Coordintor(owner: self)
}
final class Coordintor: NSObject, UIDocumentInteractionControllerDelegate { // works as delegate
let owner: DocumentPreview
init(owner: DocumentPreview) {
self.owner = owner
}
func documentInteractionControllerViewControllerForPreview(_ controller: UIDocumentInteractionController) -> UIViewController {
return owner.viewController
}
func documentInteractionControllerDidEndPreview(_ controller: UIDocumentInteractionController) {
controller.delegate = nil // done, so unlink self
owner.isActive.wrappedValue = false // notify external about done
}
}
}
// Demo of possible usage
struct DemoPDFPreview: View {
#State private var showPreview = false // state activating preview
var body: some View {
VStack {
Button("Show Preview") { self.showPreview = true }
.background(DocumentPreview($showPreview, // no matter where it is, because no content
url: Bundle.main.url(forResource: "example", withExtension: "pdf")!))
}
}
}
struct DemoPDFPreview_Previews: PreviewProvider {
static var previews: some View {
DemoPDFPreview()
}
}
I ended up doing something like the following as I wasn't able to get this working reliably with UIViewControllerRepresentable and the above answer. You might need to edit / extend this for your usecase.
class DocumentController: NSObject, ObservableObject, UIDocumentInteractionControllerDelegate {
let controller = UIDocumentInteractionController()
func presentDocument(url: URL) {
controller.delegate = self
controller.url = url
controller.presentPreview(animated: true)
}
func documentInteractionControllerViewControllerForPreview(_: UIDocumentInteractionController) -> UIViewController {
return UIApplication.shared.windows.first!.rootViewController!
}
}
Usage:
struct DocumentView: View {
#StateObject var documentController = DocumentController()
var body: some View {
Button(action: {
documentController.presentDocument(url: ...)
}, label: {
Text("Show Doc")
})
}
}
Using QLPreviewController
I know the question is about UIDocumentInteractionController, but if you want to present a PDF file (for example), you can use a QLPreviewController.
Local file
Presenting a local file:
import SwiftUI
struct DocView: View {
#State private var buttonPressed: Bool = false
var body: some View {
Button {
buttonPressed = true
} label: {
Text("Show PDF file")
}
.sheet(isPresented: $buttonPressed) {
let localURL = Bundle.main.url(forResource: "Example", withExtension: "pdf")!
PreviewController(url: localURL)
}
}
}
Remote file
Please see this gist if you need to present a remote file.
PreviewController
The UIViewControllerRepresentable for QLPreviewController.
import QuickLook
import SwiftUI
struct PreviewController: UIViewControllerRepresentable {
#Environment(\.dismiss) private var dismiss
let url: URL
func makeUIViewController(context: Context) -> UINavigationController {
let controller = QLPreviewController()
controller.dataSource = context.coordinator
controller.navigationItem.leftBarButtonItem = UIBarButtonItem(
barButtonSystemItem: .done, target: context.coordinator,
action: #selector(context.coordinator.dismiss)
)
let navigationController = UINavigationController(rootViewController: controller)
return navigationController
}
func updateUIViewController(_ uiViewController: UINavigationController, context: Context) {}
func makeCoordinator() -> Coordinator {
return Coordinator(parent: self)
}
class Coordinator: QLPreviewControllerDataSource {
let parent: PreviewController
init(parent: PreviewController) {
self.parent = parent
}
func numberOfPreviewItems(in controller: QLPreviewController) -> Int {
return 1
}
func previewController(
_ controller: QLPreviewController,
previewItemAt index: Int
) -> QLPreviewItem {
return parent.url as NSURL
}
#objc func dismiss() {
parent.dismiss()
}
}
}

FirebaseUI and SwiftUI LoginG

I´m trying to implement the firebaseUI login in an iOS app using swiftUI.
I´m able to use the main login view, but i can not control the flow after the user was loged on.
This is the code of my "login controller"
import SwiftUI
import FirebaseUI
struct CustomLogin: UIViewControllerRepresentable {
func makeUIViewController(context: Context) -> UIViewController {
let authUI = FUIAuth.defaultAuthUI()
let providers: [FUIAuthProvider] = [
FUIEmailAuth(),
FUIFacebookAuth()
// FUIPhoneAuth(authUI:FUIAuth.defaultAuthUI()),
]
authUI?.providers = providers
let authViewController = authUI?.authViewController()
// let controller = UIViewController()
// authUI!.delegate = self
return authViewController!
}
func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
}
}
struct CustomLogin_Previews: PreviewProvider {
static var previews: some View {
CustomLogin()
}
}
I can show the login flow by add CustomLogin())to my content view.
how can I manage the call backs after the user has logged on?
The user was created in firebase, but the view don´t update.
if someone has implemented a firebaseUI login with SwiftUI I appreciated it.
Thanks
I was able to implement something that worked based off of your code and some Apple tutorials. Basically, you need to add a coordinator to your UIViewControllerRepresentable. You can add your delegate to the coordinator.
Here's my scratch code that works:
import SwiftUI
import FirebaseUI
import Firebase
public var screenWidth: CGFloat {
return UIScreen.main.bounds.width
}
public var screenHeight: CGFloat {
return UIScreen.main.bounds.height
}
struct LoginView : View {
#State private var viewState = CGSize(width: 0, height: screenHeight)
#State private var MainviewState = CGSize.zero
var body : some View {
ZStack {
CustomLoginViewController { (error) in
if error == nil {
self.status()
}
}.offset(y: self.MainviewState.height).animation(.spring())
MainView().environmentObject(DataStore()).offset(y: self.viewState.height).animation(.spring())
}
}
func status() {
self.viewState = CGSize(width: 0, height: 0)
self.MainviewState = CGSize(width: 0, height: screenHeight)
}
}
struct LoginView_Previews : PreviewProvider {
static var previews : some View {
LoginView()
}
}
struct CustomLoginViewController : UIViewControllerRepresentable {
var dismiss : (_ error : Error? ) -> Void
func makeCoordinator() -> CustomLoginViewController.Coordinator {
Coordinator(self)
}
func makeUIViewController(context: Context) -> UIViewController
{
let authUI = FUIAuth.defaultAuthUI()
let providers : [FUIAuthProvider] = [
FUIEmailAuth(),
FUIGoogleAuth(),
FUIOAuth.appleAuthProvider()
]
authUI?.providers = providers
authUI?.delegate = context.coordinator
let authViewController = authUI?.authViewController()
return authViewController!
}
func updateUIViewController(_ uiViewController: UIViewController, context: UIViewControllerRepresentableContext<CustomLoginViewController>)
{
}
//coordinator
class Coordinator : NSObject, FUIAuthDelegate {
var parent : CustomLoginViewController
init(_ customLoginViewController : CustomLoginViewController) {
self.parent = customLoginViewController
}
// MARK: FUIAuthDelegate
func authUI(_ authUI: FUIAuth, didSignInWith authDataResult: AuthDataResult?, error: Error?)
{
if let error = error {
parent.dismiss(error)
}
else {
parent.dismiss(nil)
}
}
func authUI(_ authUI: FUIAuth, didFinish operation: FUIAccountSettingsOperationType, error: Error?)
{
}
}
}

Resources