protocol SafetyCheckTableViewControllerPresentationDelegate: AnyObject {
  // Called when the view controller is removed from its parent.
  func safetyCheckTableViewControllerDidRemove(_ controller: SafetyCheckTableViewController)
}
// Workaround to start the section identifier enum with the base value that's in
// shared ObjC code. Swift doesn't allow named constants in this context.
// Need to remember to use |settingsRawValue| instead of |rawValue|.
protocol SettingsEnum: RawRepresentable where RawValue == Int {}
extension SettingsEnum {
  var settingsRawValue: Int {
    // TODO(crbug.com/1285900): This fails on offical builders when trying
    // to use the ObjC constant. Hard-code it as a workaround.
    return self.rawValue + 10  // kSectionIdentifierEnumZero
  }
}
  // MARK: Private enums
  enum SettingsIdentifier: Int, SettingsEnum {
    case checkTypes
    case checkStart
  }
  // MARK: Private members
  // Current state of array of items that form the safety check.
  private var checkTypesItems: [TableViewItem]? {
    didSet {
      reloadData()
    }
  }
  // Header for the safety check page.
  private var safetyCheckHeaderItem: TableViewLinkHeaderFooterItem? {
    didSet {
      reloadData()
    }
  }
  // Current display state of the check start item.
  private var checkStartItem: TableViewItem? {
    didSet {
      reloadData()
    }
  }
  // Footer with timestamp for the safety check page.
  private var safetyCheckFooterItem: TableViewLinkHeaderFooterItem? {
    didSet {
      reloadData()
    }
  }
  override func viewDidLoad() {
    super.viewDidLoad()
    self.tableView.accessibilityIdentifier = SafetyCheckTableViewController.accessibilityIdentifier
    self.title = L10nUtils.string(messageId: IDS_OPTIONS_ADVANCED_SECTION_TITLE_SAFETY_CHECK)
  }
  // MARK: SafetyCheckConsumer
  func setCheck(_ items: [TableViewItem]) {
    checkTypesItems = items
  }
  func setSafetyCheckHeaderItem(_ item: TableViewLinkHeaderFooterItem!) {
    safetyCheckHeaderItem = item
  }
  func setCheckStart(_ item: TableViewItem!) {
    checkStartItem = item
  }
  func setTimestampFooterItem(_ item: TableViewLinkHeaderFooterItem!) {
    safetyCheckFooterItem = item
  }
  // MARK: ChromeTableViewController
  override func loadModel() {
    super.loadModel()
    if let items = self.checkTypesItems {
      let checkTypes = SettingsIdentifier.checkTypes.settingsRawValue
      if items.count != 0 {
        self.tableViewModel.addSection(withIdentifier: checkTypes)
        for item in items {
          self.tableViewModel.add(item, toSectionWithIdentifier: checkTypes)
        }
      }
      if let item = self.safetyCheckHeaderItem {
        self.tableViewModel.setHeader(item, forSectionWithIdentifier: checkTypes)
      }
    }
    if let item = self.checkStartItem {
      let checkStart = SettingsIdentifier.checkStart.settingsRawValue
      self.tableViewModel.addSection(withIdentifier: checkStart)
      self.tableViewModel.add(item, toSectionWithIdentifier: checkStart)
      if let footerItem = self.safetyCheckFooterItem {
        self.tableViewModel.setFooter(footerItem, forSectionWithIdentifier: checkStart)
      }
    }
  }
  // MARK: UIViewController
  override func didMove(toParent parent: UIViewController?) {
    super.didMove(toParent: parent)
    if parent == nil {
      self.presentationDelegate?.safetyCheckTableViewControllerDidRemove(self)
    }
  }
  // MARK: UITableViewDelegate
  override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    super.tableView(tableView, didSelectRowAt: indexPath)
    let item = self.tableViewModel.item(at: indexPath)
    self.serviceDelegate?.didSelect(item)
    tableView.deselectRow(at: indexPath, animated: false)
  }
  override func tableView(
    _ tableView: UITableView,
    shouldHighlightRowAt indexPath: IndexPath
  ) -> Bool {
    let item = self.tableViewModel.item(at: indexPath)
    return self.serviceDelegate?.isItemClickable(item) ?? false
  }
  // MARK: UITabelViewDataSource
  override func tableView(
    _ tableView: UITableView,
    cellForRowAt indexPath: IndexPath
  ) -> UITableViewCell {
    let cell = super.tableView(tableView, cellForRowAt: indexPath)
    let tableItem = self.tableViewModel.item(at: indexPath)
    if let delegate = self.serviceDelegate,
      let item = tableItem,
      delegate.isItemWithErrorInfo(item),
      let settingsCheckCell = cell as? SettingsCheckCell
    {
      settingsCheckCell.infoButton.tag = item.type
      settingsCheckCell.infoButton.addTarget(
        self,
        action: #selector(didTapErrorInfoButton),
        for: .touchUpInside)
    }
    return cell
  }
  // MARK: Private
  // Called when user tapped on the information button of an item. Shows popover with detailed
  // description of an error if needed.
    self.serviceDelegate?.infoButtonWasTapped(sender, usingItemType: sender.tag)
  }
}


class OverflowMenuHostingController<Content>: UIHostingController<Content> where Content: View {
  // This should be the width of the share sheet in compact height environments.
  let compactHeightSheetWidth: CGFloat = 568
  let uiConfiguration: OverflowMenuUIConfiguration
  init(rootView: Content, uiConfiguration: OverflowMenuUIConfiguration) {
    self.uiConfiguration = uiConfiguration
    super.init(rootView: rootView)
  }
  required init(coder aDecoder: NSCoder) {
    fatalError("Not using storyboards")
  }
  var compactHeightPreferredContentSize: CGSize {
    return CGSize(
      width: compactHeightSheetWidth, height: presentingViewController?.view.bounds.size.height ?? 0
    )
  }
  override func viewDidLoad() {
    super.viewDidLoad()
    // Only set the preferredContentSize in height == compact because otherwise
    // it overrides the default size of the menu on iPad.
    preferredContentSize =
      traitCollection.verticalSizeClass == .compact ? compactHeightPreferredContentSize : .zero
    uiConfiguration.presentingViewControllerHorizontalSizeClass =
      presentingViewController?.traitCollection.horizontalSizeClass == .regular
      ? .regular : .compact
    uiConfiguration.presentingViewControllerVerticalSizeClass =
      presentingViewController?.traitCollection.verticalSizeClass == .regular ? .regular : .compact
  }
  override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
    super.traitCollectionDidChange(previousTraitCollection)
    // Only set the preferredContentSize in height == compact because otherwise
    // it overrides the default size of the menu on iPad.
    preferredContentSize =
      traitCollection.verticalSizeClass == .compact ? compactHeightPreferredContentSize : .zero
    uiConfiguration.presentingViewControllerHorizontalSizeClass =
      presentingViewController?.traitCollection.horizontalSizeClass == .regular
      ? .regular : .compact
    uiConfiguration.presentingViewControllerVerticalSizeClass =
      presentingViewController?.traitCollection.verticalSizeClass == .regular ? .regular : .compact
  }
}


  weak var metricsHandler: PopupMenuMetricsHandler?
  var body: some View {
    Section(
      content: {
        ForEach(actionGroup.actions) { action in
          OverflowMenuActionRow(action: action, metricsHandler: metricsHandler)
        }
      },
      header: {
        Spacer()
          .frame(height: Dimensions.headerFooterHeight)
          .listRowInsets(EdgeInsets())
          .accessibilityHidden(true)
      },
      footer: {
        if let actionFooter = actionGroup.footer {
          OverflowMenuFooterRow(footer: actionFooter)
        } else {
          Spacer()
            // Use `leastNonzeroMagnitude` to remove the footer. Otherwise,
            // it uses a default height.
            .frame(height: CGFloat.leastNonzeroMagnitude)
            .listRowInsets(EdgeInsets())
            .accessibilityHidden(true)
        }
      })
  }
}


