Scenario - Use our default view controllers, launch them from custom UI

Step 1

In the VOVoucherCreationFlowDelegate, implement:

- (UIViewController<VOVoucherCreationViewControllerProtocol> *)customCreationViewController; 
func customCreationViewController() -> (UIViewController & VOVoucherCreationViewControllerProtocol) {}

to instantiate your custom creation view controller.

(Note: When you launch the creation flow, the VOVoucherCreationFlowCoordinator, will assign itself a creation view controller. It will use the default creation view controller if you do not implement the above method.)

Step 2

Your creation view controller should adopt the VOVoucherCreationViewControllerProtocol.

The following is a sample implementation of an initializer:

+ (instancetype)yourCreationViewControllerWithVoucherCreationManager:(VOVoucherCreationManager *)createManager
                                             creationFlowCoordinator:(VOVoucherCreationFlowCoordinator *)creationFlowCoordinator
                                                  createFlowDelegate:(id<VOVoucherCreationFlowDelegate>)createFlowDelegate
                                                         vouchrTheme:(VOTheme *)vouchrTheme
                                              personalizationOptions:(NSArray<VOPersonalizationOption *> *)personalizationOptions {
    NSBundle *bundle = [NSBundle bundleForClass:[YourCreationViewController class]];
    YourCreationViewController *viewController = [[YourCreationViewController alloc] initWithNibName:NSStringFromClass([YourCreationViewController class]) bundle:bundle];
    viewController.createManager = createManager;
    viewController.creationFlowCoordinator = creationFlowCoordinator;
    viewController.createFlowDelegate = createFlowDelegate;
    viewController.vouchrTheme = vouchrTheme;
    viewController.personalizationOptions = personalizationOptions;
    viewController.mutableVoucher = createManager.mutableVoucher;
    viewController.creationItems = [NSMutableArray new];

    return viewController;
} 
class func voucherCreationViewController(with createManager: VOVoucherCreationManager, creationFlowCoordinator: VOVoucherCreationFlowCoordinator, createFlowDelegate: VOVoucherCreationFlowDelegate, vouchrTheme: VOTheme, personalizationOptions: [VOPersonalizationOption]) -> Self {
    let bundle = Bundle(for: YourViewController.self)
    let viewController = YourViewController(nibName: NSStringFromClass(YourViewController.self), bundle: bundle)
    viewController.createManager = createManager
    viewController.creationFlowCoordinator = creationFlowCoordinator
    viewController.createFlowDelegate = createFlowDelegate
    viewController.vouchrTheme = vouchrTheme
    viewController.personalizationOptions = personalizationOptions
    viewController.mutableVoucher = createManager.mutableVoucher
    viewController.creationItems = [VOCreationItemView]()

    return viewController
}

(Note: assign the mutableVoucher property of the VOVoucherCreationManager to the mutableVoucher property of your creation view controller. You may also want to initialize your array of creationItems here, or you can lazily load them, etc. )

Step 3

Your creation view controller is responsible for setting up the UI to select and launch the various personalization options it was initialized with in step 2.

The following is a sample implementation using a collection view to present the personalization options:

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
    return self.personalizationOptions.count;
}

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
    [collectionView deselectItemAtIndexPath:indexPath animated:YES];
    VOPersonalizationOption *personalizationOption = self.personalizationOptions[indexPath.item];
    [self.creationFlowCoordinator launchPersonalizationViewControllerForPersonalizationOption:personalizationOption];
} 
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return personalizationOptions.count
}

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    collectionView.deselectItem(at: indexPath, animated: true)
    let personalizationOption: VOPersonalizationOption? = personalizationOptions[indexPath.item]
    creationFlowCoordinator.launchPersonalizationViewController(forPersonalizationOption: personalizationOption)
}

(Note: self.delegate refers to the VOVoucherCreationFlowCoordinator instance that assigned itself as the VOVoucherCreationFlowDelegate of your voucher creation view controller. It assigned itself when it launched the creation view controller.)

(Note 2: launchPersonalizationViewControllerForPersonalizationOption: returns a view controller if launchPersonalizationViewControllerForPersonalizationOption: was implemented by the VOVoucherCreationFlowDelegate in step 1. Otherwise it launches the default view controller associated with the personalization option.)

Step 4

The creation flow coordinator will take care of updating the voucher when users add a personalization. When a personalization is added, you can receive its VOCreationItemView to display or animate for users. To update the screen after a new personalization is added, implement:

