chromium/chrome/browser/ui/cocoa/touchbar/credit_card_autofill_touch_bar_controller.mm

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

#import "chrome/browser/ui/cocoa/touchbar/credit_card_autofill_touch_bar_controller.h"

#include "base/feature_list.h"
#include "base/i18n/rtl.h"
#include "base/memory/raw_ptr.h"
#include "base/strings/sys_string_conversions.h"
#include "base/time/time.h"
#include "base/types/cxx23_to_underlying.h"
#include "chrome/app/vector_icons/vector_icons.h"
#import "chrome/browser/ui/autofill/autofill_popup_controller.h"
#include "components/autofill/core/browser/filling_product.h"
#include "components/autofill/core/browser/ui/autofill_resource_utils.h"
#include "components/autofill/core/browser/ui/suggestion.h"
#include "components/autofill/core/browser/ui/suggestion_type.h"
#include "components/autofill/core/common/autofill_features.h"
#include "components/grit/components_scaled_resources.h"
#import "ui/base/cocoa/touch_bar_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/image/image_skia_util_mac.h"
#include "ui/gfx/paint_vector_icon.h"

namespace {

// Touch bar identifier.
NSString* const kCreditCardAutofillTouchBarId = @"credit-card-autofill";

// Touch bar items identifiers.
NSString* const kCreditCardTouchId = @"CREDIT-CARD";
NSString* const kCreditCardItemsTouchId = @"CREDIT-CARD-ITEMS";

// Maximum number of autofill items that can appear on the touch bar.
constexpr int maxTouchBarItems = 3;

// Returns the credit card image.
NSImage* GetCreditCardTouchBarImage(int iconId) {
  if (iconId < 1) {
    return nil;
  }

  // If it's a generic card image, use the vector icon instead.
  if (iconId == IDR_AUTOFILL_CC_GENERIC) {
    return NSImageFromImageSkia(
        gfx::CreateVectorIcon(kCreditCardIcon, 16, SK_ColorWHITE));
  }

  return ui::ResourceBundle::GetSharedInstance()
      .GetNativeImageNamed(iconId)
      .AsNSImage();
}

}  // namespace

@interface CreditCardAutofillTouchBarController ()
- (NSColor*)touchBarSubtextColor;
@end

@implementation CreditCardAutofillTouchBarController {
  raw_ptr<autofill::AutofillPopupController> _controller;  // weak
  bool _is_credit_card_popup;
}

- (instancetype)initWithController:
    (autofill::AutofillPopupController*)controller {
  if ((self = [super init])) {
    _controller = controller;
    _is_credit_card_popup = (_controller->GetMainFillingProduct() ==
                             autofill::FillingProduct::kCreditCard);
  }
  return self;
}

- (NSTouchBar*)makeTouchBar {
  if (!_controller->GetLineCount() || !_is_credit_card_popup) {
    return nil;
  }

  NSTouchBar* touchBar = [[NSTouchBar alloc] init];
  [touchBar setCustomizationIdentifier:ui::GetTouchBarId(
                                           kCreditCardAutofillTouchBarId)];
  touchBar.delegate = self;

  [touchBar setDefaultItemIdentifiers:@[ kCreditCardItemsTouchId ]];
  return touchBar;
}

- (NSTouchBarItem*)touchBar:(NSTouchBar*)touchBar
      makeItemForIdentifier:(NSTouchBarItemIdentifier)identifier {
  if (![identifier hasSuffix:kCreditCardItemsTouchId]) {
    return nil;
  }

  NSMutableArray* creditCardItems = [NSMutableArray array];
  for (int i = 0; i < _controller->GetLineCount() && i < maxTouchBarItems;
       i++) {
    const autofill::Suggestion& suggestion = _controller->GetSuggestionAt(i);
    if (suggestion.type != autofill::SuggestionType::kAutocompleteEntry &&
        suggestion.type != autofill::SuggestionType::kAddressEntry &&
        suggestion.type != autofill::SuggestionType::kCreditCardEntry) {
      continue;
    }

    NSString* cardIdentifier = [NSString
        stringWithFormat:@"%@-%i",
                         ui::GetTouchBarItemId(kCreditCardAutofillTouchBarId,
                                               kCreditCardTouchId),
                         i];
    NSCustomTouchBarItem* item =
        [[NSCustomTouchBarItem alloc] initWithIdentifier:cardIdentifier];
    [item setView:[self createCreditCardButtonAtRow:i]];
    [creditCardItems addObject:item];
  }

  return [NSGroupTouchBarItem groupItemWithIdentifier:identifier
                                                items:creditCardItems];
}

- (NSColor*)touchBarSubtextColor {
  return [NSColor colorWithCalibratedRed:206.0 / 255.0
                                   green:206.0 / 255.0
                                    blue:206.0 / 255.0
                                   alpha:1.0];
}

- (NSButton*)createCreditCardButtonAtRow:(int)row {
  const autofill::Suggestion& suggestion = _controller->GetSuggestionAt(row);
  NSString* label = base::SysUTF16ToNSString(suggestion.main_text.value);
  NSString* subtext = nil;
  std::vector<std::vector<autofill::Suggestion::Text>> suggestion_labels =
      suggestion.labels;
  if (!suggestion_labels.empty()) {
    CHECK_GT(suggestion_labels.size(), 0U);
    CHECK_GT(suggestion_labels[0].size(), 0U);
    subtext =
        base::SysUTF16ToNSString(std::move(suggestion_labels[0][0].value));
  }

  // Create the button title based on the text direction.
  NSString* buttonTitle =
      [subtext length] ? [NSString stringWithFormat:@"%@ %@", label, subtext]
                       : label;

  // Create the button.
  NSImage* cardIconImage =
      GetCreditCardTouchBarImage(autofill::GetIconResourceID(suggestion.icon));
  NSButton* button = nil;
  if (cardIconImage) {
    button = [NSButton buttonWithTitle:buttonTitle
                                 image:cardIconImage
                                target:self
                                action:@selector(acceptCreditCard:)];
    button.imageHugsTitle = YES;
    button.imagePosition = base::i18n::IsRTL() ? NSImageLeft : NSImageRight;
  } else {
    button = [NSButton buttonWithTitle:buttonTitle
                                target:self
                                action:@selector(acceptCreditCard:)];
  }

  // Apply text attributes to the button so that the subtext will appear
  // smaller and lighter than the rest of the title.
  NSMutableAttributedString* attributedString =
      [button.attributedTitle mutableCopy];
  NSFont* subtextFont =
      [NSFontManager.sharedFontManager convertFont:button.font
                                            toSize:button.font.pointSize - 1];
  NSRange labelRange = NSMakeRange(0, label.length);
  NSRange subtextRange =
      NSMakeRange(buttonTitle.length - subtext.length, subtext.length);
  [attributedString addAttribute:NSForegroundColorAttributeName
                           value:NSColor.whiteColor
                           range:labelRange];
  [attributedString addAttribute:NSForegroundColorAttributeName
                           value:[self touchBarSubtextColor]
                           range:subtextRange];
  [attributedString addAttribute:NSFontAttributeName
                           value:subtextFont
                           range:subtextRange];
  button.attributedTitle = attributedString;

  // The tag is used to store the suggestion index.
  button.tag = row;

  return button;
}

- (void)acceptCreditCard:(id)sender {
  _controller->AcceptSuggestion([sender tag]);
}

- (void)setIsCreditCardPopup:(bool)is_credit_card_popup {
  _is_credit_card_popup = is_credit_card_popup;
}

@end