struct OverflowMenuDestinationButton: ButtonStyle {
  enum Dimensions {
    static let cornerRadius: CGFloat = 13
    /// The padding on either side of the text in the vertical layout,
    /// separating it from the next view.
    static let verticalLayoutTextPadding: CGFloat = 3
    /// The padding on either side of the view in the horizontal layout,
    /// separating it from the next view.
    static let horizontalLayoutViewPadding: CGFloat = 16
    /// The padding around the icon and inside the background in horizontal
    /// layout.
    static let horizontalLayoutIconPadding: CGFloat = 3
    /// The spacing between the icon and the text in horizontal layout.
    static let horizontalLayoutIconSpacing: CGFloat = 14
    /// The image width, which controls the width of the overall view.
    static let imageWidth: CGFloat = 54
    /// The size of the Symbol in the icon.
    static let iconSymbolSize: CGFloat = 26
    /// The width of the icon, used for positioning the unread badge over the
    /// corner.
    static let iconWidth: CGFloat = 30
    /// The width of the badge circle.
    static let badgeWidth: CGFloat = 10
    /// The width of the new label badge.
    static let newLabelBadgeWidth: CGFloat = 20
  }
  /// The destination for this view.
  var destination: OverflowMenuDestination
  /// The layout parameters for this view.
  var layoutParameters: OverflowMenuDestinationView.LayoutParameters
  weak var metricsHandler: PopupMenuMetricsHandler?
  func makeBody(configuration: Configuration) -> some View {
    let destinationWidth = OverflowMenuDestinationButton.destinationWidth(
      forLayoutParameters: layoutParameters)
    Group {
      switch layoutParameters {
      case .vertical:
        VStack {
          icon(configuration: configuration)
          text
        }
        .frame(width: destinationWidth)
      case .horizontal:
        HStack {
          icon(configuration: configuration)
          Spacer().frame(width: Dimensions.horizontalLayoutIconSpacing)
          text
        }
        .frame(width: destinationWidth, alignment: .leading)
        // In horizontal layout, the item itself has leading and trailing
        // padding.
        .padding([.leading, .trailing], Dimensions.horizontalLayoutViewPadding)
      }
    }
    .contentShape(Rectangle())
  }
  /// Background color for the icon.
  func backgroundColor(configuration: Configuration) -> Color {
    return configuration.isPressed ? Color(.systemGray4) : .groupedSecondaryBackground
  }
  /// View representing the background of the icon.
  func iconBackground(configuration: Configuration) -> some View {
    RoundedRectangle(cornerRadius: Dimensions.cornerRadius)
      .foregroundColor(backgroundColor(configuration: configuration))
  }
  /// Icon for the destination.
  func icon(configuration: Configuration) -> some View {
    let interiorPadding: CGFloat
    let spacing: CGFloat
    switch layoutParameters {
    case .vertical(let iconSpacing, let iconPadding):
      spacing = iconSpacing
      interiorPadding = iconPadding
    case .horizontal:
      spacing = 0
      interiorPadding = Dimensions.horizontalLayoutIconPadding
    }
    let image =
      (destination.systemSymbol
      ? Image(systemName: destination.symbolName) : Image(destination.symbolName)).renderingMode(
        .template)
    return iconBuilder(
      configuration: configuration, spacing: spacing, interiorPadding: interiorPadding, image: image
    )
  }
  var newBadgeOffsetX: CGFloat {
    return Dimensions.iconWidth - (Dimensions.newLabelBadgeWidth - 10)
  }
  var newBadgeOffsetY: CGFloat {
    return -Dimensions.iconWidth + (Dimensions.newLabelBadgeWidth - 10)
  }
  var circleBadge: some View {
    return Circle()
      .frame(width: Dimensions.badgeWidth, height: Dimensions.badgeWidth)
      .offset(
        x: Dimensions.iconWidth - (Dimensions.badgeWidth / 2),
        y: -Dimensions.iconWidth + (Dimensions.badgeWidth / 2))
  }
  /// Build the image to be displayed, based on the configuration of the item.
  /// TODO(crbug.com/1315544): Remove this once only the symbols are present.
  func iconBuilder(
    configuration: Configuration, spacing: CGFloat, interiorPadding: CGFloat, image: Image
  ) -> some View {
    let configuredImage =
      image
      .overlay {
        if destination.badge == .error {
          circleBadge.foregroundColor(.red500)
        } else if destination.badge == .promo {
          circleBadge.foregroundColor(.blue600)
        } else if destination.badge == .new {
          Image(systemName: "seal.fill")
            .resizable()
            .foregroundColor(.blue600)
            .frame(width: Dimensions.newLabelBadgeWidth, height: Dimensions.newLabelBadgeWidth)
            .offset(x: newBadgeOffsetX, y: newBadgeOffsetY)
            .overlay {
              if let newLabelString = L10nUtils.stringWithFixup(
                messageId: IDS_IOS_NEW_LABEL_FEATURE_BADGE)
              {
                Text(newLabelString)
                  .font(.system(size: 10, weight: .bold, design: .rounded))
                  .offset(x: newBadgeOffsetX, y: newBadgeOffsetY)
                  .scaledToFit()
                  .foregroundColor(.primaryBackground)
              }
            }
        }
      }
      .frame(width: Dimensions.imageWidth, height: Dimensions.imageWidth)
      .padding(interiorPadding)
      .background(iconBackground(configuration: configuration))
      .padding([.leading, .trailing], spacing)
      // Without explicitly removing the image from accessibility,
      // VoiceOver will occasionally read out icons it thinks it can
      // recognize.
      .accessibilityHidden(true)
    configuredImage
      .foregroundColor(.blue600).imageScale(.medium).font(
        Font.system(size: Dimensions.iconSymbolSize, weight: .medium))
  }
  /// Text view for the destination.
  var text: some View {
    // Only the vertical layout has extra spacing around the text
    let textSpacing: CGFloat
    let maximumLines: Int?
    switch layoutParameters {
    case .vertical:
      textSpacing = Dimensions.verticalLayoutTextPadding
      maximumLines = nil
    case .horizontal:
      textSpacing = 0
      maximumLines = 1
    }
    return Text(destination.name)
      .font(.caption2)
      .padding([.leading, .trailing], textSpacing)
      .multilineTextAlignment(.center)
      .lineLimit(maximumLines)
  }
  static public func destinationWidth(
    forLayoutParameters layoutParameters: OverflowMenuDestinationView.LayoutParameters
  ) -> CGFloat {
    switch layoutParameters {
    case .vertical(let iconSpacing, let iconPadding):
      return Dimensions.imageWidth + 2 * iconSpacing + 2 * iconPadding
    case .horizontal(let itemWidth):
      return itemWidth
    }
  }
}
/// A view displaying a single destination.
struct OverflowMenuDestinationView: View {
  /// Parameters providing any necessary data to layout the view.
  enum LayoutParameters {
    /// The destination has an icon on top and text below.
    /// There is `iconSpacing` to either side of the icon, and `iconPadding`
    /// around the icon and inside the background.
    case vertical(iconSpacing: CGFloat, iconPadding: CGFloat)
    /// The destination has an icon on the left and text on the right. Here
    /// the view will have a fixed overall `itemWidth`.
    case horizontal(itemWidth: CGFloat)
  }
  enum AccessibilityIdentifier {
    /// The addition to the `accessibilityIdentfier` for this element if it
    /// has an error badge.
    static let errorBadge = "errorBadge"
    /// The addition to the `accessibilityIdentfier` for this element if it
    /// has a promo badge.
    static let promoBadge = "promoBadge"
    /// The addition to the `accessibilityIdentfier` for this element if it
    /// has a "New" badge.
    static let newBadge = "newBadge"
  }
  /// The destination for this view.
  var destination: OverflowMenuDestination
  /// The layout parameters for this view.
  var layoutParameters: LayoutParameters
  weak var metricsHandler: PopupMenuMetricsHandler?
  var body: some View {
    Button(
      action: {
        metricsHandler?.popupMenuTookAction()
        destination.handler()
      },
      label: {
        EmptyView()
      }
    )
    .accessibilityIdentifier(accessibilityIdentifier)
    .accessibilityLabel(Text(accessibilityLabel))
    .buttonStyle(
      OverflowMenuDestinationButton(destination: destination, layoutParameters: layoutParameters))
  }
  var accessibilityLabel: String {
    return [
      destination.name,
      destination.badge == .error
        ? L10nUtils.stringWithFixup(
          messageId: IDS_IOS_ITEM_ACCOUNT_ERROR_BADGE_ACCESSIBILITY_HINT) : nil,
      destination.badge == .promo
        ? L10nUtils.stringWithFixup(messageId: IDS_IOS_NEW_ITEM_ACCESSIBILITY_HINT) : nil,
      destination.badge == .new
        ? L10nUtils.stringWithFixup(messageId: IDS_IOS_TOOLS_MENU_CELL_NEW_FEATURE_BADGE) : nil,
    ].compactMap { $0 }.joined(separator: ", ")
  }
  var accessibilityIdentifier: String {
    return [
      destination.accessibilityIdentifier,
      destination.badge == .error ? AccessibilityIdentifier.errorBadge : nil,
      destination.badge == .promo ? AccessibilityIdentifier.promoBadge : nil,
      destination.badge == .new ? AccessibilityIdentifier.newBadge : nil,
    ].compactMap { $0 }.joined(separator: "-")
  }
}


  /// The size of the symbols.
  static let symbolSize: CGFloat = 18
  static let symbolImageFrameLength: CGFloat = 30
  static let symbolImagePadding: CGFloat = -4
  /// The size of the "N" IPH icon.
  static let newLabelIconWidth: CGFloat = 15
  weak var metricsHandler: PopupMenuMetricsHandler?
  var body: some View {
    Button(
      action: {
        metricsHandler?.popupMenuTookAction()
        action.handler()
      },
      label: {
        HStack {
          Text(action.name).lineLimit(1)
          if action.displayNewLabelIcon {
            newLabelIconView()
              .accessibilityIdentifier("overflowRowIPHBadgeIdentifier")
          }
          Spacer()
          imageBuilder().frame(
            width: OverflowMenuActionRow.symbolImageFrameLength,
            height: OverflowMenuActionRow.symbolImageFrameLength, alignment: .center
          )
          // Without explicitly removing the image from accessibility,
          // VoiceOver will occasionally read out icons it thinks it can
          // recognize.
          .accessibilityHidden(true)
        }
        .contentShape(Rectangle())
      }
    ).padding([.trailing], OverflowMenuActionRow.symbolImagePadding)
      .accessibilityIdentifier(action.accessibilityIdentifier)
      .disabled(!action.enabled || action.enterpriseDisabled)
      .accentColor(.textPrimary)
      .listRowSeparatorTint(.overflowMenuSeparator)
  }
  /// Build the image to be displayed, based on the configuration of the item.
  /// TODO(crbug.com/1315544): Remove this once only the symbols are present.
  func imageBuilder() -> some View {
    actionSymbol().font(Font.system(size: OverflowMenuActionRow.symbolSize, weight: .medium))
      .imageScale(
        .medium)
  }
  func actionSymbol() -> Image {
    let symbol =
      action.systemSymbol ? Image(systemName: action.symbolName) : Image(action.symbolName)
    if action.monochromeSymbol {
      return symbol.symbolRenderingMode(.monochrome)
    }
    return symbol
  }
  // Returns the "N" IPH icon view.
  func newLabelIconView() -> some View {
    return Image(systemName: "seal.fill")
      .resizable()
      .foregroundColor(.blue600)
      .frame(
        width: OverflowMenuActionRow.newLabelIconWidth,
        height: OverflowMenuActionRow.newLabelIconWidth
      )
      .overlay {
        if let newLabelString = L10nUtils.stringWithFixup(
          messageId: IDS_IOS_NEW_LABEL_FEATURE_BADGE)
        {
          Text(newLabelString)
            .font(.system(size: 10, weight: .bold, design: .rounded))
            .scaledToFit()
            .foregroundColor(.primaryBackground)
        }
      }
  }
}


import SwiftUI
extension Color {
  static var overflowMenuSeparator: Color {
    let uiColor = UIColor { traitCollection in
      let color =
        traitCollection.userInterfaceStyle == .dark
        ? UIColor(named: kTertiaryBackgroundColor) : UIColor(named: kGrey200Color)
      return color ?? .separator
    }
    if #available(iOS 15, *) {
      return Color(uiColor: uiColor)
    } else {
      return Color(uiColor)
    }
  }
}


  public static func makeViewController(
    withModel model: OverflowMenuModel,
    uiConfiguration: OverflowMenuUIConfiguration,
    metricsHandler: PopupMenuMetricsHandler
  ) -> UIViewController {
    return OverflowMenuHostingController(
      rootView: OverflowMenuView(
        model: model, uiConfiguration: uiConfiguration, metricsHandler: metricsHandler),
      uiConfiguration: uiConfiguration)
  }
}


    // Whether the destination should show an error badge.
    case error
    // Whether the destination should show a promo badge.
    case promo
    // Whether the destination should show a "New" badge
    // indicating a new destination.
    case new
    case none
  }
  public var badge: BadgeType = .none
  /// The uniquely-identifying overflow_menu::Destination of the destination.
  public var destination: Int = 0
}


  ) {
    self.link = link
    self.image = Image(uiImage: image)
    super.init(
      name: name, symbolName: "", systemSymbol: true, monochromeSymbol: true,
      accessibilityIdentifier: accessibilityIdentifier,
      enterpriseDisabled: false, displayNewLabelIcon: false,
      handler: handler)
  }
}


  /// The destinations for the overflow menu.
  public var destinations: [OverflowMenuDestination]
  /// The action groups for the overflow menu.
  public var actionGroups: [OverflowMenuActionGroup]
  public init(
    destinations: [OverflowMenuDestination],
    actionGroups: [OverflowMenuActionGroup]
  ) {
    self.destinations = destinations
    self.actionGroups = actionGroups
  }
}


  static public func numDestinationsVisibleWithoutHorizontalScrolling(
    forScreenWidth width: CGFloat, forContentSizeCategory sizeCategory: UIContentSizeCategory
  ) -> CGFloat {
    let contentSizeCategory = ContentSizeCategory(sizeCategory) ?? .medium
    return OverflowMenuDestinationList.numDestinationsVisibleWithoutHorizontalScrolling(
      forScreenWidth: width, forSizeCategory: contentSizeCategory)
  }
  public init(
    presentingViewControllerHorizontalSizeClass: UIUserInterfaceSizeClass,
    presentingViewControllerVerticalSizeClass: UIUserInterfaceSizeClass
  ) {
    self.presentingViewControllerHorizontalSizeClass =
      UserInterfaceSizeClass(presentingViewControllerHorizontalSizeClass) ?? .compact
    self.presentingViewControllerVerticalSizeClass =
      UserInterfaceSizeClass(presentingViewControllerVerticalSizeClass) ?? .compact
  }
}


struct OverflowMenuActionList: View {
  enum Constants {
    // The minimum row height for any row in the list.
    static let minimumRowHeight: CGFloat = 48
  }
  /// The list of action groups for this view.
  var actionGroups: [OverflowMenuActionGroup]
  /// The metrics handler to alert when the user takes metrics actions.
  weak var metricsHandler: PopupMenuMetricsHandler?
  var body: some View {
    List {
      ForEach(actionGroups) { actionGroup in
        OverflowMenuActionSection(actionGroup: actionGroup, metricsHandler: metricsHandler)
      }
    }
    .simultaneousGesture(
      DragGesture().onChanged({ _ in
        metricsHandler?.popupMenuScrolledVertically()
      })
    )
    .accessibilityIdentifier(kPopupMenuToolsMenuActionListId)
    .listStyle(InsetGroupedListStyle())
    // Allow sections to have very small headers controlling section spacing.
    .environment(\.defaultMinListHeaderHeight, 0)
    .environment(\.defaultMinListRowHeight, Constants.minimumRowHeight)
  }
}
/// Calls `onScroll` when the user performs a drag gesture over the content of the list.
struct ListScrollDetectionModifier: ViewModifier {
  let onScroll: () -> Void
  func body(content: Content) -> some View {
    content
      // For some reason, without this, user interaction is not forwarded to the list.
      .onTapGesture(perform: {})
      // Long press gestures are dismissed and `onPressingChanged` called with
      // `pressing` equal to `false` when the user performs a drag gesture
      // over the content, hence why this works. `DragGesture` cannot be used
      // here, even with a `simultaneousGesture` modifier, because it prevents
      // swipe-to-delete from correctly triggering within the list.
      .onLongPressGesture(
        perform: {},
        onPressingChanged: { pressing in
          if !pressing {
            onScroll()
          }
        })
  }
}


  /// Whether the action is disabled by enterprise policy.
  ) {
    self.name = name
    self.symbolName = symbolName
    self.systemSymbol = systemSymbol
    self.monochromeSymbol = monochromeSymbol
    self.accessibilityIdentifier = accessibilityIdentifier
    self.enterpriseDisabled = enterpriseDisabled
    self.displayNewLabelIcon = displayNewLabelIcon
    self.handler = handler
  }
}
// MARK: - Identifiable
extension OverflowMenuItem: Identifiable {
  public var id: String {
    return name
  }
}


