chromium/ios/chrome/browser/badges/ui_bundled/badge_button_factory.mm

// Copyright 2019 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/badges/ui_bundled/badge_button_factory.h"

#import <ostream>

#import "base/notreached.h"
#import "build/build_config.h"
#import "components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.h"
#import "ios/chrome/browser/infobars/model/infobar_ios.h"
#import "ios/chrome/browser/shared/ui/symbols/symbols.h"
#import "ios/chrome/browser/badges/ui_bundled/badge_button.h"
#import "ios/chrome/browser/badges/ui_bundled/badge_constants.h"
#import "ios/chrome/browser/badges/ui_bundled/badge_delegate.h"
#import "ios/chrome/browser/badges/ui_bundled/badge_overflow_menu_util.h"
#import "ios/chrome/common/ui/colors/semantic_color_names.h"
#import "ios/chrome/grit/ios_strings.h"
#import "ui/base/l10n/l10n_util.h"

namespace {
// The identifier for the new popup menu action trigger.
NSString* const kOverflowPopupMenuActionIdentifier =
    @"kOverflowPopupMenuActionIdentifier";

// The size of the incognito symbol image.
const CGFloat kSymbolIncognitoPointSize = 28.;

// The size of the incognito full screen symbol image.
const CGFloat kSymbolIncognitoFullScreenPointSize = 14.;

}  // namespace

@implementation BadgeButtonFactory

- (BadgeButton*)badgeButtonForBadgeType:(BadgeType)badgeType
                           usingInfoBar:(InfoBarIOS*)infoBar {
  switch (badgeType) {
    case kBadgeTypePasswordSave:
      return [self passwordsSaveBadgeButton];
    case kBadgeTypePasswordUpdate:
      return [self passwordsUpdateBadgeButton];
    case kBadgeTypeSaveCard:
      return [self saveCardBadgeButton];
    case kBadgeTypeTranslate:
      return [self translateBadgeButton];
    case kBadgeTypeIncognito:
      return [self incognitoBadgeButton];
    case kBadgeTypeOverflow:
      return [self overflowBadgeButton];
    case kBadgeTypeSaveAddressProfile:
      return [self saveAddressProfileBadgeButton:infoBar];
    case kBadgeTypePermissionsCamera:
      return [self permissionsCameraBadgeButton];
    case kBadgeTypePermissionsMicrophone:
      return [self permissionsMicrophoneBadgeButton];
    case kBadgeTypeParcelTracking:
      return [self parcelTrackingBadgeButton];
    case kBadgeTypeNone:
      NOTREACHED_IN_MIGRATION() << "A badge should not have kBadgeTypeNone";
      return nil;
  }
}

#pragma mark - Private
- (BadgeButton*)passwordsSaveBadgeButton {
  UIImage* image =
      CustomSymbolWithPointSize(kPasswordSymbol, kInfobarSymbolPointSize);
#if !BUILDFLAG(IS_IOS_MACCATALYST)
  image = CustomSymbolWithPointSize(kMulticolorPasswordSymbol,
                                    kInfobarSymbolPointSize);
#endif  // BUILDFLAG(IS_IOS_MACCATALYST)
  BadgeButton* button = [self createButtonForType:kBadgeTypePasswordSave
                                            image:image];
  [button addTarget:self.delegate
                action:@selector(passwordsBadgeButtonTapped:)
      forControlEvents:UIControlEventTouchUpInside];
  button.accessibilityIdentifier =
      kBadgeButtonSavePasswordAccessibilityIdentifier;
  button.accessibilityLabel =
      l10n_util::GetNSString(IDS_IOS_INFOBAR_BADGES_PASSWORD_HINT);
  return button;
}

- (BadgeButton*)passwordsUpdateBadgeButton {
  UIImage* image =
      CustomSymbolWithPointSize(kPasswordSymbol, kInfobarSymbolPointSize);
#if !BUILDFLAG(IS_IOS_MACCATALYST)
  image = CustomSymbolWithPointSize(kMulticolorPasswordSymbol,
                                    kInfobarSymbolPointSize);
#endif  // BUILDFLAG(IS_IOS_MACCATALYST)
  BadgeButton* button = [self createButtonForType:kBadgeTypePasswordUpdate
                                            image:image];
  [button addTarget:self.delegate
                action:@selector(passwordsBadgeButtonTapped:)
      forControlEvents:UIControlEventTouchUpInside];
  button.accessibilityIdentifier =
      kBadgeButtonUpdatePasswordAccessibilityIdentifier;
  button.accessibilityLabel =
      l10n_util::GetNSString(IDS_IOS_INFOBAR_BADGES_PASSWORD_HINT);
  return button;
}