- (void)didUpdateVoucherWithCreationItemView:(VOCreationItemView *)creationItemView withCompletion:(void (^)(void))completion;
func didUpdateVoucher(with creationItemView: VOCreationItemView?, withCompletion completion: @escaping () -> Void) {}

Optional - Send, Edit, Preview, Prepopulate

You will generally want a reference the VOVoucherCreationFlowCoordinator initialized during setup. You will call methods on the VOVoucherCreationFlowCoordinator instance to send, edit, and preview the reveal animation of the voucher.

Sending

To send a voucher using our default send voucher view controller, your button or other event handling UI element should implement the following when a user taps on it:

- (void)sendButtonPressed:(UIButton *)sender {
    [self.creationFlowCoordinator launchSendVoucherScreenFromCreationViewControllerWithCreationItems:self.creationItems
                                                                                     backgroundColor:backgroundColor];
} 
func sendButtonPressed(_ sender: UIButton?) {
    creationFlowCoordinator.launchSendVoucherScreenFromCreationViewController(withCreationItems: creationItems, backgroundColor: backgroundColor)
}

Editing

To start the edit voucher flow, your Edit button should implement the following:

- (IBAction)editButtonPressed:(UIButton *)sender {
    [self.creationFlowCoordinator launchEditScreenFromCreationViewControllerWithCreationItems:self.creationItems];
} 
@IBAction func editButtonPressed(_ sender: UIButton) {
    creationFlowCoordinator.launchEditScreenFromCreationViewController(withCreationItems: creationItems)
}

(NOTE: editing currently still goes through the surpriise flow: Preview Screen -> Creation Screen -> Personalization View Controller; TODO: launch personalization screens directly?)

delegate callbacks

The default editing flow allows for rearranging, and deleting creation items. You can receive updated creation items through the following two methods. Implement them to, for example, update your creation view controller’s creation items array after editing:

- (void)didEditVoucherWithRearrangedCreationItems:(NSMutableArray<CreationItemImageView *> *)creationItems;

- (void)didEditVoucherWithDeletedCreationItems:(NSMutableArray<CreationItemImageView *> *)creationItems; 
func didEditVoucher(withRearrangedCreationItems creationItems: [CreationItemImageView]) {}

func didEditVoucher(withDeletedCreationItems creationItems: [CreationItemImageView]) {}

Preview Reveal Animation

To preview the reveal animation from your creation view controller, implement a variation of the following:

- (IBAction)previewButtonPressed:(UIButton *)sender {
    [self.creationFlowCoordinator launchRevealScreenFromCreationViewControllerWithVoucher:self.mutableVoucher];
} 
@IBAction func previewButtonPressed(_ sender: UIButton) {
    creationFlowCoordinator.launchRevealScreenFromCreationViewController(withVoucher: mutableVoucher)
}

Prepopulate

You can prepopulate a voucher with contents from an ‘Occasion’ loaded from the VODiscoverScreenV1ViewController.

In your setup class, launch the flow through the discover screen by calling the following method through your VOVoucherCreationFlowCoordinator:

[self.voucherCreationFlowCoordinator launchDiscoverScreenVersion:DiscoverScreenVersion
                                                onViewController:self
                                          personalizationOptions:[self personalizations]
                                                 discoverBuilder:^(VODiscoverScreenBuilder * _Nonnull builder) {
                                                    // set builder properties here
                                                 }];
voucherCreationFlowCoordinator.launch(DiscoverScreenVersion, on: self, personalizationOptions: personalizations(), discoverBuilder: { builder in
            // set builder properties here
        })

In the flow, a user selects an VOOccasion, and proceeds to the VOPreviewVoucherContentsViewController. Next, the user taps the “Use It” button to initiate prepopulation. One by one, each personalization is added to the voucher, and each time a callback is made to the following method:

- (void)didUpdateVoucherWithCreationItemView:(nullable VOCreationItemView *)creationItemView withCompletion:(nullable void (^)(void))completion {
  [self.creationItems addObject:creationItem];
  [self.tableView reloadData];
} 
func didUpdateVoucher(with creationItemView: VOCreationItemView?, withCompletion completion: (() -> Void)? = nil) {
    creationItems.append(creationItem)
    tableView.reloadData()
}

This example implementation adds a VOCreationItemView to the view controller’s creationItems array, and reloads the tableView. Your implementation will be specific to your custom creation view controller.