struct OverflowMenuDestinationList: View {
  enum Constants {
    /// Padding breakpoints for each width. The ranges should be inclusive of
    /// the larger number. That is, a width of 320 should fall in the
    /// `(230, 320]` bucket.
    static let widthBreakpoints: [CGFloat] = [
      180, 230, 320, 400, 470, 560, 650,
    ]
    /// Array of the lower end of each breakpoint range.
    static let lowerWidthBreakpoints = [nil] + widthBreakpoints
    /// Array of the higher end of each breakpoint range.
    static let upperWidthBreakpoints = widthBreakpoints + [nil]
    /// Leading space on the first icon.
    static let iconInitialSpace: CGFloat = 16
    /// Range of spacing around icons; varies based on view width.
    static let iconSpacingRange: ClosedRange<CGFloat> = 9...13
    /// Range of icon paddings; varies based on view width.
    static let iconPaddingRange: ClosedRange<CGFloat> = 0...3
    /// When the dynamic text size is large, the width of each item is the
    /// screen width minus a fixed space.
    static let largeTextSizeSpace: CGFloat = 120
    /// Space above the list pushing them down from the grabber.
    static let topMargin: CGFloat = 20
    /// The name for the coordinate space of the scroll view, so children can
    /// find their positioning in the scroll view.
    static let coordinateSpaceName = "destinations"
  }
  /// `PreferenceKey` to track the leading offset of the scroll view.
  struct ScrollViewLeadingOffset: PreferenceKey {
    static var defaultValue: CGFloat = .greatestFiniteMagnitude
    static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
      value = min(value, nextValue())
    }
  }
  /// The current dynamic type size.
  var body: some View {
    VStack {
      Spacer(minLength: Constants.topMargin)
      GeometryReader { geometry in
        scrollView(in: geometry)
          .coordinateSpace(name: Constants.coordinateSpaceName)
          .accessibilityIdentifier(kPopupMenuToolsMenuTableViewId)
      }
    }
    .background(
      Color("destination_highlight_color").opacity(uiConfiguration.highlightDestinationsRow ? 1 : 0)
    )
    .animation(
      .linear(duration: kMaterialDuration3), value: uiConfiguration.highlightDestinationsRow
    )
    .onPreferenceChange(ScrollViewLeadingOffset.self) { newOffset in
      // Only alert the handler if scroll tracking has started.
      if let listOffset = listOffset,
        newOffset != listOffset
      {
        metricsHandler?.popupMenuScrolledHorizontally()
      }
      // Only update the offset if scroll tracking has started or the newOffset
      // is approximately 0 (this starts scroll tracking). In RTL mode, the
      // offset is not exactly 0, so a strict comparison won't work.
      if listOffset != nil || (listOffset == nil && abs(newOffset) < 1e-9) {
        listOffset = newOffset
      }
    }
  }
  private func scrollView(in geometry: GeometryProxy) -> some View {
    ScrollViewReader { proxy in
      ScrollView(.horizontal, showsIndicators: false) {
        let spacing = OverflowMenuDestinationList.destinationSpacing(
          forScreenWidth: geometry.size.width)
        let layoutParameters = OverflowMenuDestinationList.layoutParameters(
          forScreenWidth: geometry.size.width, forSizeCategory: sizeCategory)
        let alignment: VerticalAlignment = sizeCategory >= .accessibilityMedium ? .center : .top
        ZStack {
          HStack(alignment: alignment, spacing: 0) {
            // Make sure the space to the first icon is constant, so add extra
            // spacing before the first item.
            Spacer().frame(width: Constants.iconInitialSpace - spacing.iconSpacing)
            ForEach(destinations) { destination in
              OverflowMenuDestinationView(
                destination: destination, layoutParameters: layoutParameters,
                metricsHandler: metricsHandler
              ).id(destination.destination)
            }
          }
          GeometryReader { innerGeometry in
            let frame = innerGeometry.frame(in: .named(Constants.coordinateSpaceName))
            let parentWidth = geometry.size.width
            // When the view is RTL, the offset should be calculated from the
            // right edge.
            let offset = layoutDirection == .leftToRight ? frame.minX : parentWidth - frame.maxX
            Color.clear
              .preference(key: ScrollViewLeadingOffset.self, value: offset)
          }
        }
      }
      .onAppear {
        if layoutDirection == .rightToLeft {
          proxy.scrollTo(destinations.first?.destination)
        }
        uiConfiguration.destinationListScreenFrame = geometry.frame(in: .global)
      }
    }
  }
  /// Finds the lower and upper breakpoint above and below `width`.
  ///
  /// Returns `nil` for either end if `width` is above or below the largest or
  /// smallest breakpoint.
  private static func findBreakpoints(forScreenWidth width: CGFloat) -> (CGFloat?, CGFloat?) {
    // Add extra sentinel values to either end of the breakpoint array.
    let x = zip(
      Constants.lowerWidthBreakpoints, Constants.upperWidthBreakpoints
    )
    // There should only be one item where the provided width is both greater
    // than the lower end and less than the upper end.
    .filter {
      (low, high) in
      // Check if width is above the low value, or default to true if low is
      // nil.
      let aboveLow = low.map { value in width > value } ?? true
      let belowHigh = high.map { value in width <= value } ?? true
      return aboveLow && belowHigh
    }.first
    return x ?? (nil, nil)
  }
  /// Calculates the icon spacing and padding for the given `width`.
  private static func destinationSpacing(forScreenWidth width: CGFloat) -> (
    iconSpacing: CGFloat, iconPadding: CGFloat
  ) {
    let (lowerBreakpoint, upperBreakpoint) = findBreakpoints(
      forScreenWidth: width)
    // If there's no lower breakpoint, `width` is lower than the lowest, so
    // default to the lower bound of the ranges.
    guard let lowerBreakpoint = lowerBreakpoint else {
      return (
        iconSpacing: Constants.iconSpacingRange.lowerBound,
        iconPadding: Constants.iconPaddingRange.lowerBound
      )
    }
    // If there's no upper breakpoint, `width` is higher than the highest, so
    // default to the higher bound of the ranges.
    guard let upperBreakpoint = upperBreakpoint else {
      return (
        iconSpacing: Constants.iconSpacingRange.upperBound,
        iconPadding: Constants.iconPaddingRange.upperBound
      )
    }
    let breakpointRange = lowerBreakpoint...upperBreakpoint
    let iconSpacing = mapNumber(
      width, from: breakpointRange, to: Constants.iconSpacingRange)
    let iconPadding = mapNumber(
      width, from: breakpointRange, to: Constants.iconPaddingRange)
    return (iconSpacing: iconSpacing, iconPadding: iconPadding)
  }
  private static func layoutParameters(
    forScreenWidth width: CGFloat, forSizeCategory sizeCategory: ContentSizeCategory
  ) -> OverflowMenuDestinationView.LayoutParameters {
    let spacing = OverflowMenuDestinationList.destinationSpacing(forScreenWidth: width)
    return sizeCategory >= .accessibilityMedium
      ? .horizontal(itemWidth: width - Constants.largeTextSizeSpace)
      : .vertical(
        iconSpacing: spacing.iconSpacing,
        iconPadding: spacing.iconPadding)
  }
  public static func numDestinationsVisibleWithoutHorizontalScrolling(
    forScreenWidth width: CGFloat, forSizeCategory sizeCategory: ContentSizeCategory
  )
    -> CGFloat
  {
    let layoutParameters = OverflowMenuDestinationList.layoutParameters(
      forScreenWidth: width, forSizeCategory: sizeCategory)
    let destinationWidth = OverflowMenuDestinationButton.destinationWidth(
      forLayoutParameters: layoutParameters)
    return (width / destinationWidth).rounded(.up)
  }
  /// Maps the given `number` from its relative position in `inRange` to its
  /// relative position in `outRange`.
  private static func mapNumber<F: FloatingPoint>(
    _ number: F, from inRange: ClosedRange<F>, to outRange: ClosedRange<F>
  ) -> F {
    let scalingFactor =
      (outRange.upperBound - outRange.lowerBound)
      / (inRange.upperBound - inRange.lowerBound)
    return (number - inRange.lowerBound) * scalingFactor + outRange.lowerBound
  }
}


struct OverflowMenuView: View {
  enum Dimensions {
    static let destinationListHeight: CGFloat = 123
  }
  var model: OverflowMenuModel
  var uiConfiguration: OverflowMenuUIConfiguration
  weak var metricsHandler: PopupMenuMetricsHandler?
  var body: some View {
    VStack(
      alignment: .leading,
      // Leave no spaces above or below Divider, the two other sections will
      // include proper spacing.
      spacing: 0
    ) {
      OverflowMenuDestinationList(
        destinations: model.destinations, metricsHandler: metricsHandler,
        uiConfiguration: uiConfiguration
      ).frame(height: Dimensions.destinationListHeight)
      Divider()
      OverflowMenuActionList(actionGroups: model.actionGroups, metricsHandler: metricsHandler)
      // Add a spacer on iPad to make sure there's space below the list.
      if uiConfiguration.presentingViewControllerHorizontalSizeClass == .regular
        && uiConfiguration.presentingViewControllerVerticalSizeClass == .regular
      {
        Spacer()
      }
    }.background(Color(.systemGroupedBackground).edgesIgnoringSafeArea(.all))
  }
}


  /// The footer at bottom.
  public var footer: OverflowMenuFooter?
  public init(groupName: String, actions: [OverflowMenuAction], footer: OverflowMenuFooter?) {
    self.groupName = groupName
    self.actions = actions
    self.footer = footer
  }
}
// MARK: - Identifiable
extension OverflowMenuActionGroup: Identifiable {
  public var id: String {
    return groupName
  }
}


import SwiftUI
/// A view that displays a footer in the overflow menu.
struct OverflowMenuFooterRow: View {
  enum Dimensions {
    /// Space between elements on the icon line.
    static let iconLineSpacing: CGFloat = 12
    /// The vertical spacing between icon line, label (name) and link.
    static let verticalSpacing: CGFloat = 3
    /// The extra vertical above and below icon line.
    static let iconLineExtraVerticalSpacing: CGFloat = 9
    // The height of the icon line dividers.
    static let iconLineDividerHeight: CGFloat = 1
  }
  /// The footer for this row.
  var body: some View {
    VStack(
      alignment: .center,
      spacing: Dimensions.verticalSpacing
    ) {
      HStack(
        alignment: .center,
        spacing: Dimensions.iconLineSpacing
      ) {
        Rectangle()
          .foregroundColor(.overflowMenuSeparator)
          .frame(height: Dimensions.iconLineDividerHeight)
        footer.image
          .fixedSize()
          .foregroundColor(.grey500)
        Rectangle()
          .foregroundColor(.overflowMenuSeparator)
          .frame(height: Dimensions.iconLineDividerHeight)
      }
      .padding([.top], Dimensions.iconLineExtraVerticalSpacing)
      Text(footer.name)
        .padding([.top], Dimensions.iconLineExtraVerticalSpacing)
        .font(.footnote)
      Text(footer.link)
        .font(.caption2)
        .foregroundColor(.chromeBlue)
        .onTapGesture(perform: footer.handler)
        .accessibilityIdentifier(footer.accessibilityIdentifier)
    }
    // Group all children together so VoiceOver doesn't have to read the two
    // text labels individually.
    .accessibilityElement(children: .combine)
    .accessibilityAction(.default, footer.handler)
  }
}


Color+Chrome

