session-ios/Signal/src/ViewControllers/ContactShareViewHelper.swift

290 lines
10 KiB
Swift

//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
import Foundation
import SignalServiceKit
import ContactsUI
import MessageUI
@objc
public protocol ContactShareViewHelperDelegate: class {
func didCreateOrEditContact()
}
@objc
public class ContactShareViewHelper: NSObject, CNContactViewControllerDelegate {
weak var delegate: ContactShareViewHelperDelegate?
let contactShare: ContactShareViewModel
let contactsManager: OWSContactsManager
weak var fromViewController: UIViewController?
public required init(contactShare: ContactShareViewModel, contactsManager: OWSContactsManager, fromViewController: UIViewController, delegate: ContactShareViewHelperDelegate) {
SwiftAssertIsOnMainThread(#function)
self.contactShare = contactShare
self.contactsManager = contactsManager
self.fromViewController = fromViewController
self.delegate = delegate
super.init()
}
// MARK: Actions
@objc
public func sendMessageToContact() {
Logger.info("\(logTag) \(#function)")
presentThreadAndPeform(action: .compose)
}
@objc
public func audioCallToContact() {
Logger.info("\(logTag) \(#function)")
presentThreadAndPeform(action: .audioCall)
}
@objc
public func videoCallToContact() {
Logger.info("\(logTag) \(#function)")
presentThreadAndPeform(action: .videoCall)
}
private func presentThreadAndPeform(action: ConversationViewAction) {
// TODO: We're taking the first Signal account id. We might
// want to let the user select if there's more than one.
let phoneNumbers = contactShare.systemContactsWithSignalAccountPhoneNumbers(contactsManager)
guard phoneNumbers.count > 0 else {
owsFail("\(logTag) missing Signal recipient id.")
return
}
guard phoneNumbers.count > 1 else {
let recipientId = phoneNumbers.first!
SignalApp.shared().presentConversation(forRecipientId: recipientId, action: action)
return
}
showPhoneNumberPicker(phoneNumbers: phoneNumbers, completion: { (recipientId) in
SignalApp.shared().presentConversation(forRecipientId: recipientId, action: action)
})
}
@objc
public func inviteContact() {
Logger.info("\(logTag) \(#function)")
guard let fromViewController = fromViewController else {
owsFail("\(logTag) missing fromViewController")
return
}
guard MFMessageComposeViewController.canSendText() else {
Logger.info("\(logTag) Device cannot send text")
OWSAlerts.showErrorAlert(message: NSLocalizedString("UNSUPPORTED_FEATURE_ERROR", comment: ""))
return
}
let phoneNumbers = contactShare.e164PhoneNumbers()
guard phoneNumbers.count > 0 else {
owsFail("\(logTag) no phone numbers.")
return
}
let inviteFlow =
InviteFlow(presentingViewController: fromViewController, contactsManager: contactsManager)
inviteFlow.sendSMSTo(phoneNumbers: phoneNumbers)
}
func addToContacts() {
Logger.info("\(logTag) \(#function)")
guard let fromViewController = fromViewController else {
owsFail("\(logTag) missing fromViewController")
return
}
let actionSheet = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
actionSheet.addAction(UIAlertAction(title: NSLocalizedString("CONVERSATION_SETTINGS_NEW_CONTACT",
comment: "Label for 'new contact' button in conversation settings view."),
style: .default) { _ in
self.didPressCreateNewContact()
})
actionSheet.addAction(UIAlertAction(title: NSLocalizedString("CONVERSATION_SETTINGS_ADD_TO_EXISTING_CONTACT",
comment: "Label for 'new contact' button in conversation settings view."),
style: .default) { _ in
self.didPressAddToExistingContact()
})
actionSheet.addAction(OWSAlerts.cancelAction)
fromViewController.present(actionSheet, animated: true)
}
private func showPhoneNumberPicker(phoneNumbers: [String], completion :@escaping ((String) -> Void)) {
guard let fromViewController = fromViewController else {
owsFail("\(logTag) missing fromViewController")
return
}
let actionSheet = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
for phoneNumber in phoneNumbers {
actionSheet.addAction(UIAlertAction(title: PhoneNumber.bestEffortLocalizedPhoneNumber(withE164: phoneNumber),
style: .default) { _ in
completion(phoneNumber)
})
}
actionSheet.addAction(OWSAlerts.cancelAction)
fromViewController.present(actionSheet, animated: true)
}
func didPressCreateNewContact() {
Logger.info("\(logTag) \(#function)")
presentNewContactView()
}
func didPressAddToExistingContact() {
Logger.info("\(logTag) \(#function)")
presentSelectAddToExistingContactView()
}
// MARK: -
private func presentNewContactView() {
guard let fromViewController = fromViewController else {
owsFail("\(logTag) missing fromViewController")
return
}
guard contactsManager.supportsContactEditing else {
owsFail("\(logTag) Contact editing not supported")
return
}
guard let systemContact = OWSContacts.systemContact(for: contactShare.dbRecord) else {
owsFail("\(logTag) Could not derive system contact.")
return
}
guard contactsManager.isSystemContactsAuthorized else {
ContactsViewHelper.presentMissingContactAccessAlertController(from: fromViewController)
return
}
let contactViewController = CNContactViewController(forNewContact: systemContact)
contactViewController.delegate = self
contactViewController.allowsActions = false
contactViewController.allowsEditing = true
contactViewController.navigationItem.leftBarButtonItem = UIBarButtonItem(title: CommonStrings.cancelButton, style: .plain, target: self, action: #selector(didFinishEditingContact))
contactViewController.navigationItem.leftBarButtonItem = UIBarButtonItem(title: CommonStrings.cancelButton,
style: .plain,
target: self,
action: #selector(didFinishEditingContact))
guard let navigationController = fromViewController.navigationController else {
owsFail("\(logTag) missing navigationController")
return
}
navigationController.pushViewController(contactViewController, animated: true)
// HACK otherwise CNContactViewController Navbar is shown as black.
// RADAR rdar://28433898 http://www.openradar.me/28433898
// CNContactViewController incompatible with opaque navigation bar
UIUtil.applyDefaultSystemAppearence()
}
private func presentSelectAddToExistingContactView() {
guard let fromViewController = fromViewController else {
owsFail("\(logTag) missing fromViewController")
return
}
guard contactsManager.supportsContactEditing else {
owsFail("\(logTag) Contact editing not supported")
return
}
guard contactsManager.isSystemContactsAuthorized else {
ContactsViewHelper.presentMissingContactAccessAlertController(from: fromViewController)
return
}
// TODO: Revisit this.
guard let firstPhoneNumber = contactShare.e164PhoneNumbers().first else {
owsFail("\(logTag) Missing phone number.")
return
}
// TODO: We need to modify OWSAddToContactViewController to take a OWSContact
// and merge it with an existing CNContact.
let viewController = OWSAddToContactViewController()
viewController.configure(withRecipientId: firstPhoneNumber)
guard let navigationController = fromViewController.navigationController else {
owsFail("\(logTag) missing navigationController")
return
}
navigationController.pushViewController(viewController, animated: true)
}
// MARK: - CNContactViewControllerDelegate
@objc public func contactViewController(_ viewController: CNContactViewController, didCompleteWith contact: CNContact?) {
Logger.info("\(logTag) \(#function)")
guard let fromViewController = fromViewController else {
owsFail("\(logTag) missing fromViewController")
return
}
guard let navigationController = fromViewController.navigationController else {
owsFail("\(logTag) missing navigationController")
return
}
guard let delegate = delegate else {
owsFail("\(logTag) missing delegate")
return
}
navigationController.popToViewController(fromViewController, animated: true)
delegate.didCreateOrEditContact()
}
@objc public func didFinishEditingContact() {
Logger.info("\(logTag) \(#function)")
guard let fromViewController = fromViewController else {
owsFail("\(logTag) missing fromViewController")
return
}
guard let navigationController = fromViewController.navigationController else {
owsFail("\(logTag) missing navigationController")
return
}
guard let delegate = delegate else {
owsFail("\(logTag) missing delegate")
return
}
navigationController.popToViewController(fromViewController, animated: true)
delegate.didCreateOrEditContact()
}
}