chromium/ios/chrome/browser/download/ui_bundled/vcard_coordinator.mm

// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#import "ios/chrome/browser/download/ui_bundled/vcard_coordinator.h"

#import <ContactsUI/ContactsUI.h>

#import "base/scoped_observation.h"
#import "ios/chrome/browser/download/model/vcard_tab_helper.h"
#import "ios/chrome/browser/download/model/vcard_tab_helper_delegate.h"
#import "ios/chrome/browser/shared/model/browser/browser.h"
#import "ios/chrome/browser/web_state_list/model/web_state_dependency_installer_bridge.h"
#import "ios/web/public/web_state_observer_bridge.h"

@interface VcardCoordinator () <DependencyInstalling, VcardTabHelperDelegate> {
  // Bridge which observes WebStateList and alerts this coordinator when this
  // needs to register the Mediator with a new WebState.
  std::unique_ptr<WebStateDependencyInstallerBridge> _dependencyInstallerBridge;
}

// NavigationController that contains a viewController used to display a
// contact.
@property(nonatomic, strong) UINavigationController* navigationViewController;

@end

@implementation VcardCoordinator

- (instancetype)initWithBaseViewController:(UIViewController*)baseViewController
                                   browser:(Browser*)browser {
  if ((self = [super initWithBaseViewController:baseViewController
                                        browser:browser])) {
    _dependencyInstallerBridge =
        std::make_unique<WebStateDependencyInstallerBridge>(
            self, browser->GetWebStateList());
  }
  return self;
}

- (void)stop {
  // Reset this observer manually. We want this to go out of scope now, to
  // ensure it detaches before `browser` and its WebStateList get destroyed.
  _dependencyInstallerBridge.reset();

  self.navigationViewController = nil;
}

#pragma mark - DependencyInstalling methods

- (void)installDependencyForWebState:(web::WebState*)webState {
  VcardTabHelper::FromWebState(webState)->set_delegate(self);
}

- (void)uninstallDependencyForWebState:(web::WebState*)webState {
  VcardTabHelper::FromWebState(webState)->set_delegate(nil);
}

#pragma mark - Private

// Dismisses the the `navigationViewController`.
- (void)dismissButtonTapped {
  [self.baseViewController dismissViewControllerAnimated:true completion:nil];
}

// Retreives contact informations from `data` and presents it.
- (void)presentContactVCardFromData:(NSData*)vcardData {
  // TODO(crbug.com/40208267): Vcard download code only support the first
  // contact.
  CNContact* contact =
      [[CNContactVCardSerialization contactsWithData:vcardData
                                               error:nil] firstObject];
  if (!contact) {
    return;
  }

  CNContactViewController* contactViewController =
      [CNContactViewController viewControllerForUnknownContact:contact];

  contactViewController.allowsEditing = YES;
  contactViewController.contactStore = [[CNContactStore alloc] init];

  UIBarButtonItem* dismissButton = [[UIBarButtonItem alloc]
      initWithBarButtonSystemItem:UIBarButtonSystemItemDone
                           target:self
                           action:@selector(dismissButtonTapped)];
  contactViewController.navigationItem.leftBarButtonItem = dismissButton;

  self.navigationViewController = [[UINavigationController alloc]
      initWithRootViewController:contactViewController];
  [self.baseViewController presentViewController:self.navigationViewController
                                        animated:YES
                                      completion:nil];
}

#pragma mark - VcardTabHelperDelegate

- (void)openVcardFromData:(NSData*)vcardData {
  DCHECK(vcardData);
  [self presentContactVCardFromData:vcardData];
}

@end