import SwiftUI
// Adds easy SwiftUI access to the Chrome color palette.
extension Color {
  /// The background color.
  public static var background: Color {
    return Color(kBackgroundColor)
  }
  /// The primary text color.
  public static var textPrimary: Color {
    return Color(kTextPrimaryColor)
  }
  /// The secondary text color.
  public static var textSecondary: Color {
    return Color(kTextSecondaryColor)
  }
  /// The tertiary text color.
  public static var textTertiary: Color {
    return Color(kTextTertiaryColor)
  }
  /// The quaternary text color.
  public static var textQuaternary: Color {
    return Color(kTextQuaternaryColor)
  }
  /// The tertiary background color
  public static var tertiaryBackground: Color {
    return Color(kTertiaryBackgroundColor)
  }
  /// The updated tertiary background color
  public static var updatedTertiaryBackground: Color {
    return Color(kUpdatedTertiaryBackgroundColor)
  }
  /// The primary grouped background color.
  public static var groupedPrimaryBackground: Color {
    return Color(kGroupedPrimaryBackgroundColor)
  }
  /// The secondary grouped background color.
  public static var groupedSecondaryBackground: Color {
    return Color(kGroupedSecondaryBackgroundColor)
  }
  /// The primary background color.
  public static var primaryBackground: Color {
    return Color(kPrimaryBackgroundColor)
  }
  /// The secondary background color.
  public static var secondaryBackground: Color {
    return Color(kSecondaryBackgroundColor)
  }
  /// The grey200 color.
  public static var grey200: Color {
    return Color(kGrey200Color)
  }
  /// The grey300 color.
  public static var grey300: Color {
    return Color(kGrey300Color)
  }
  /// The grey500 color
  public static var grey500: Color {
    return Color(kGrey500Color)
  }
  /// The grey700 color
  public static var grey700: Color {
    return Color(kGrey700Color)
  }
  /// The blue color.
  public static var chromeBlue: Color {
    return Color(kBlueColor)
  }
  /// The blue halo color.
  public static var blueHalo: Color {
    return Color(kBlueHaloColor)
  }
  /// The blue500 color.
  public static var blue500: Color {
    return Color(kBlue500Color)
  }
  /// The blue600 color.
  public static var blue600: Color {
    return Color(kBlue600Color)
  }
  /// The red500 color.
  public static var red500: Color {
    return Color(kRed500Color)
  }
  /// The table row view highlight color.
  public static var tableRowViewHighlight: Color {
    return Color(kTableViewRowHighlightColor)
  }
  /// The table view separator color.
  public static var separator: Color {
    return Color(kSeparatorColor)
  }
  /// The toolbar shadow color.
  public static var toolbarShadow: Color {
    return Color(kToolbarShadowColor)
  }
}


import Struct
import XCTest
class StructTest: XCTestCase {
  func testStruct() throws {
    var goodFoo = Foolean()
    var badFoo = Foolean()
    // Test calling static method from struct.
    goodFoo.value = true
    goodFoo.description = Foolean.GetDescriptionForValue(true)
    badFoo.value = false
    badFoo.description = Foolean.GetDescriptionForValue(true)
    // Test passing object defined in C++ and initialized in Swift to top level C++ functions.
    XCTAssertTrue(IsFooleanValid(goodFoo))
    XCTAssertFalse(IsFooleanValid(badFoo))
  }
}


import Enums
import XCTest
class EnumTest: XCTestCase {
  func testEnums() throws {
    // Explicitly typed.
    var color: Color = kBlue
    color = kYellow
    XCTAssertEqual(color, kYellow, "Typed enum doesn't match")
    // Implicit type. |x| is an |Int|.
    let x = kThree
    XCTAssertEqual(x, kThree, "Implicitly typed enum doesn't match")
    // Implicit type, |anotherColor| is a |Color|.
    let anotherColor = kYellow
    XCTAssertEqual(anotherColor, kYellow, "")
    XCTAssertNotEqual(anotherColor, kBlue)
  }
  func testClassEnum() throws {
    let pet: Pet = Pet.goat
    XCTAssertEqual(pet, Pet.goat, "")
    XCTAssertNotEqual(pet, Pet.dogcow, "")
    XCTAssertNotEqual(Pet.goat, Pet.dogcow)
  }
}


import Classes
import UIKit
import XCTest
class InlinedClassTest: XCTestCase {
  func testInlined() throws {
    var obj = InlinedClass()
    var num: Int32 = obj.AddTo(10)
    XCTAssertEqual(num, 10, "Addition didn't work correctly")
    num = obj.AddTo(5)
    XCTAssertEqual(num, 15, "Addition didn't work correctly")
    var composed = ComposedClass()
    composed.Increment(2)
    let result: Int32 = composed.Increment(8)
    XCTAssertEqual(result, 10, "Stack based class didn't work")
  }
}


import Classes
import UIKit
import XCTest
class OutlinedClassTest: XCTestCase {
  func testOutlined() throws {
    var outlined = Outlined()
    XCTAssertEqual(outlined.OutlinedAddition(8), 8, "Outlined method broken")
    XCTAssertEqual(outlined.OutlinedAddition(2), 10, "Outlined method broken")
  }
  func testOutlinedInitalCtor() throws {
    var outlined = Outlined(10)
    XCTAssertEqual(outlined.OutlinedAddition(8), 18, "Outlined method broken")
    XCTAssertEqual(outlined.OutlinedAddition(2), 20, "Outlined method broken")
  }
}


import Classes
import XCTest
class PolymorphismTest: XCTestCase {
  func testBasicInheritance() throws {
    #if swift(<5.7)
      var rect = Rectangle(10, 10)
      XCTAssertEqual(rect.Area(), 100)
      XCTAssertEqual(rect.NumberOfSides(), 4)
      var square = Square(5)
      XCTAssertEqual(square.Area(), 25)
      XCTAssertEqual(square.NumberOfSides(), 4)
      var triangle = Triangle(10, 10)
      XCTAssertEqual(triangle.Area(), 50)
      XCTAssertEqual(triangle.NumberOfSides(), 3)
    #endif
  }
  // The primary bug for inherited methods not working is
  // https://github.com/apple/swift/issues/55192. That covers several of
  // these tests.
  func testInheritedMethods_noCompile() throws {
    // Test calling a public method defined in the public base class.
    // DOESN'T COMPILE: value of type 'Rectangle' has no member 'HasSides'
    // CRASHES in 5.7-dev.
    // var rect = Rectangle(10, 10)
    // XCTAssertTrue(rect.HasSides())
  }
  func testRuntimePolymorphism_fails() throws {
    // MakeShape() creates a Triangle and returns the object as a Shape*.
    // let shape = MakeShape(10, 10)
    // DOES NOT WORK: executes the Shape implementation, not the Triangle
    // version, and thus fails the comparision (0 != 3)
    // XCTAssertEqual(shape!.pointee.NumberOfSides(), 3)
  }
  func testPureVirtualMethods_noCompile() throws {
    // MakeShape() creates a Triangle and returns the object as a Shape*.
    // let shape = MakeShape(10, 10)
    // DOES NOT COMPILE: undefined symbol Shape::Area() for lld.
    // XCTAssertEqual(shape!.pointee.Area(), 50)
  }
}


import Pointer
import XCTest
class ObjectPassingTest: XCTestCase {
  func testReferenceParameters() throws {
    let a = Object(10)
    let b = Object(20)
    let passer = ObjectPassing()
    XCTAssertEqual(a.GetValue(), 10)
    XCTAssertEqual(passer.AddReferences(a, b), 30)
  }
  func testPointerParameters() throws {
    var a = Object(10)
    var b = Object(20)
    let passer = ObjectPassing()
    XCTAssertEqual(a.GetValue(), 10)
    XCTAssertEqual(passer.AddPointers(&a, &b), 30)
  }
  func testMismatchedParameters() throws {
    // var obj = Object(10)
    // var str = "Hello"
    // let passer = ObjectPassing()
    // Correctly doesn't compile because the types don't match. Error is
    // "cannot convert value of type 'UnsafeMutablePointer<String>' to expected
    // argument type 'UnsafeMutablePointer<Object>'.
    // XCTAssertEqual(passer.AddPointers(&obj, &obj, &str), 60, "")
  }
  // Note: if this method returns `Int` instead of `Int32` the compiler
  // will crash (filed as https://github.com/apple/swift/issues/58458).
  // This has been fixed in ToT.
  // Note: prior to Swift 5.6, calling GetValue() (which is const) on these objects
  // results in a compiler error about calling immutable methods on a `let` object.
  // Omit this test on earlier Swift versions.
  func addObjects(one: Object, two: Object) -> Int32 {
    return one.GetValue() + two.GetValue()
  }
  func addPointerObjects(one: UnsafeMutablePointer<Object>, two: UnsafeMutablePointer<Object>)
    -> Int32
  {
    return one.pointee.GetValue() + two.pointee.GetValue()
  }
  func testPassToSwift() throws {
    var a = Object(10)
    var b = Object(20)
    XCTAssertEqual(addObjects(one: a, two: b), 30)
    XCTAssertEqual(addPointerObjects(one: &a, two: &b), 30)
  }
}


import Pointer
import UIKit
import XCTest
class PointerTest: XCTestCase {
  func testReturnedPointer() throws {
    var returner = PointerReturner()
    XCTAssertEqual(returner.Valid(), true, "Object not valid?")
    let intPtr = returner.IntegerPointer()!
    XCTAssertEqual(intPtr.pointee, 17, "Pointer-to-integer return broken")
  }
  func testReturnedObjectPointer() throws {
    var returner = PointerReturner()
    let ptr = returner.ObjectPointer()!
    XCTAssertEqual(ptr.pointee.Valid(), true, "Object returned by pointer not valid?")
    let intPtr = ptr.pointee.IntegerPointer()!
    XCTAssertEqual(intPtr.pointee, 17, "Pointer-to-integer returned from pointer-to-object broken")
  }
}


import Pointer
import UIKit
import XCTest
class UniquePointerTest: XCTestCase {
  func testReturnedObjectPointer() throws {
    var returner = ValueReturner()
    let object = returner.ObjectPointer()!
    XCTAssertEqual(object.pointee.IsValid(), true, "")
    // DOESN'T COMPILE: value of type 'Value' has no member 'GetValue'
    // in 5.7 official builds. http://crbug.com/1336937
    // XCTAssertEqual(object.pointee.GetValue(), 17, "")
  }
}


import Namespace
import UIKit
import XCTest
class NamespaceTest: XCTestCase {
  func testNamespaceClass() throws {
    // Non-namespaced class.
    let goat = Goat()
    XCTAssertEqual(goat.GetValue(), 7, "Values don't match")
    // Namespaced class with the same type name, verify the namespaced one
    // is the one created.
    let spaceGoat = space.Goat()
    spaceGoat.DoNothing()
    XCTAssertEqual(spaceGoat.GetValue(), 42, "Values don't match")
  }
  func testNamespaceTypedEnum_noCompile() throws {
    // namespaced typed enum.
    // DOESN'T COMPILE: 'Vehicle' has no member 'boat' (it does).
    // let vehicle = space.Vehicle.boat
  }
  func testNamespaceClassEnum() throws {
    // Use a namespaced class enum.
    // Compiles ONLY with Swift greater than version 5.6 (Xcode 13.3).
    let animal = space.Animal.goat
    XCTAssertEqual(animal, space.Animal.goat, "values don't match")
    XCTAssertNotEqual(animal, space.Animal.dog, "values don't match")
  }
  func testNestedNamespace() throws {
    let goat = outer.inner.NestedGoat()
    XCTAssertEqual(goat.GetValue(), 50, "values don't match")
  }
  func testClassEnumInOutNamespace_crashes() throws {
    // Test the enum class not in a namespace.
    let food = SameNameEnum.watermelon
    XCTAssertNotEqual(food, SameNameEnum.orange, "something broke")
    // Test the enum class in a namespace.
    // CRASHES in XCTAssertNotEqual()
    // In progress CL: https://github.com/apple/swift/pull/42494.
    // let moreFood = sameName.SameNameEnum.watermelon;
    // XCTAssertNotEqual(moreFood, sameName.SameNameEnum.orange, "something broke")
  }
}