- (BadgeButton*)saveCardBadgeButton {
  UIImage* image =
      DefaultSymbolWithPointSize(kCreditCardSymbol, kInfobarSymbolPointSize);
  BadgeButton* button = [self createButtonForType:kBadgeTypeSaveCard
                                            image:image];
  [button addTarget:self.delegate
                action:@selector(saveCardBadgeButtonTapped:)
      forControlEvents:UIControlEventTouchUpInside];
  button.accessibilityIdentifier = kBadgeButtonSaveCardAccessibilityIdentifier;
  button.accessibilityLabel =
      l10n_util::GetNSString(IDS_IOS_AUTOFILL_SAVE_CARD_BADGE_HINT);
  return button;
}

- (BadgeButton*)translateBadgeButton {
  UIImage* image =
      CustomSymbolWithPointSize(kTranslateSymbol, kInfobarSymbolPointSize);
  BadgeButton* button = [self createButtonForType:kBadgeTypeTranslate
                                            image:image];
  [button addTarget:self.delegate
                action:@selector(translateBadgeButtonTapped:)
      forControlEvents:UIControlEventTouchUpInside];
  button.accessibilityIdentifier = kBadgeButtonTranslateAccessibilityIdentifier;
  button.accessibilityLabel =
      l10n_util::GetNSString(IDS_IOS_INFOBAR_BADGES_TRANSLATE_HINT);
  return button;
}

- (BadgeButton*)incognitoBadgeButton {
  BadgeButton* button;
  UIImage* image;

  image =
      SymbolWithPalette(CustomSymbolWithPointSize(kIncognitoCircleFillSymbol,
                                                  kSymbolIncognitoPointSize),
                        SmallIncognitoPalette());
  button = [self createButtonForType:kBadgeTypeIncognito image:image];
  button.fullScreenImage = CustomSymbolTemplateWithPointSize(
      kIncognitoSymbol, kSymbolIncognitoFullScreenPointSize);

  button.tintColor = [UIColor colorNamed:kTextPrimaryColor];
  button.accessibilityTraits &= ~UIAccessibilityTraitButton;
  button.userInteractionEnabled = NO;
  button.accessibilityIdentifier = kBadgeButtonIncognitoAccessibilityIdentifier;
  button.accessibilityLabel =
      l10n_util::GetNSString(IDS_IOS_BADGE_INCOGNITO_HINT);
  return button;
}

- (BadgeButton*)overflowBadgeButton {
  UIImage* image = DefaultSymbolWithPointSize(kEllipsisCircleFillSymbol,
                                              kInfobarSymbolPointSize);
  BadgeButton* button = [self createButtonForType:kBadgeTypeOverflow
                                            image:image];
  button.accessibilityIdentifier = kBadgeButtonOverflowAccessibilityIdentifier;
  button.accessibilityLabel =
      l10n_util::GetNSString(IDS_IOS_OVERFLOW_BADGE_HINT);

  // Configure new overflow popup menu if enabled.
  button.showsMenuAsPrimaryAction = YES;

  // Adds an empty menu so the event triggers the first time.
  button.menu = [UIMenu menuWithChildren:@[]];
  [button removeActionForIdentifier:kOverflowPopupMenuActionIdentifier
                   forControlEvents:UIControlEventMenuActionTriggered];

  // Configure actions that should be executed on each tap of the overflow
  // badge button to make sure the right overflow menu items are showing up.
  __weak UIButton* weakButton = button;
  __weak BadgeButtonFactory* weakSelf = self;
  void (^showModalFunction)(BadgeType) = ^(BadgeType badgeType) {
    [weakSelf.delegate showModalForBadgeType:badgeType];
  };
  void (^buttonTapHandler)(UIAction*) = ^(UIAction* action) {
    [weakSelf.delegate overflowBadgeButtonTapped:weakButton];
    weakButton.menu = GetOverflowMenuFromBadgeTypes(
        weakSelf.delegate.badgeTypesForOverflowMenu, showModalFunction);
  };
  UIAction* action =
      [UIAction actionWithTitle:@""
                          image:nil
                     identifier:kOverflowPopupMenuActionIdentifier
                        handler:buttonTapHandler];

  // Attach the action to the button.
  [button addAction:action forControlEvents:UIControlEventMenuActionTriggered];
  return button;
}

