chromium/ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_plus_address_mediator.mm

// Copyright 2024 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/autofill/ui_bundled/manual_fill/manual_fill_plus_address_mediator.h"

#import "base/i18n/message_formatter.h"
#import "base/ranges/algorithm.h"
#import "base/strings/sys_string_conversions.h"
#import "components/plus_addresses/plus_address_service.h"
#import "components/strings/grit/components_strings.h"
#import "ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_action_cell.h"
#import "ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_constants.h"
#import "ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_content_injector.h"
#import "ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_plus_address.h"
#import "ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_plus_address_cell.h"
#import "ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_plus_address_consumer.h"
#import "ios/chrome/browser/favicon/model/favicon_loader.h"
#import "ios/chrome/browser/net/model/crurl.h"
#import "ios/chrome/grit/ios_strings.h"
#import "net/base/registry_controlled_domains/registry_controlled_domain.h"
#import "ui/base/l10n/l10n_util.h"
#import "ui/gfx/favicon_size.h"
#import "url/gurl.h"

@implementation ManualFillPlusAddressMediator {
  // The favicon loader used in the cell.
  FaviconLoader* _faviconLoader;

  // Used to fetch plus addresses.
  plus_addresses::PlusAddressService* _plusAddressService;

  // Origin to fetch plus addresses for.
  GURL _URL;

  // The origin to which all operations should be scoped.
  url::Origin _mainFrameOrigin;
}

- (instancetype)initWithFaviconLoader:(FaviconLoader*)faviconLoader
                   plusAddressService:
                       (plus_addresses::PlusAddressService*)plusAddressService
                                  URL:(const GURL&)URL {
  self = [super init];
  if (self) {
    _faviconLoader = faviconLoader;
    _plusAddressService = plusAddressService;
    _URL = URL;
    _mainFrameOrigin = url::Origin::Create(URL);
  }

  return self;
}

- (void)setConsumer:(id<ManualFillPlusAddressConsumer>)consumer {
  if (consumer == _consumer) {
    return;
  }
  _consumer = consumer;
  [self postPlusAddressesToConsumer];
  [self postActionsToConsumer];
}

#pragma mark - TableViewFaviconDataSource

- (void)faviconForPageURL:(CrURL*)URL
               completion:(void (^)(FaviconAttributes*))completion {
  CHECK(completion);
  _faviconLoader->FaviconForPageUrlOrHost(URL.gurl, gfx::kFaviconSize,
                                          completion);
}

#pragma mark - Private

// Initiates the process of fetching and presenting Plus Addresses to the
// consumer.
- (void)postPlusAddressesToConsumer {
  if (!self.consumer) {
    return;
  }

  __weak __typeof(self) weakSelf = self;
  auto callback =
      base::BindOnce(^(std::vector<plus_addresses::PlusProfile> plusProfiles) {
        std::erase_if(plusProfiles,
                      [&](const plus_addresses::PlusProfile& plusProfile) {
                        return !plusProfile.is_confirmed;
                      });

        ManualFillPlusAddressMediator* strongSelf = weakSelf;
        if (!strongSelf) {
          return;
        }

        [strongSelf onPlusAddressesFetched:plusProfiles];
      });

  _plusAddressService->GetAffiliatedPlusProfiles(_mainFrameOrigin,
                                                 std::move(callback));
}

// Presents the fetched `plusProfiles` to the consumer.
- (void)onPlusAddressesFetched:
    (const std::vector<plus_addresses::PlusProfile>&)plusProfiles {
  int plusAddressesCount = (int)plusProfiles.size();
  NSMutableArray* items =
      [[NSMutableArray alloc] initWithCapacity:plusAddressesCount];

  for (int i = 0; i < plusAddressesCount; i++) {
    NSString* cellIndexAccessibilityLabel = base::SysUTF16ToNSString(
        base::i18n::MessageFormatter::FormatWithNamedArgs(
            l10n_util::GetStringUTF16(
                IDS_PLUS_ADDRESS_MANUAL_FALLBACK_CELL_INDEX_IOS),
            "count", plusAddressesCount, "position", i + 1));

    ManualFillPlusAddress* manualFillPlusAddress =
        [self createManualFillPlusAddress:base::SysUTF8ToNSString(
                                              *plusProfiles[i].plus_address)];
    ManualFillPlusAddressItem* item = [[ManualFillPlusAddressItem alloc]
                initWithPlusAddress:manualFillPlusAddress
                    contentInjector:_contentInjector
                        menuActions:@[]
        cellIndexAccessibilityLabel:cellIndexAccessibilityLabel];
    [items addObject:item];
  }

  [self.consumer presentPlusAddresses:items];
}

// Creates `ManualFillPlusAddress` from `plusAddress`.
- (ManualFillPlusAddress*)createManualFillPlusAddress:(NSString*)plusAddress {
  std::string host = _URL.host();
  std::string site_name =
      net::registry_controlled_domains::GetDomainAndRegistry(
          host, net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
  NSString* siteName = base::SysUTF8ToNSString(site_name);
  NSString* plusAddressHost = base::SysUTF8ToNSString(host);
  if ([plusAddressHost hasPrefix:@"www."] && plusAddressHost.length > 4) {
    plusAddressHost = [plusAddressHost substringFromIndex:4];
  }
  return [[ManualFillPlusAddress alloc]
      initWithPlusAddress:plusAddress
                 siteName:siteName.length ? siteName : plusAddressHost
                     host:plusAddressHost
                      URL:_URL];
}

// Sends actions to the consumer.
- (void)postActionsToConsumer {
  if (!self.consumer) {
    return;
  }

  NSString* managePlusAddressesTitle = l10n_util::GetNSString(
      IDS_PLUS_ADDRESS_MANUAL_FALLBACK_MANAGE_ACTION_TEXT_IOS);
  ManualFillActionItem* managePlusAddressItem =
      [[ManualFillActionItem alloc] initWithTitle:managePlusAddressesTitle
                                           action:nil];
  managePlusAddressItem.accessibilityIdentifier =
      manual_fill::kManagePlusAddressAccessibilityIdentifier;
  [self.consumer presentPlusAddressActions:@[ managePlusAddressItem ]];
}

@end