import Foundation
import SwiftUI
import WidgetKit
struct SearchWidget: Widget {
  // Changing |kind| or deleting this widget will cause all installed instances of this widget to
  // stop updating and show the placeholder state.
  let kind: String = "SearchWidget"
  var body: some WidgetConfiguration {
    StaticConfiguration(kind: kind, provider: Provider()) { entry in
      SearchWidgetEntryView(entry: entry)
    }
    .configurationDisplayName(
      Text("IDS_IOS_WIDGET_KIT_EXTENSION_SEARCH_DISPLAY_NAME")
    )
    .description(Text("IDS_IOS_WIDGET_KIT_EXTENSION_SEARCH_DESCRIPTION"))
    .supportedFamilies([.systemSmall])
  }
}
struct SearchWidgetEntryView: View {
  var entry: Provider.Entry
  var body: some View {
    // We wrap this widget in a link on top of using `widgetUrl` so that the voice over will treat
    // the widget as one tap target. Without the wrapping, voice over treats the content within
    // the widget as multiple tap targets.
    Link(destination: WidgetConstants.SearchWidget.url) {
      ZStack {
        Color("widget_background_color")
          .unredacted()
        VStack(alignment: .leading, spacing: 0) {
          ZStack {
            RoundedRectangle(cornerRadius: 26)
              .frame(height: 52)
              .foregroundColor(Color("widget_search_bar_color"))
            HStack(spacing: 0) {
              Image("widget_chrome_logo")
                .clipShape(Circle())
                .padding(.leading, 8)
                .unredacted()
              Spacer()
            }
          }
          .frame(minWidth: 0, maxWidth: .infinity)
          .padding([.leading, .trailing], 11)
          .padding(.top, 16)
          Spacer()
          Text("IDS_IOS_WIDGET_KIT_EXTENSION_SEARCH_TITLE")
            .foregroundColor(Color("widget_text_color"))
            .fontWeight(.semibold)
            .font(.subheadline)
            .padding([.leading, .bottom, .trailing], 16)
        }
      }
    }
    .widgetURL(WidgetConstants.SearchWidget.url)
    .accessibility(
      label: Text("IDS_IOS_WIDGET_KIT_EXTENSION_SEARCH_A11Y_LABEL"))
  }
}


import Foundation
import SwiftUI
import WidgetKit
#if IOS_ENABLE_LOCKSCREEN_WIDGET
  #if IOS_AVAILABLE_LOCKSCREEN_WIDGET
    enum LockscreenLauncherWidgetType {
      case search, incognito, voiceSearch, dinoGame
      struct Configuration {
        let displayName: LocalizedStringKey, description: LocalizedStringKey, imageName: String,
          accessibilityLabel: LocalizedStringKey,
          widgetURL: URL
        var supportedFamilies: [WidgetFamily] {
          if #available(iOS 16, *) {
            return [.accessoryCircular]
          }
          return []
        }
      }
      var configuration: Configuration {
        switch self {
        case .search:
          return Configuration(
            displayName: "IDS_IOS_WIDGET_KIT_EXTENSION_LOCKSCREEN_LAUNCHER_SEARCH_DISPLAY_NAME",
            description: "IDS_IOS_WIDGET_KIT_EXTENSION_LOCKSCREEN_LAUNCHER_SEARCH_DESCRIPTION",
            imageName: "lockscreen_chrome_logo",
            accessibilityLabel:
              "IDS_IOS_WIDGET_KIT_EXTENSION_LOCKSCREEN_LAUNCHER_SEARCH_A11Y_LABEL",
            widgetURL: WidgetConstants.LockscreenLauncherWidget.searchUrl)
        case .incognito:
          return Configuration(
            displayName: "IDS_IOS_WIDGET_KIT_EXTENSION_LOCKSCREEN_LAUNCHER_INCOGNITO_DISPLAY_NAME",
            description: "IDS_IOS_WIDGET_KIT_EXTENSION_LOCKSCREEN_LAUNCHER_INCOGNITO_DESCRIPTION",
            imageName: "lockscreen_incognito_logo",
            accessibilityLabel:
              "IDS_IOS_WIDGET_KIT_EXTENSION_LOCKSCREEN_LAUNCHER_INCOGNITO_A11Y_LABEL",
            widgetURL: WidgetConstants.LockscreenLauncherWidget.incognitoUrl)
        case .voiceSearch:
          return Configuration(
            displayName:
              "IDS_IOS_WIDGET_KIT_EXTENSION_LOCKSCREEN_LAUNCHER_VOICESEARCH_DISPLAY_NAME",
            description: "IDS_IOS_WIDGET_KIT_EXTENSION_LOCKSCREEN_LAUNCHER_VOICESEARCH_DESCRIPTION",
            imageName: "lockscreen_voicesearch_logo",
            accessibilityLabel:
              "IDS_IOS_WIDGET_KIT_EXTENSION_LOCKSCREEN_LAUNCHER_VOICESEARCH_A11Y_LABEL",
            widgetURL: WidgetConstants.LockscreenLauncherWidget.voiceSearchUrl)
        case .dinoGame:
          return Configuration(
            displayName: "IDS_IOS_WIDGET_KIT_EXTENSION_LOCKSCREEN_LAUNCHER_GAME_DISPLAY_NAME",
            description: "IDS_IOS_WIDGET_KIT_EXTENSION_LOCKSCREEN_LAUNCHER_GAME_DESCRIPTION",
            imageName: "lockscreen_game_logo",
            accessibilityLabel: "IDS_IOS_WIDGET_KIT_EXTENSION_LOCKSCREEN_LAUNCHER_GAME_A11Y_LABEL",
            widgetURL: WidgetConstants.LockscreenLauncherWidget.gameUrl)
        }
      }
    }
    struct LockscreenLauncherWidgetEntryView: View {
      let entry: Provider.Entry
      let configuration: LockscreenLauncherWidgetType.Configuration
      var body: some View {
        let configuration = self.configuration
        ZStack {
          if #available(iOS 16, *) {
            AccessoryWidgetBackground()
          }
          Image(configuration.imageName)
            .renderingMode(.template)
            .foregroundColor(.white)
        }
        .widgetURL(configuration.widgetURL)
        .accessibilityElement()
        .accessibilityLabel(configuration.accessibilityLabel)
      }
    }
    func lockscreenLauncherWidgetConfiguration(
      ofKind kind: String, forType type: LockscreenLauncherWidgetType
    ) -> some WidgetConfiguration {
      let configuration = type.configuration
      return StaticConfiguration(kind: kind, provider: Provider()) { entry in
        LockscreenLauncherWidgetEntryView(entry: entry, configuration: configuration)
      }
      .configurationDisplayName(
        Text(configuration.displayName)
      )
      .description(Text(configuration.description))
      .supportedFamilies(configuration.supportedFamilies)
    }
    struct LockscreenLauncherSearchWidget: Widget {
      // Changing |kind| or deleting this widget will cause all installed instances of this widget
      // to stop updating and show the placeholder state.
      let kind: String = "LockscreenLauncherSearchWidget"
      var body: some WidgetConfiguration {
        lockscreenLauncherWidgetConfiguration(ofKind: kind, forType: .search)
      }
    }
    struct LockscreenLauncherIncognitoWidget: Widget {
      // Changing |kind| or deleting this widget will cause all installed instances of this widget
      // to stop updating and show the placeholder state.
      let kind: String = "LockscreenLauncherIncognitoWidget"
      var body: some WidgetConfiguration {
        lockscreenLauncherWidgetConfiguration(ofKind: kind, forType: .incognito)
      }
    }
    struct LockscreenLauncherVoiceSearchWidget: Widget {
      // Changing |kind| or deleting this widget will cause all installed instances of this widget
      // to stop updating and show the placeholder state.
      let kind: String = "LockscreenLauncherVoiceSearchWidget"
      var body: some WidgetConfiguration {
        lockscreenLauncherWidgetConfiguration(ofKind: kind, forType: .voiceSearch)
      }
    }
    struct LockscreenLauncherGameWidget: Widget {
      // Changing |kind| or deleting this widget will cause all installed instances of this widget
      // to stop updating and show the placeholder state.
      let kind: String = "LockscreenLauncherGameWidget"
      var body: some WidgetConfiguration {
        lockscreenLauncherWidgetConfiguration(ofKind: kind, forType: .dinoGame)
      }
    }
  #endif  // IOS_AVAILABLE_LOCKSCREEN_WIDGET
#endif  // IOS_ENABLE_LOCKSCREEN_WIDGET


import Foundation
import SwiftUI
import WidgetKit
struct ShortcutsWidget: Widget {
  // Changing 'kind' or deleting this widget will cause all installed instances of this widget to
  // stop updating and show the placeholder state.
  let kind: String = "ShortcutsWidget"
  var body: some WidgetConfiguration {
    StaticConfiguration(
      kind: kind,
      provider: Provider()
    ) { entry in
      ShortcutsWidgetEntryView(entry: entry)
    }
    .configurationDisplayName(
      Text("Shortcuts Widget")
    )
    .description(Text("Shortcuts Widget Description"))
    .supportedFamilies([.systemMedium])
  }
}
struct ShortcutsWidgetEntryView: View {
  let entry: Provider.Entry
  var body: some View {
    EmptyView()
  }
}


import Foundation
import SwiftUI
import WidgetKit
struct ConfigureQuickActionsWidgetEntry: TimelineEntry {
  let date: Date
  let useLens: Bool
}
struct ConfigureQuickActionsWidgetEntryProvider: TimelineProvider {
  func placeholder(in context: Context) -> ConfigureQuickActionsWidgetEntry {
    ConfigureQuickActionsWidgetEntry(date: Date(), useLens: false)
  }
  func shouldUseLens() -> Bool {
    let sharedDefaults: UserDefaults = AppGroupHelper.groupUserDefaults()
    let useLens: Bool =
      sharedDefaults.bool(
        forKey: WidgetConstants.QuickActionsWidget.isGoogleDefaultSearchEngineKey)
      && sharedDefaults.bool(
        forKey: WidgetConstants.QuickActionsWidget.enableLensInWidgetKey)
    return useLens
  }
  func getSnapshot(
    in context: Context,
  ) {
    let entry = ConfigureQuickActionsWidgetEntry(
      date: Date(),
      useLens: shouldUseLens()
    )
    let entries: [ConfigureQuickActionsWidgetEntry] = [entry]
    let timeline: Timeline = Timeline(entries: entries, policy: .never)
    completion(timeline)
  }
}
struct QuickActionsWidget: Widget {
  // Changing |kind| or deleting this widget will cause all installed instances of this widget to
  // stop updating and show the placeholder state.
  let kind: String = "QuickActionsWidget"
  var body: some WidgetConfiguration {
    StaticConfiguration(
      kind: kind,
      provider: ConfigureQuickActionsWidgetEntryProvider()
    ) { entry in
      QuickActionsWidgetEntryView(entry: entry)
    }
    .configurationDisplayName(
      Text("IDS_IOS_WIDGET_KIT_EXTENSION_QUICK_ACTIONS_DISPLAY_NAME")
    )
    .description(Text("IDS_IOS_WIDGET_KIT_EXTENSION_QUICK_ACTIONS_DESCRIPTION"))
    .supportedFamilies([.systemMedium])
  }
}
struct QuickActionsWidgetEntryView: View {
  var entry: ConfigureQuickActionsWidgetEntry
  private let searchAreaHeight: CGFloat = 92
  private let separatorHeight: CGFloat = 32
  private let incognitoA11yLabel: LocalizedStringKey =
    "IDS_IOS_WIDGET_KIT_EXTENSION_QUICK_ACTIONS_INCOGNITO_A11Y_LABEL"
  private let voiceSearchA11yLabel: LocalizedStringKey =
    "IDS_IOS_WIDGET_KIT_EXTENSION_QUICK_ACTIONS_VOICE_SEARCH_A11Y_LABEL"
  private let lensA11yLabel: LocalizedStringKey =
    "IDS_IOS_WIDGET_KIT_EXTENSION_QUICK_ACTIONS_LENS_A11Y_LABEL"
  private let qrA11yLabel: LocalizedStringKey =
    "IDS_IOS_WIDGET_KIT_EXTENSION_QUICK_ACTIONS_QR_SCAN_A11Y_LABEL"
  func symbolWithName(symbolName: String, system: Bool) -> some View {
    let image = system ? Image(systemName: symbolName) : Image(symbolName)
    return image.foregroundColor(Color("widget_actions_icon_color")).font(
      .system(size: 20, weight: .medium)
    ).imageScale(.medium)
  }
  var body: some View {
    VStack(spacing: 0) {
      ZStack {
        Color("widget_background_color")
          .unredacted()
        VStack {
          Spacer()
          Link(destination: WidgetConstants.QuickActionsWidget.searchUrl) {
            ZStack {
              RoundedRectangle(cornerRadius: 26)
                .frame(height: 52)
                .foregroundColor(Color("widget_search_bar_color"))
              HStack(spacing: 12) {
                Image("widget_chrome_logo")
                  .clipShape(Circle())
                  // Without .clipShape(Circle()), in the redacted/placeholder
                  // state the Widget shows an rectangle placeholder instead of
                  // a circular one.
                  .padding(.leading, 8)
                  .unredacted()
                Text("IDS_IOS_WIDGET_KIT_EXTENSION_QUICK_ACTIONS_TITLE")
                  .font(.subheadline)
                  .foregroundColor(Color("widget_text_color"))
                Spacer()
              }
            }
            .frame(minWidth: 0, maxWidth: .infinity)
            .padding([.leading, .trailing], 11)
          }
          .accessibility(
            label:
              Text(
                "IDS_IOS_WIDGET_KIT_EXTENSION_QUICK_ACTIONS_SEARCH_A11Y_LABEL"
              )
          )
          Spacer()
        }
        .frame(height: searchAreaHeight)
      }
      ZStack {
        Rectangle()
          .foregroundColor(Color("widget_actions_row_background_color"))
          .frame(minWidth: 0, maxWidth: .infinity)
        HStack {
          // Show interactive buttons if the widget is fully loaded, and show
          // the custom placeholder otherwise.
          if redactionReasons.isEmpty {
            Link(destination: WidgetConstants.QuickActionsWidget.incognitoUrl) {
              symbolWithName(symbolName: "widget_incognito_icon", system: false)
                .frame(minWidth: 0, maxWidth: .infinity)
            }
            .accessibility(label: Text(incognitoA11yLabel))
            Separator(height: separatorHeight)
            Link(
              destination: WidgetConstants.QuickActionsWidget.voiceSearchUrl
            ) {
              symbolWithName(symbolName: "mic", system: true)
                .frame(minWidth: 0, maxWidth: .infinity)
            }
            .accessibility(label: Text(voiceSearchA11yLabel))
            Separator(height: separatorHeight)
            if entry.useLens {
              Link(destination: WidgetConstants.QuickActionsWidget.lensUrl) {
                symbolWithName(symbolName: "widget_lens_icon", system: false)
                  .frame(minWidth: 0, maxWidth: .infinity)
              }
              .accessibility(label: Text(lensA11yLabel))
            } else {
              Link(destination: WidgetConstants.QuickActionsWidget.qrCodeUrl) {
                symbolWithName(symbolName: "qrcode", system: true)
                  .frame(minWidth: 0, maxWidth: .infinity)
              }
              .accessibility(label: Text(qrA11yLabel))
            }
          } else {
            ButtonPlaceholder()
            Separator(height: separatorHeight)
            ButtonPlaceholder()
            Separator(height: separatorHeight)
            ButtonPlaceholder()
          }
        }
        .frame(minWidth: 0, maxWidth: .infinity)
        .padding([.leading, .trailing], 11)
      }
    }
  }
}
struct Separator: View {
  let height: CGFloat
  var body: some View {
    RoundedRectangle(cornerRadius: 1)
      .foregroundColor(Color("widget_separator_color"))
      .frame(width: 2, height: height)
  }
}
struct ButtonPlaceholder: View {
  private let widthOfPlaceholder: CGFloat = 28
  var body: some View {
    Group {
      RoundedRectangle(cornerRadius: 4, style: .continuous)
        .frame(width: widthOfPlaceholder, height: widthOfPlaceholder)
        .foregroundColor(Color("widget_text_color"))
        .opacity(0.3)
    }.frame(minWidth: 0, maxWidth: .infinity)
  }
}


