chromium/ios/chrome/browser/home_customization/ui/home_customization_collection_configurator.mm

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

#import "ios/chrome/browser/home_customization/ui/home_customization_collection_configurator.h"

#import "ios/chrome/browser/home_customization/ui/home_customization_view_controller_protocol.h"
#import "ios/chrome/browser/home_customization/utils/home_customization_helper.h"

namespace {

// The height of a cell in a vertical collection view section.
const CGFloat kVerticalListCellHeight = 74;

// The horizontal spacing between the cell and each side of the vertical
// collection view.
const CGFloat kVerticalListHorizontalPadding = 20;

// The vertical spacing between cells.
const CGFloat kSpacingBetweenCells = 10;

// The vertical spacing below the header.
const CGFloat kSpacingBelowHeader = 10;

}  // namespace

@interface HomeCustomizationCollectionConfigurator ()

// The view controller being configured.
@property(nonatomic, weak)
    UIViewController<HomeCustomizationViewControllerProtocol,
                     UICollectionViewDelegate>* viewController;

@end

@implementation HomeCustomizationCollectionConfigurator

- (instancetype)initWithViewController:
    (UIViewController<HomeCustomizationViewControllerProtocol,
                      UICollectionViewDelegate>*)viewController {
  self = [super init];
  if (self) {
    _viewController = viewController;
  }
  return self;
}

#pragma mark - Public

- (void)configureCollectionView {
  UICollectionView* collectionView =
      [[UICollectionView alloc] initWithFrame:CGRectZero
                         collectionViewLayout:[self collectionViewLayout]];
  collectionView.translatesAutoresizingMaskIntoConstraints = NO;
  collectionView.delegate = _viewController;
  collectionView.accessibilityIdentifier = [HomeCustomizationHelper
      accessibilityIdentifierForPageCollection:_viewController.page];
  _viewController.collectionView = collectionView;

  UICollectionViewDiffableDataSource* diffableDataSource =
      [self createDiffableDataSource];
  _viewController.collectionView.dataSource = diffableDataSource;
  _viewController.diffableDataSource = diffableDataSource;
}

- (void)configureNavigationBar {
  _viewController.title =
      [HomeCustomizationHelper navigationBarTitleForPage:_viewController.page];
  UIBarButtonItem* dismissButton = [[UIBarButtonItem alloc]
      initWithBarButtonSystemItem:UIBarButtonSystemItemClose
                           target:_viewController
                           action:@selector(dismissCustomizationMenuPage)];
  dismissButton.accessibilityIdentifier = kNavigationBarDismissButtonIdentifier;
  _viewController.navigationItem.rightBarButtonItem = dismissButton;
  _viewController.navigationItem.backBarButtonItem.accessibilityIdentifier =
      kNavigationBarBackButtonIdentifier;
  [_viewController.navigationItem setHidesBackButton:YES];
}

- (NSCollectionLayoutSection*)verticalListSectionForLayoutEnvironment:
    (id<NSCollectionLayoutEnvironment>)layoutEnvironment {
  NSCollectionLayoutSize* itemSize = [NSCollectionLayoutSize
      sizeWithWidthDimension:[NSCollectionLayoutDimension
                                 fractionalWidthDimension:1.]
             heightDimension:[NSCollectionLayoutDimension
                                 fractionalHeightDimension:1.]];
  NSCollectionLayoutItem* item =
      [NSCollectionLayoutItem itemWithLayoutSize:itemSize];

  NSCollectionLayoutSize* groupSize = [NSCollectionLayoutSize
      sizeWithWidthDimension:[NSCollectionLayoutDimension
                                 fractionalWidthDimension:1.]
             heightDimension:[NSCollectionLayoutDimension
                                 estimatedDimension:kVerticalListCellHeight]];
  NSCollectionLayoutGroup* group =
      [NSCollectionLayoutGroup verticalGroupWithLayoutSize:groupSize
                                                  subitems:@[ item ]];

  NSCollectionLayoutSection* section =
      [NSCollectionLayoutSection sectionWithGroup:group];

  // Adds spacing between cells, as well as content insets so that the cells
  // have the correct width.
  section.interGroupSpacing = kSpacingBetweenCells;
  section.contentInsets = NSDirectionalEdgeInsetsMake(
      [self doesPageHaveHeader] ? kSpacingBelowHeader : 0,
      kVerticalListHorizontalPadding, 0, kVerticalListHorizontalPadding);

  if ([self doesPageHaveHeader]) {
    NSCollectionLayoutSize* headerSize = [NSCollectionLayoutSize
        sizeWithWidthDimension:[NSCollectionLayoutDimension
                                   fractionalWidthDimension:1.]
               heightDimension:[NSCollectionLayoutDimension
                                   estimatedDimension:kVerticalListCellHeight]];
    NSCollectionLayoutBoundarySupplementaryItem* headerItem =
        [NSCollectionLayoutBoundarySupplementaryItem
            boundarySupplementaryItemWithLayoutSize:headerSize
                                        elementKind:
                                            UICollectionElementKindSectionHeader
                                          alignment:NSRectAlignmentTopLeading];
    section.boundarySupplementaryItems = @[ headerItem ];
  }

  return section;
}

#pragma mark - Private

// Returns a collection view layout suited for the current page.
- (UICollectionViewLayout*)collectionViewLayout {
  UICollectionViewCompositionalLayoutConfiguration* configuration =
      [[UICollectionViewCompositionalLayoutConfiguration alloc] init];
  __weak auto weakViewController = _viewController;
  return [[UICollectionViewCompositionalLayout alloc]
      initWithSectionProvider:^(
          NSInteger sectionIndex,
          id<NSCollectionLayoutEnvironment> layoutEnvironment) {
        return [weakViewController sectionForIndex:sectionIndex
                                 layoutEnvironment:layoutEnvironment];
      }
                configuration:configuration];
}

// Creates the diffable data source with a cell provider used to configure
// each cell.
- (UICollectionViewDiffableDataSource*)createDiffableDataSource {
  __weak auto weakViewController = _viewController;
  auto cellProvider =
      ^UICollectionViewCell*(UICollectionView* collectionView,
                             NSIndexPath* indexPath, NSNumber* itemIdentifier) {
        return [weakViewController configuredCellForIndexPath:indexPath
                                               itemIdentifier:itemIdentifier];
      };
  UICollectionViewDiffableDataSource* diffableDataSource =
      [[UICollectionViewDiffableDataSource alloc]
          initWithCollectionView:_viewController.collectionView
                    cellProvider:cellProvider];
  if ([self doesPageHaveHeader]) {
    diffableDataSource.supplementaryViewProvider = ^UICollectionReusableView*(
        UICollectionView* collectionView, NSString* elementKind,
        NSIndexPath* indexPath) {
      return [weakViewController configuredHeaderForIndexPath:indexPath];
    };
  }

  return diffableDataSource;
}

// Whether the current page should display a header.
- (BOOL)doesPageHaveHeader {
  return _viewController.page == CustomizationMenuPage::kDiscover ||
         _viewController.page == CustomizationMenuPage::kMagicStack;
}

@end