- (BadgeButton*)saveAddressProfileBadgeButton:(InfoBarIOS*)infoBar {
  UIImage* image =
      CustomSymbolWithPointSize(kLocationSymbol, kInfobarSymbolPointSize);

  if (infoBar) {
    autofill::AutofillSaveUpdateAddressProfileDelegateIOS* delegate =
        static_cast<autofill::AutofillSaveUpdateAddressProfileDelegateIOS*>(
            infoBar->delegate());
    CHECK(delegate);
    if (delegate->IsMigrationToAccount()) {
      image = CustomSymbolWithPointSize(kCloudAndArrowUpSymbol,
                                        kInfobarSymbolPointSize);
    }
  }

  BadgeButton* button = [self createButtonForType:kBadgeTypeSaveAddressProfile
                                            image:image];
  [button addTarget:self.delegate
                action:@selector(saveAddressProfileBadgeButtonTapped:)
      forControlEvents:UIControlEventTouchUpInside];
  button.accessibilityIdentifier =
      kBadgeButtonSaveAddressProfileAccessibilityIdentifier;
  // TODO(crbug.com/40103383): Create a11y label hint.
  return button;
}

- (BadgeButton*)permissionsCameraBadgeButton {
  BadgeButton* button = [self
      createButtonForType:kBadgeTypePermissionsCamera
                    image:CustomSymbolTemplateWithPointSize(
                              kCameraFillSymbol, kInfobarSymbolPointSize)];
  [button addTarget:self.delegate
                action:@selector(permissionsBadgeButtonTapped:)
      forControlEvents:UIControlEventTouchUpInside];
  button.accessibilityIdentifier =
      kBadgeButtonPermissionsCameraAccessibilityIdentifier;
  button.accessibilityLabel =
      l10n_util::GetNSString(IDS_IOS_INFOBAR_BADGES_PERMISSIONS_HINT);
  return button;
}

- (BadgeButton*)permissionsMicrophoneBadgeButton {
  BadgeButton* button = [self
      createButtonForType:kBadgeTypePermissionsMicrophone
                    image:DefaultSymbolTemplateWithPointSize(
                              kMicrophoneFillSymbol, kInfobarSymbolPointSize)];
  [button addTarget:self.delegate
                action:@selector(permissionsBadgeButtonTapped:)
      forControlEvents:UIControlEventTouchUpInside];
  button.accessibilityIdentifier =
      kBadgeButtonPermissionsMicrophoneAccessibilityIdentifier;
  button.accessibilityLabel =
      l10n_util::GetNSString(IDS_IOS_INFOBAR_BADGES_PERMISSIONS_HINT);
  return button;
}

- (BadgeButton*)parcelTrackingBadgeButton {
  UIImage* image =
      DefaultSymbolWithPointSize(kShippingBoxSymbol, kInfobarSymbolPointSize);
  BadgeButton* button = [self createButtonForType:kBadgeTypeParcelTracking
                                            image:image];
  [button addTarget:self.delegate
                action:@selector(parcelTrackingBadgeButtonTapped:)
      forControlEvents:UIControlEventTouchUpInside];
  button.accessibilityIdentifier =
      kBadgeButtonParcelTrackingAccessibilityIdentifier;
  button.accessibilityLabel =
      l10n_util::GetNSString(IDS_IOS_INFOBAR_BADGES_PARCEL_TRACKING_HINT);
  return button;
}

- (BadgeButton*)createButtonForType:(BadgeType)badgeType image:(UIImage*)image {
  BadgeButton* button = [BadgeButton badgeButtonWithType:badgeType];
  UIImageSymbolConfiguration* symbolConfig = [UIImageSymbolConfiguration
      configurationWithPointSize:kInfobarSymbolPointSize
                          weight:UIImageSymbolWeightRegular
                           scale:UIImageSymbolScaleMedium];
  [button setPreferredSymbolConfiguration:symbolConfig
                          forImageInState:UIControlStateNormal];
  button.image = image;
  button.fullScreenOn = NO;
  button.imageView.contentMode = UIViewContentModeScaleAspectFit;
  [NSLayoutConstraint
      activateConstraints:@[ [button.widthAnchor
                              constraintEqualToAnchor:button.heightAnchor] ]];
  return button;
}

@end