main

  ) {
    let entry = SimpleEntry(date: Date())
    completion(entry)
  }
  func getTimeline(
    in context: Context,
struct ChromeWidgets: WidgetBundle {
  init() {
    CrashHelper.configure()
  }
  var body: some Widget {
    QuickActionsWidget()
    SearchWidget()
    DinoGameWidget()
    #if IOS_ENABLE_SHORTCUTS_WIDGET
      ShortcutsWidget()
    #endif
    #if IOS_ENABLE_LOCKSCREEN_WIDGET
      #if IOS_AVAILABLE_LOCKSCREEN_WIDGET
        LockscreenLauncherSearchWidget()
        LockscreenLauncherIncognitoWidget()
        LockscreenLauncherVoiceSearchWidget()
        LockscreenLauncherGameWidget()
      #endif
    #endif
  }
}


import Foundation
import SwiftUI
import WidgetKit
struct DinoGameWidget: Widget {
  // Changing |kind| or deleting this widget will cause all installed instances of this widget to
  // stop updating and show the placeholder state.
  let kind: String = "DinoGameWidget"
  var body: some WidgetConfiguration {
    StaticConfiguration(kind: kind, provider: Provider()) { entry in
      DinoGameWidgetEntryView(entry: entry)
    }
    .configurationDisplayName(
      Text("IDS_IOS_WIDGET_KIT_EXTENSION_GAME_DISPLAY_NAME")
    )
    .description(Text("IDS_IOS_WIDGET_KIT_EXTENSION_GAME_DESCRIPTION"))
    .supportedFamilies([.systemSmall])
  }
}
struct DinoGameWidgetEntryView: View {
  let background = "widget_dino_background"
  let backgroundPlaceholder = "widget_dino_background_placeholder"
  var entry: Provider.Entry
  var body: some View {
    // We wrap this widget in a link on top of using `widgetUrl` so that the voice over will treat
    // the widget as one tap target. Without the wrapping, voice over treats the content within
    // the widget as multiple tap targets.
    Link(destination: WidgetConstants.DinoGameWidget.url) {
      ZStack {
        Image(redactionReasons.isEmpty ? background : backgroundPlaceholder)
          .resizable()
          .unredacted()
        VStack(alignment: .leading, spacing: 0) {
          Spacer()
            .frame(minWidth: 0, maxWidth: .infinity)
          HStack {
            Text("IDS_IOS_WIDGET_KIT_EXTENSION_GAME_TITLE")
              .foregroundColor(Color("widget_text_color"))
              .fontWeight(.semibold)
              .font(.subheadline)
              .lineLimit(1)
            Spacer()
          }
          .padding([.leading, .bottom], 16)
        }
      }
    }
    .widgetURL(WidgetConstants.DinoGameWidget.url)
    .accessibility(
      label: Text("IDS_IOS_WIDGET_KIT_EXTENSION_GAME_A11Y_LABEL"))
  }
}


import Foundation
struct WidgetConstants {
  struct SearchWidget {
    static let url = URL(string: "chromewidgetkit://search-widget/search")!
  }
  struct QuickActionsWidget {
    static let searchUrl =
      URL(string: "chromewidgetkit://quick-actions-widget/search")!
    static let incognitoUrl =
      URL(string: "chromewidgetkit://quick-actions-widget/incognito")!
    static let voiceSearchUrl =
      URL(string: "chromewidgetkit://quick-actions-widget/voicesearch")!
    static let qrCodeUrl =
      URL(string: "chromewidgetkit://quick-actions-widget/qrreader")!
    static let lensUrl =
      URL(string: "chromewidgetkit://quick-actions-widget/lens")!
    static let isGoogleDefaultSearchEngineKey = "isGoogleDefaultSearchEngine"
    static let enableLensInWidgetKey = "enableLensInWidget"
  }
  struct DinoGameWidget {
    static let url = URL(string: "chromewidgetkit://dino-game-widget/game")!
  }
  struct LockscreenLauncherWidget {
    static let searchUrl =
      URL(string: "chromewidgetkit://lockscreen-launcher-widget/search")!
    static let incognitoUrl =
      URL(string: "chromewidgetkit://lockscreen-launcher-widget/incognito")!
    static let voiceSearchUrl =
      URL(string: "chromewidgetkit://lockscreen-launcher-widget/voicesearch")!
    static let gameUrl = URL(string: "chromewidgetkit://lockscreen-launcher-widget/game")!
  }
}


import UIKit
/// Globally maps reference views to layout guides.
///
/// Usage:
/// 1.  Reference a view from a part of the UI under a specific name.
/// 2.  In a different part of the UI, request a layout guide under that name. Add the synced layout
///     guide to the UI. It will track the reference view automatically.
///
/// Details:
/// -   Referenced views and created layout guides are only weakly stored by the layout guide
///     center.
/// -   Referenced views don't have to be laid out by AutoLayout.
/// -   Referenced views and layout guides don't have to be in the same window.
  public func reference(view referenceView: UIView?, under name: String) {
    let oldReferenceView = referencedView(under: name)
    // Early return if `referenceView` is already set.
    if referenceView == oldReferenceView {
      return
    }
    oldReferenceView?.cr_onWindowCoordinatesChanged = nil
    if let referenceView = referenceView {
      referenceViews.setObject(referenceView, forKey: name as NSString)
    } else {
      referenceViews.removeObject(forKey: name as NSString)
    }
    updateGuides(named: name)
    // Schedule updates to the matching layout guides when the reference view
    // moves in its window.
    referenceView?.cr_onWindowCoordinatesChanged = { [weak self] _ in
      self?.updateGuides(named: name)
    }
  }
  /// Returns the referenced view under `name`.
  public func makeLayoutGuide(named name: String) -> UILayoutGuide {
    let layoutGuide = FrameLayoutGuide()
    layoutGuide.onDidMoveToWindow = { [weak self] _ in
      self?.updateGuides(named: name)
    }
    // Keep a weak reference to the layout guide.
    if layoutGuides[name] == nil {
      layoutGuides[name] = NSHashTable<FrameLayoutGuide>.weakObjects()
    }
    layoutGuides[name]?.add(layoutGuide)
    return layoutGuide
  }
  /// MARK: Private
  /// Weakly stores the reference views.
  private var referenceViews = NSMapTable<NSString, UIView>.strongToWeakObjects()
  /// Weakly stores the layout guides.
  private var layoutGuides = [String: NSHashTable<FrameLayoutGuide>]()
  /// Updates all available guides for the given `name`.
  private func updateGuides(named name: String) {
    // Early return if there is no reference window.
    guard let referenceView = referencedView(under: name) else { return }
    guard let referenceWindow = referenceView.window else { return }
    // Early return if there are no layout guides.
    guard let layoutGuidesForName = layoutGuides[name] else { return }
    for layoutGuide in layoutGuidesForName.allObjects {
      // Skip if there is no owning window.
      guard let owningView = layoutGuide.owningView else { continue }
      guard let owningWindow = owningView.window else { continue }
      let frameInReferenceWindow = referenceView.convert(referenceView.bounds, to: nil)
      let frameInOwningWindow = referenceWindow.convert(frameInReferenceWindow, to: owningWindow)
      let frameInOwningView = owningView.convert(frameInOwningWindow, from: nil)
      layoutGuide.constrainedFrame = frameInOwningView
    }
  }
}


UIView+WindowCoordinates

