diff --git a/MVMCore/MVMCore.xcodeproj/project.pbxproj b/MVMCore/MVMCore.xcodeproj/project.pbxproj index 33451d0..97a9bb3 100644 --- a/MVMCore/MVMCore.xcodeproj/project.pbxproj +++ b/MVMCore/MVMCore.xcodeproj/project.pbxproj @@ -34,6 +34,7 @@ 01F2A04C23A82B1B00D954D8 /* ActionCallModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01F2A04B23A82B1B00D954D8 /* ActionCallModel.swift */; }; 01F2A05223A8325100D954D8 /* ModelMapping.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01F2A05123A8325100D954D8 /* ModelMapping.swift */; }; 0A42538F23F3414800554656 /* Codable+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A42538E23F3414800554656 /* Codable+Helpers.swift */; }; + 0ACC81A22613C73800A9C886 /* ActionContactModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ACC81A12613C73800A9C886 /* ActionContactModel.swift */; }; 0AEBB84625FA75C000EA80EE /* ActionOpenSMSModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AEBB84525FA75C000EA80EE /* ActionOpenSMSModel.swift */; }; 0AFF597A23FC6E60005C24E8 /* ActionShareModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AFF597923FC6E60005C24E8 /* ActionShareModel.swift */; }; 30349BF11FCCA78A00546A1E /* MVMCoreSessionTimeHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = 30349BEF1FCCA78A00546A1E /* MVMCoreSessionTimeHandler.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -169,6 +170,7 @@ 0A11030B20864F94008ADD90 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = ""; }; 0A11030C20864F9A008ADD90 /* es-MX */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "es-MX"; path = "es-MX.lproj/Localizable.strings"; sourceTree = ""; }; 0A42538E23F3414800554656 /* Codable+Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Codable+Helpers.swift"; sourceTree = ""; }; + 0ACC81A12613C73800A9C886 /* ActionContactModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionContactModel.swift; sourceTree = ""; }; 0AEBB84525FA75C000EA80EE /* ActionOpenSMSModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionOpenSMSModel.swift; sourceTree = ""; }; 0AFF597923FC6E60005C24E8 /* ActionShareModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionShareModel.swift; sourceTree = ""; }; 30349BEF1FCCA78A00546A1E /* MVMCoreSessionTimeHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreSessionTimeHandler.h; sourceTree = ""; }; @@ -452,6 +454,7 @@ BB780ADE250F8C890030BD2F /* ActionNoopModel.swift */, D27073B625BB45C4001C7246 /* ActionActionsModel.swift */, 0AEBB84525FA75C000EA80EE /* ActionOpenSMSModel.swift */, + 0ACC81A12613C73800A9C886 /* ActionContactModel.swift */, ); path = ActionType; sourceTree = ""; @@ -853,6 +856,7 @@ 8876D5E91FB50AB000EB2E3D /* NSArray+MFConvenience.m in Sources */, D27073B725BB45C4001C7246 /* ActionActionsModel.swift in Sources */, 946EE1B2237B5F260036751F /* JSONValue.swift in Sources */, + 0ACC81A22613C73800A9C886 /* ActionContactModel.swift in Sources */, AFBB96971FBA3A9A0008D868 /* MVMCorePresentViewControllerOperation.m in Sources */, AF43A5781FBA5B7C008E9347 /* MVMCoreJSONConstants.m in Sources */, AFBB96691FBA3A570008D868 /* MVMCoreRequestParameters.m in Sources */, diff --git a/MVMCore/MVMCore/ActionHandling/MVMCoreActionHandler.m b/MVMCore/MVMCore/ActionHandling/MVMCoreActionHandler.m index e6183cf..15fab4e 100644 --- a/MVMCore/MVMCore/ActionHandling/MVMCoreActionHandler.m +++ b/MVMCore/MVMCore/ActionHandling/MVMCoreActionHandler.m @@ -27,13 +27,16 @@ #import #import #import "MVMCoreLoadingOverlayHandler.h" +#import NSString * const KeyActionType = @"actionType"; NSString * const KeyActionTypeLinkAway = @"openURL"; NSString * const KeyActionTypeOpen = @"openPage"; -@implementation MVMCoreActionHandler +@interface MVMCoreActionHandler() +@end +@implementation MVMCoreActionHandler + (nullable instancetype)sharedActionHandler { return [MVMCoreActionUtility initializerClassCheck:[MVMCoreObject sharedInstance].actionHandler classToVerify:self]; } @@ -71,7 +74,10 @@ NSString * const KeyActionTypeOpen = @"openPage"; } else if ([actionType isEqualToString:KeyActionTypeSMS]) { [self smsAction:actionInformation additionalData:additionalData delegateObject:delegateObject]; - + + } else if ([actionType isEqualToString:KeyActionTypeContact]) { + [self contactAction:actionInformation additionalData:additionalData delegateObject:delegateObject]; + } else if ([actionType isEqualToString:KeyActionTypeShare]) { [self shareAction:actionInformation additionalData:additionalData delegateObject:delegateObject]; @@ -264,6 +270,46 @@ NSString * const KeyActionTypeOpen = @"openPage"; [MVMCoreActionUtility linkAway:[smsQuery stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding] appURLString:nil]; } +- (void)contactAction:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject { + + __weak typeof(self) weakSelf = self; + + NSString *phoneNumber = [actionInformation string:@"phoneNumber"]; + + if (!phoneNumber) { return; } + CNMutableContact *contact = [[CNMutableContact alloc] init]; + NSString *approach = [actionInformation stringForKey:@"approach"]; + + CNLabeledValue *phone = [[CNLabeledValue alloc] initWithLabel:CNLabelOther value:[[CNPhoneNumber alloc] initWithStringValue:phoneNumber]]; + contact.phoneNumbers = @[phone]; + + if ([approach isEqualToString:KeyAdd]) { + [MVMCoreDispatchUtility performBlockOnMainThread:^{ + CNContactPickerViewController *controller = [[CNContactPickerViewController alloc] init]; + // Setting to accessibilityValue as a workaround to pass data via the delegate function. + [controller.view setAccessibilityIdentifier:phoneNumber]; + controller.delegate = weakSelf; + + [[MVMCoreNavigationHandler sharedNavigationHandler] presentViewController:controller animated:YES]; + }]; + } else if ([approach isEqualToString:KeyCreate]) { + [MVMCoreDispatchUtility performBlockOnMainThread:^{ + contact.givenName = [actionInformation string:@"firstName"]; + contact.familyName = [actionInformation string:@"lastName"]; + + CNContactStore *store = [[CNContactStore alloc] init]; + CNContactViewController *controller = [CNContactViewController viewControllerForNewContact:contact]; + controller.contactStore = store; + controller.delegate = weakSelf; + + UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:controller]; + navigationController.modalPresentationStyle = UIModalPresentationPageSheet; + + [[MVMCoreNavigationHandler sharedNavigationHandler] pushViewController:controller animated:YES]; + }]; + } +} + - (void)callAction:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject { // Call NSString *callNumber = [actionInformation stringForKey:KeyCallNumber]; @@ -341,7 +387,49 @@ NSString * const KeyActionTypeOpen = @"openPage"; } } -#pragma mark - open url functions +#pragma mark - CNContactViewControllerDelegate + +- (void)contactViewController:(CNContactViewController *)viewController didCompleteWithContact:(CNContact *)contact { + [[MVMCoreNavigationHandler sharedNavigationHandler] removeCurrentViewController]; +} + +- (BOOL)contactViewController:(CNContactViewController *)viewController shouldPerformDefaultActionForContactProperty:(CNContactProperty *)property { + return YES; +} + +#pragma mark - CNContactPickerDelegate + +- (void)contactPickerDidCancel:(CNContactPickerViewController *)picker { + [[MVMCoreNavigationHandler sharedNavigationHandler] removeCurrentViewController]; +} + +- (void)contactPicker:(CNContactPickerViewController *)picker didSelectContact:(CNContact *)contact { + + // This is a means to pass the data to this delegate function. + NSString *phoneNumber = picker.view.accessibilityIdentifier; + + if (!phoneNumber) { return; } + CNContactStore *store = [[CNContactStore alloc] init]; + CNMutableContact *existingContact = [(CNMutableContact *)contact mutableCopy]; + CNPhoneNumber *number = [[CNPhoneNumber alloc] initWithStringValue:phoneNumber]; + CNLabeledValue *labelValue = [[CNLabeledValue alloc] initWithLabel:CNLabelOther value:number]; + NSMutableArray *phoneNumbers = [NSMutableArray new]; + [phoneNumbers addObject:labelValue]; + [phoneNumbers addObjectsFromArray:existingContact.phoneNumbers]; + existingContact.phoneNumbers = phoneNumbers; + + __weak typeof(self) weakSelf = self; + + [MVMCoreDispatchUtility performBlockOnMainThread:^{ + CNContactViewController *controller = [CNContactViewController viewControllerForNewContact:existingContact]; + controller.contactStore = store; + controller.delegate = weakSelf; + + [[MVMCoreNavigationHandler sharedNavigationHandler] pushViewController:controller animated:YES]; + }]; +} + +#pragma mark - Open URL - (void)linkAwayAction:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject { @@ -427,7 +515,7 @@ NSString * const KeyActionTypeOpen = @"openPage"; [[MVMCoreNavigationHandler sharedNavigationHandler] presentViewController:safariViewController animated:YES]; } -#pragma mark - Default Action Protocol Functions +#pragma mark - Default Action Protocol + (void)defaultLogAction:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject{ // Currently no default log action but this will eventually be server driven. diff --git a/MVMCore/MVMCore/Constants/MVMCoreJSONConstants.h b/MVMCore/MVMCore/Constants/MVMCoreJSONConstants.h index 00a72f1..084db36 100644 --- a/MVMCore/MVMCore/Constants/MVMCoreJSONConstants.h +++ b/MVMCore/MVMCore/Constants/MVMCoreJSONConstants.h @@ -26,6 +26,9 @@ extern NSString * const KeyButtonMap; extern NSString * const KeyOpenSupport; extern NSString * const KeyPostAction; +extern NSString * const KeyAdd; +extern NSString * const KeyCreate; + extern NSString * const KeyLinks; extern NSString * const KeyTitle; extern NSString * const KeyMessage; @@ -35,6 +38,7 @@ extern NSString * const KeyActionTypeShare; extern NSString * const KeyShareType; extern NSString * const KeyShareText; extern NSString * const KeyActionTypeSMS; +extern NSString * const KeyActionTypeContact; extern NSString * const KeyActionTypeCall; extern NSString * const KeyActionTypePreviousSubmit; extern NSString * const KeyActionTypeCancel; diff --git a/MVMCore/MVMCore/Constants/MVMCoreJSONConstants.m b/MVMCore/MVMCore/Constants/MVMCoreJSONConstants.m index 71ecd0e..dfd33b9 100644 --- a/MVMCore/MVMCore/Constants/MVMCoreJSONConstants.m +++ b/MVMCore/MVMCore/Constants/MVMCoreJSONConstants.m @@ -28,6 +28,9 @@ NSString * const KeyButtonMap = @"ButtonMap"; NSString * const KeyOpenSupport = @"openSupport"; NSString * const KeyPostAction = @"PostAction"; +NSString * const KeyAdd = @"add"; +NSString * const KeyCreate = @"create"; + NSString * const KeyLinks = @"Links"; NSString * const KeyTitle = @"title"; NSString * const KeyMessage = @"message"; @@ -36,6 +39,7 @@ NSString * const KeyActionTypeBack = @"back"; NSString * const KeyActionTypeShare = @"share"; NSString * const KeyActionTypeCall = @"call"; NSString * const KeyActionTypeSMS = @"sms"; +NSString * const KeyActionTypeContact = @"contact"; NSString * const KeyActionTypePreviousSubmit = @"previousSubmit"; NSString * const KeyActionTypeCancel = @"cancel"; NSString * const KeyActionTypeRedirect = @"switchApp"; diff --git a/MVMCore/MVMCore/Models/ActionType/ActionContactModel.swift b/MVMCore/MVMCore/Models/ActionType/ActionContactModel.swift new file mode 100644 index 0000000..6ccbc13 --- /dev/null +++ b/MVMCore/MVMCore/Models/ActionType/ActionContactModel.swift @@ -0,0 +1,39 @@ +// +// ActionContactModel.swift +// MVMCore +// +// Created by Kevin Christiano on 3/30/21. +// Copyright © 2021 myverizon. All rights reserved. +// + +import ContactsUI + + +@objcMembers public class ActionContactModel: ActionModelProtocol { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + + public static var identifier: String = "contact" + public var actionType: String = ActionCallModel.identifier + + public var phoneNumber: String + public var firstName: String? + public var lastName: String? + public var approach: String = KeyCreate + public var extraParameters: JSONValueDictionary? + public var analyticsData: JSONValueDictionary? + + //-------------------------------------------------- + // MARK: - Initializer + //-------------------------------------------------- + + public init(phoneNumber: String, firstName: String? = nil, lastName: String? = nil, approach: String = KeyCreate, _ extraParameters: JSONValueDictionary? = nil, _ analyticsData: JSONValueDictionary? = nil) { + self.phoneNumber = phoneNumber + self.firstName = firstName + self.lastName = lastName + self.approach = approach + self.extraParameters = extraParameters + self.analyticsData = analyticsData + } +} diff --git a/MVMCore/MVMCore/Models/ModelMapping.swift b/MVMCore/MVMCore/Models/ModelMapping.swift index 5524380..26cb696 100644 --- a/MVMCore/MVMCore/Models/ModelMapping.swift +++ b/MVMCore/MVMCore/Models/ModelMapping.swift @@ -23,6 +23,7 @@ try? ModelRegistry.register(ActionNoopModel.self) try? ModelRegistry.register(ActionActionsModel.self) try? ModelRegistry.register(ActionOpenSMSModel.self) + try? ModelRegistry.register(ActionContactModel.self) } }