import UIKit
/// Lets any UIView communicate when its coordinates in its window change.
///
/// This is useful to know when a view moved on the screen, even when it didn't change frame in its
/// own parent.
///
/// To get notified when the view moved in its window:
///
///     let myView = UIView()
///     myView.cr_onWindowCoordinatesChanged = { view in
///       // Print the window coordinates.
///       print("\(view) moved to \(view convertRect:view.bounds toView:nil)")
///     }
///     let parentView = UIView()
///     parentView.addSubview(myView)
///     let window = UIWindow()
///     window.addSubview(parentView)  // → Calls the closure a first time.
///     parentView.frame = CGRect(x: 10, y: 20, width: 30, height: 40)  // → Calls the closure.
///
///  Even though `myView`'s frame itself was not modified in `parentView`, the closure is called, as
///  actually, `myView` moved transitively in its window.
///
    get {
      objc_getAssociatedObject(self, &UIView.OnWindowCoordinatesChangedKey) as? (UIView) -> Void
    }
    set {
      objc_setAssociatedObject(
        self, &UIView.OnWindowCoordinatesChangedKey, newValue, .OBJC_ASSOCIATION_COPY)
      if newValue != nil {
        // Make sure UIView supports window observing.
        Self.cr_supportsWindowObserving = true
        observation = observe(\.window, options: [.initial]) { [weak self] _, _ in
          guard let self = self else { return }
          if self.window != nil {
            self.addMirrorViewInWindow()
            // Additionally, call the closure here as the view moved to a window.
            self.cr_onWindowCoordinatesChanged?(self)
          } else {
            self.removeMirrorViewInWindow()
          }
        }
      } else {
        observation = nil
      }
    }
  }
  /// MARK: Private
  /// The currently set observation of the window property.
  private var observation: NSKeyValueObservation? {
    get {
      objc_getAssociatedObject(self, &UIView.ObservationKey) as? NSKeyValueObservation
    }
    set {
      objc_setAssociatedObject(
        self, &UIView.ObservationKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    }
  }
  /// Inserts a direct subview to the receiver's window, with constraints such that the mirror view
  /// always has the same window coordinates as the receiver. The mirror view calls the
  /// `onWindowCoordinatesChanged` closure when its bounds change.
  private func addMirrorViewInWindow() {
    let mirrorViewInWindow = NotifyingView()
    mirrorViewInWindow.backgroundColor = .clear
    mirrorViewInWindow.isUserInteractionEnabled = false
    mirrorViewInWindow.translatesAutoresizingMaskIntoConstraints = false
    mirrorViewInWindow.onLayoutChanged = { [weak self] _ in
      // Callback on the next turn of the run loop to wait for AutoLayout to have updated the entire
      // hierarchy. (It can happen that AutoLayout updates the mirror view before the mirrored
      // view.)
      DispatchQueue.main.async {
        guard let self = self else { return }
        self.cr_onWindowCoordinatesChanged?(self)
      }
    }
    guard let window = window else { fatalError() }
    window.insertSubview(mirrorViewInWindow, at: 0)
    NSLayoutConstraint.activate([
      mirrorViewInWindow.topAnchor.constraint(equalTo: topAnchor),
      mirrorViewInWindow.bottomAnchor.constraint(equalTo: bottomAnchor),
      mirrorViewInWindow.leadingAnchor.constraint(equalTo: leadingAnchor),
      mirrorViewInWindow.trailingAnchor.constraint(equalTo: trailingAnchor),
    ])
    self.mirrorViewInWindow = mirrorViewInWindow
  }
  /// Removes the mirror view added by a call to `addMirrorViewInWindow`.
  private func removeMirrorViewInWindow() {
    mirrorViewInWindow?.onLayoutChanged = nil
    mirrorViewInWindow?.removeFromSuperview()
    mirrorViewInWindow = nil
  }
  /// The currently set mirror view.
  private var mirrorViewInWindow: NotifyingView? {
    get {
      objc_getAssociatedObject(self, &UIView.MirrorViewInWindowKey) as? NotifyingView
    }
    set {
      objc_setAssociatedObject(
        self, &UIView.MirrorViewInWindowKey, newValue, .OBJC_ASSOCIATION_ASSIGN)
    }
  }
  /// A simple view that calls a closure when its bounds and center changed.
  private class NotifyingView: UIView {
    var onLayoutChanged: ((UIView) -> Void)?
    override var bounds: CGRect {
      didSet {
        onLayoutChanged?(self)
      }
    }
    override var center: CGPoint {
      didSet {
        onLayoutChanged?(self)
      }
    }
  }
  /// Keys for storing associated objects.
  private static var OnWindowCoordinatesChangedKey = ""
  private static var ObservationKey = ""
  private static var MirrorViewInWindowKey = ""
}


import UIKit
/// A layout guide with two distinct additions:
/// 1.  encapsulates the KVO on its owning view's window and triggers a callback closure;
/// 2.  can be constrained to a fixed frame in its owning view coordinates.
///
/// 1. To get notified when the layout guide is added to a new window:
///
///     let layoutGuide = FrameLayoutGuide()
///     layoutGuide.onDidMoveToWindow = { guide in
///       if let window = guide.owningView?.window {
///         print("\(guide) moved to \(guide.owningView?.window)")
///       } else {
///         print("\(guide) was removed from its window")
///       }
///     }
///
///  2. To constrain a frame to the layout guide:
///
///      let layoutGuide = FrameLayoutGuide()
///      layoutGuide.constrainedFrame = CGRect(x: 10, y: 20, width: 30, height: 40)
///
///  The layout guide can then be used as an anchor to place elements related to its position.
    get {
      constrainedFrameView.frame
    }
    set {
      constrainedFrameView.frame = newValue
    }
  }
  /// MARK: Private
  /// When `owningView` changes, remove `constrainedFrameView` from the old to the new view, then
  /// reset the constraints anchoring the layout guide on `constrainedFrameView`.
  override open var owningView: UIView? {
    willSet {
      constrainedFrameView.removeFromSuperview()
    }
    didSet {
      if let owningView = owningView {
        owningView.addSubview(constrainedFrameView)
        NSLayoutConstraint.activate([
          leadingAnchor.constraint(equalTo: constrainedFrameView.leadingAnchor),
          trailingAnchor.constraint(equalTo: constrainedFrameView.trailingAnchor),
          topAnchor.constraint(equalTo: constrainedFrameView.topAnchor),
          bottomAnchor.constraint(equalTo: constrainedFrameView.bottomAnchor),
        ])
      }
    }
  }
  /// The observation of the owning view's window property. It's an optional variable because it
  /// can't be initialized before `self` is. See `init`.
  private var observation: NSKeyValueObservation?
  /// The view to inject in the owning view. Its frame will be set to `constrainedFrame`. The layout
  /// guide will anchor itself on that view.
  private let constrainedFrameView: UIView
  public override init() {
    constrainedFrameView = UIView()
    constrainedFrameView.backgroundColor = .clear
    constrainedFrameView.isUserInteractionEnabled = false
    super.init()
    // Make sure UIView supports window observing.
    UIView.cr_supportsWindowObserving = true
    // Start observing. It is not possible to initialize `observation` before `super.init()` because
    // the call to `observe(_:changeHandler:)` requires `self` to be initialized.
    // https://developer.apple.com/documentation/swift/cocoa_design_patterns/using_key-value_observing_in_swift
    observation = observe(\.owningView?.window, options: [.old, .new]) { layoutGuide, change in
      // Filter out changes where owning view changed but not the window. This can happen if a
      // layout guide is moved to a different owning view whose window is the same.
      if change.oldValue != change.newValue {
        layoutGuide.onDidMoveToWindow?(layoutGuide)
      }
    }
  }
  required init(coder aDecoder: NSCoder) {
    fatalError("Not using storyboards")
  }
}


UIView+WindowObserving

    get {
      return swizzled
    }
    set {
      if swizzled != newValue {
        // Swap implementations.
        guard
          let willMove1 = class_getInstanceMethod(UIView.self, #selector(willMove(toWindow:))),
          let willMove2 = class_getInstanceMethod(UIView.self, #selector(cr_willMove(toWindow:))),
          let didMove1 = class_getInstanceMethod(UIView.self, #selector(didMoveToWindow)),
          let didMove2 = class_getInstanceMethod(UIView.self, #selector(cr_didMoveToWindow)),
          // UITextField's original implementations don't call the super class implementations,
          // which breaks the interposition at the UIView level. Handle UITextField explicitly.
          let textFieldWillMove1 = class_getInstanceMethod(
            UITextField.self, #selector(willMove(toWindow:))),
          let textFieldWillMove2 = class_getInstanceMethod(
            UITextField.self, #selector(cr_willMove(toWindow:))),
          let textFieldDidMove1 = class_getInstanceMethod(
            UITextField.self, #selector(didMoveToWindow)),
          let textFieldDidMove2 = class_getInstanceMethod(
            UITextField.self, #selector(cr_didMoveToWindow))
        else {
          // If it failed here, don't change the `swizzled` state.
          return
        }
        method_exchangeImplementations(willMove1, willMove2)
        method_exchangeImplementations(didMove1, didMove2)
        method_exchangeImplementations(textFieldWillMove1, textFieldWillMove2)
        method_exchangeImplementations(textFieldDidMove1, textFieldDidMove2)
        // Change the `swizzled` state.
        swizzled = newValue
      }
    }
  }
  /// Signals that the `window` key is supported via Manual Change Notification.
  /// https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/KeyValueObserving/Articles/KVOCompliance.html#//apple_ref/doc/uid/20002178-SW3
    cr_willMove(toWindow: newWindow)
    willChangeValue(forKey: "window")
  }
  /// Adds a call to the KVO `didChangeValue(forKey:)` method.
    cr_willMove(toWindow: newWindow)
    willChangeValue(forKey: "window")
  }
  /// Adds a call to the KVO `didChangeValue(forKey:)` method.
  ///
  /// This version is necessary, as UITextField's original implementation doesn't call its
  /// superclass implementation, hence escapes the interposition at the UIView level.
    cr_didMoveToWindow()
    didChangeValue(forKey: "window")
  }
}


import Foundation
import WidgetKit
/// Helper class to update timelines for WidgetKit widgets.
public final class WidgetTimelinesUpdater: NSObject {
  /// The queue onto which time-consuming work is dispatched.
  private static let queue = DispatchQueue(label: "com.google.chrome.ios.WidgetTimelinesUpdater")
  /// Updates timelines for all shared widgets.
  ///
  /// Whether or not widgets are actually updated depends on many factors
  /// governed by an OS level budgeting system. Widgets are guaranteed
  /// to be updated if the main app is in the foreground.
  ///
  /// This method is safe to call from any thread.
  public static func reloadAllTimelines() {
    queue.async {
      WidgetCenter.shared.reloadAllTimelines()
    }
  }
}


import Foundation
/// An object that stores and retrieves the widget configurations from user defaults.
public struct UserDefaultsWidgetStore {
  /// The key that the current widget configurations are stored under in the user defaults.
  private let widgetInfoKey = "com.google.chrome.ios.widgets.widget-info"
  // Use UserDefaults.standard because this information only needs to be stored and retrieved from
  // the main app.
  private let userDefaults = UserDefaults.standard
  public func storeWidgetInfo(_ info: [String]) throws {
    let encoder = JSONEncoder()
    let data = try encoder.encode(info)
    userDefaults.set(data, forKey: widgetInfoKey)
  }
  public func retrieveStoredWidgetInfo() -> Result<[String], Error> {
    guard let data = userDefaults.data(forKey: widgetInfoKey) else {
      // If there is no stored data, return an empty array.
      return .success([])
    }
    let decoder = JSONDecoder()
    return Result {
      return try decoder.decode(Array<String>.self, from: data)
    }
  }
}


import Foundation
import WidgetKit
/// Logs metrics associated with iOS 14 home screen widgets.
public final class WidgetsMetricLogger: NSObject {
  /// The queue onto which time-consuming work is dispatched.
  private static let queue = DispatchQueue(label: "com.google.chrome.ios.WidgetMetricLogger")
  // MARK: Public
  /// A callback to be called when a widget install is detected. This callback is passed the
  /// information about which widget was installed.
  ///
  /// This property must be set before the `logInstalledWidgets` method is called.
  /// Logs metrics if the user has installed or uninstalled a widget since the last check.
  ///
  /// This method should be called once per application foreground, for example in the
  /// `applicationWillEnterForeground` method.
  ///
  /// This method is safe to call from any thread.
  public static func logInstalledWidgets() {
    if #available(iOS 14, *) {
      // To avoid blocking startup, perform work on a background queue.
      queue.async {
        logInstalledWidgets(fetcher: WidgetCenter.shared, store: UserDefaultsWidgetStore())
      }
    }
  }
  // MARK: Private
  /// Logs metrics if the user has installed or uninstalled a widget since the last app launch.
  static func logInstalledWidgets(fetcher: WidgetCenter, store: UserDefaultsWidgetStore) {
    fetcher.getCurrentConfigurations { result in
      // If fetching either current or previous info fails, avoid logging anything. The next time
      // this is called, metrics will be logged.
      guard let currentWidgets = try? result.get().map({ $0.kind }) else {
        return
      }
      // Log current widgets.
      for widget in currentWidgets {
        widgetCurrentCallback?(widget)
      }
      guard let storedWidgets = try? store.retrieveStoredWidgetInfo().get() else {
        return
      }
      // Attempt to store the new configurations and verify that it is successful to avoid double
      // logging. If metrics were logged when storage failed, they would be double-logged the next
      // time this method is called.
      do {
        try store.storeWidgetInfo(currentWidgets)
      } catch {
        return
      }
      // Current widgets minus stored widgets are installations.
      var installedWidgets = currentWidgets
      for storedWidget in storedWidgets {
        if let index = installedWidgets.firstIndex(of: storedWidget) {
          installedWidgets.remove(at: index)
        }
      }
      for installedWidget in installedWidgets {
        widgetInstalledCallback?(installedWidget)
      }
      // Stored widgets minus current widgets are uninstallations.
      var uninstalledWidgets = storedWidgets
      for currentWidget in currentWidgets {
        if let index = uninstalledWidgets.firstIndex(of: currentWidget) {
          uninstalledWidgets.remove(at: index)
        }
      }
      for uninstalledWidget in uninstalledWidgets {
        widgetUninstalledCallback?(uninstalledWidget)
      }
    }
  }
}


import CoreSpotlight
import UIKit
/// Displays details of a single CSSearchableItem.
class SearchableItemDetailViewController: UIViewController {
  let item: CSSearchableItem
  init(with item: CSSearchableItem) {
    self.item = item
    super.init(nibName: nil, bundle: nil)
  }
  required init?(coder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }
  enum Section: CaseIterable {
    case main
  }
  struct SearchableItemDetail: Hashable {
    let title: String  // Used as unique ID
    let value: String?
    func hash(into hasher: inout Hasher) {
      hasher.combine(title)
    }
    static func == (lhs: SearchableItemDetail, rhs: SearchableItemDetail) -> Bool {
      return lhs.title == rhs.title
    }
  }
  var dataSource: UICollectionViewDiffableDataSource<Section, SearchableItemDetail>! = nil
  var collectionView: UICollectionView! = nil
  override func viewDidLoad() {
    super.viewDidLoad()
    navigationItem.title = item.attributeSet.title ?? item.uniqueIdentifier
    configureHierarchy()
    configureDataSource()
  }
  func createLayout() -> UICollectionViewLayout {
    let config = UICollectionLayoutListConfiguration(appearance: .insetGrouped)
    return UICollectionViewCompositionalLayout.list(using: config)
  }
  private func configureHierarchy() {
    collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: createLayout())
    collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
    view.addSubview(collectionView)
  }
  private func configureDataSource() {
    let cellRegistration = UICollectionView.CellRegistration<
      UICollectionViewListCell, SearchableItemDetail
    > { (cell, indexPath, detail) in
      var content = cell.defaultContentConfiguration()
      content.text = detail.title
      content.secondaryText = detail.value
      cell.contentConfiguration = content
    }
    dataSource = UICollectionViewDiffableDataSource<Section, SearchableItemDetail>(
      collectionView: collectionView
    ) {
      (collectionView: UICollectionView, indexPath: IndexPath, identifier: SearchableItemDetail)
        -> UICollectionViewCell? in
      return collectionView.dequeueConfiguredReusableCell(
        using: cellRegistration, for: indexPath, item: identifier)
    }
    var snapshot = NSDiffableDataSourceSnapshot<Section, SearchableItemDetail>()
    snapshot.appendSections([SearchableItemDetailViewController.Section.main])
    snapshot.appendItems([
      SearchableItemDetail(title: "displayName", value: item.attributeSet.displayName),
      SearchableItemDetail(title: "domain", value: item.domainIdentifier),
      SearchableItemDetail(title: "title", value: item.attributeSet.title),
      SearchableItemDetail(title: "id", value: item.uniqueIdentifier),
      SearchableItemDetail(title: "URL", value: item.attributeSet.url?.absoluteString),
      SearchableItemDetail(title: "description", value: item.attributeSet.contentDescription),
      SearchableItemDetail(title: "thumbnail data", value: thumbnailDescription()),
    ])
    dataSource.apply(snapshot, animatingDifferences: false)
  }
  private func thumbnailDescription() -> String {
    guard let data = item.attributeSet.thumbnailData else {
      return "not available"
    }
    guard let image = UIImage(data: data) else {
      return "corrupt image data"
    }
  }
}


import CoreSpotlight
import UIKit
/// Controller backed by SpotlightLogger known items, with filter function.
class ItemsController {
  func filteredItems(with filter: String? = nil, limit: Int? = nil) -> [CSSearchableItem] {
    let filtered = knownItems.filter { $0.contains(filter) }
    if let limit = limit {
      return Array(filtered.prefix(through: limit))
    } else {
      return filtered
    }
  }
  private lazy var knownItems: [CSSearchableItem] = {
    return SpotlightLogger.shared().knownIndexedItems() ?? []
  }()
}
/// Displays a list of all searchable items from the spotlight logger.
class SpotlightDebuggerAllItemsViewController: UIViewController {
  enum Section: CaseIterable {
    case main
  }
  let itemsController = ItemsController()
  let searchBar = UISearchBar(frame: .zero)
  var collectionView: UICollectionView!
  var dataSource: UICollectionViewDiffableDataSource<Section, CSSearchableItem>!
  var nameFilter: String?
  override func viewDidLoad() {
    super.viewDidLoad()
    navigationItem.title = "Donated Items"
    configureHierarchy()
    configureDataSource()
    performQuery(with: nil)
  }
  override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    collectionView.deselectAllItems(animated: animated)
  }
}
extension UICollectionView {
  func deselectAllItems(animated: Bool) {
    guard let selectedItems = indexPathsForSelectedItems else { return }
    for indexPath in selectedItems { deselectItem(at: indexPath, animated: animated) }
  }
}
extension SpotlightDebuggerAllItemsViewController {
  func configureDataSource() {
    let cellRegistration = UICollectionView.CellRegistration<
      UICollectionViewListCell, CSSearchableItem
    > { (cell, indexPath, item) in
      var content = cell.defaultContentConfiguration()
      content.text = item.attributeSet.title
      if let data = item.attributeSet.thumbnailData {
        content.image = UIImage(data: data)
        content.imageProperties.maximumSize = CGSize(width: 40, height: 40)
      } else {
        content.image = UIImage(systemName: "questionmark.diamond")
      }
      cell.accessories = [.disclosureIndicator()]
      cell.contentConfiguration = content
    }
    dataSource = UICollectionViewDiffableDataSource<Section, CSSearchableItem>(
      collectionView: collectionView
    ) {
      (collectionView: UICollectionView, indexPath: IndexPath, identifier: CSSearchableItem)
        -> UICollectionViewCell? in
      // Return the cell.
      return collectionView.dequeueConfiguredReusableCell(
        using: cellRegistration, for: indexPath, item: identifier)
    }
  }
  func performQuery(with filter: String?) {
    let items = itemsController.filteredItems(with: filter).sorted {
      $0.uniqueIdentifier < $1.uniqueIdentifier
    }
    var snapshot = NSDiffableDataSourceSnapshot<Section, CSSearchableItem>()
    snapshot.appendSections([.main])
    snapshot.appendItems(items)
    dataSource.apply(snapshot, animatingDifferences: true)
  }
}
extension SpotlightDebuggerAllItemsViewController {
  func createLayout() -> UICollectionViewLayout {
    let config = UICollectionLayoutListConfiguration(appearance: .insetGrouped)
    return UICollectionViewCompositionalLayout.list(using: config)
  }
  func configureHierarchy() {
    view.backgroundColor = .systemBackground
    let layout = createLayout()
    let collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout)
    collectionView.translatesAutoresizingMaskIntoConstraints = false
    searchBar.translatesAutoresizingMaskIntoConstraints = false
    collectionView.backgroundColor = .systemBackground
    collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
    collectionView.delegate = self
    view.addSubview(collectionView)
    view.addSubview(searchBar)
    let views = ["cv": collectionView, "searchBar": searchBar]
    var constraints = [NSLayoutConstraint]()
    constraints.append(
      contentsOf: NSLayoutConstraint.constraints(
        withVisualFormat: "H:|[cv]|", options: [], metrics: nil, views: views))
    constraints.append(
      contentsOf: NSLayoutConstraint.constraints(
        withVisualFormat: "H:|[searchBar]|", options: [], metrics: nil, views: views))
    constraints.append(
      contentsOf: NSLayoutConstraint.constraints(
        withVisualFormat: "V:[searchBar]-20-[cv]|", options: [], metrics: nil, views: views))
    constraints.append(
      searchBar.topAnchor.constraint(
        equalToSystemSpacingBelow: view.safeAreaLayoutGuide.topAnchor, multiplier: 1.0))
    NSLayoutConstraint.activate(constraints)
    self.collectionView = collectionView
    searchBar.delegate = self
  }
}
extension SpotlightDebuggerAllItemsViewController: UICollectionViewDelegate {
  func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    guard let item = self.dataSource.itemIdentifier(for: indexPath) else {
      collectionView.deselectItem(at: indexPath, animated: true)
      return
    }
    let detailViewController = SearchableItemDetailViewController(with: item)
    self.navigationController?.pushViewController(detailViewController, animated: true)
  }
}
extension SpotlightDebuggerAllItemsViewController: UISearchBarDelegate {
  func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
    performQuery(with: searchText)
  }
}
extension CSSearchableItem {
  func contains(_ filter: String?) -> Bool {
    guard let filterText = filter else { return true }
    if filterText.isEmpty { return true }
    let lowercasedFilter = filterText.lowercased()
    return (attributeSet.title?.lowercased().contains(lowercasedFilter) ?? false)
      || (attributeSet.url?.absoluteString.lowercased().contains(lowercasedFilter) ?? false)
      || (domainIdentifier?.lowercased().contains(lowercasedFilter) ?? false)
      || uniqueIdentifier.lowercased().contains(lowercasedFilter)
  }
}


  /// Pedal title, as seen in the pedal button/row.
  public let title: String
  /// Pedal subtitle, e.g. "Settings -> Passwords"
  public let subtitle: String
  /// Describes the action performed; can be used for voiceover.
  public let hint: String
  /// The image for the Pedal.
  public let image: UIImage
  public let imageTintColor: UIColor?
  public let backgroundColor: UIColor?
  public let imageBorderColor: UIColor?
  /// Action to run when the pedal is executed.
  public let action: () -> Void
  /// Action type for metrics collection. Int-casted OmniboxPedalId
  public let type: Int
  public init(
    title: String, subtitle: String,
    accessibilityHint: String,
    image: UIImage,
    imageTintColor: UIColor?,
    backgroundColor: UIColor?,
    imageBorderColor: UIColor?,
    type: Int,
  ) {
    self.title = title
    self.subtitle = subtitle
    self.hint = accessibilityHint
    self.image = image
    self.imageTintColor = imageTintColor
    self.backgroundColor = backgroundColor
    self.imageBorderColor = imageBorderColor
    self.type = type
    self.action = action
  }
}
extension OmniboxPedalData: OmniboxIcon {
  public var iconType: OmniboxIconType {
    return .suggestionIcon
  }
  public var iconImage: UIImage? {
    return image
  }
  public var imageURL: CrURL? { return nil }
  public var iconImageTintColor: UIColor? {
    return imageTintColor
  }
  public var backgroundImageTintColor: UIColor? {
    return backgroundColor
  }
  public var borderColor: UIColor? {
    return imageBorderColor
  }
}


  }
  var body: some View {
    Button {
      state.action?()
    } label: {
      if sizeCategory < .accessibilityMedium {
        regularLayout()
      } else {
        xxlLayout()
      }
    }
    .buttonStyle(InactiveTabsButtonStyle())
  }
  /// MARK - Layouts
  /// Displays the elements mostly horizontally, for when the size category is small.
  private func xxlLayout() -> some View {
    HStack {
      leadingTextVStack {
        title()
        counter()
        subtitle()
      }
      Spacer()
      disclosure()
    }
  }
  /// MARK - Elements
  /// Displays the button title.
  private func subtitle() -> some View {
    if let daysThreshold = state.daysThreshold {
      Text(
        L10nUtils.formatString(
          messageId: IDS_IOS_INACTIVE_TABS_BUTTON_SUBTITLE,
          argument: String(daysThreshold))
      )
      .font(.footnote)
      .foregroundColor(.textSecondary)
    }
  }
  /// Displays the tabs count.
  ///
  /// If the count is larger than 99, "99+" is displayed.
  /// If the count is not set, this returns nothing.
  private func disclosure() -> some View {
    if #available(iOS 16.0, *) {
      Image(systemName: kChevronForwardSymbol)
        .foregroundColor(.textTertiary)
        .fontWeight(.semibold)
    } else {
      // fontWeight is not available on Image. Wrap it in a Text.
      Text(Image(systemName: kChevronForwardSymbol))
        .foregroundColor(.textTertiary)
        .fontWeight(.semibold)
    }
  }
  /// VStack displaying its contents from the leading edge. Textual content is also leading aligned
  /// when displayed on multiple lines.
    VStack(alignment: .leading, spacing: Dimensions.spacing) {
      content()
    }
    .multilineTextAlignment(.leading)
  }
  /// MARK - Styles
  /// Style for the main button, i.e. the top-level view.
  private struct InactiveTabsButtonStyle: ButtonStyle {
    func makeBody(configuration: Configuration) -> some View {
      configuration.label
        .padding([.top, .bottom], Dimensions.verticalPadding)
        .padding([.leading, .trailing], Dimensions.horizontalPadding)
        .background(
          configuration.isPressed ? Color(.systemGray4) : Color.groupedSecondaryBackground
        )
        .cornerRadius(Dimensions.cornerRadius)
        .environment(\.colorScheme, .dark)
    }
  }
}