chromium/ios/chrome/browser/ui/content_suggestions/parcel_tracking/magic_stack_parcel_list_half_sheet_table_view_controller.mm

// Copyright 2023 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/ui/content_suggestions/parcel_tracking/magic_stack_parcel_list_half_sheet_table_view_controller.h"

#import "base/apple/foundation_util.h"
#import "ios/chrome/browser/shared/ui/symbols/symbols.h"
#import "ios/chrome/browser/shared/ui/table_view/cells/table_view_item.h"
#import "ios/chrome/browser/shared/ui/table_view/table_view_utils.h"
#import "ios/chrome/browser/ui/content_suggestions/parcel_tracking/parcel_tracking_item.h"
#import "ios/chrome/browser/ui/content_suggestions/parcel_tracking/parcel_tracking_view.h"
#import "ios/chrome/common/ui/colors/semantic_color_names.h"
#import "ios/chrome/common/ui/util/constraints_ui_util.h"
#import "ios/chrome/grit/ios_strings.h"
#import "ui/base/l10n/l10n_util_mac.h"

namespace {

const CGFloat kEllipsisButtonPointSize = 24;
const CGFloat kParcelCellMargin = 16;

enum SectionIdentifier : NSInteger {
  SectionIdentifierParcelList = kSectionIdentifierEnumZero,
};

enum ItemType : NSInteger {
  ItemTypeParcelItem = kItemTypeEnumZero,
};

}  // namespace

// Delegate for ParcelListCell.
@protocol ParcelListCellDelegate

// Indicates to the delegate to untrack `parcelID`.
- (void)untrackParcel:(NSString*)parcelID carrier:(ParcelType)carrier;

@end

// Cell displaying a tracked parcel with an option button.
@interface ParcelListCell : TableViewCell

// Configures this cell with the `config`.
- (void)configureCell:(ParcelTrackingItem*)config;

// Delegate for this cell.
@property(nonatomic, weak) id<ParcelListCellDelegate> delegate;

// Tracking number for this cell.
@property(nonatomic, copy) NSString* parcelID;

// Button with more options for this cell.
@property(nonatomic, strong) UIButton* ellipsisButton;

@end

@implementation ParcelListCell {
  ParcelTrackingModuleView* _parcelTrackingView;
  ParcelType _carrier;
}

- (instancetype)initWithStyle:(UITableViewCellStyle)style
              reuseIdentifier:(NSString*)reuseIdentifier {
  self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
  if (self) {
    _parcelTrackingView =
        [[ParcelTrackingModuleView alloc] initWithFrame:CGRectZero];

    // Add empty view to serve as spacing between the parcel contents and the
    // options button that dynamically expands horizontally to fill space.
    UIView* emptySpaceFiller = [[UIView alloc] init];
    [emptySpaceFiller
        setContentHuggingPriority:UILayoutPriorityDefaultLow
                          forAxis:UILayoutConstraintAxisHorizontal];
    self.ellipsisButton = [[UIButton alloc] init];

    UIImage* ellipsisImage = DefaultSymbolWithPointSize(
        kEllipsisCircleFillSymbol, kEllipsisButtonPointSize);
    UIImageSymbolConfiguration* config = [UIImageSymbolConfiguration
        configurationWithPointSize:kEllipsisButtonPointSize
                            weight:UIImageSymbolWeightMedium
                             scale:UIImageSymbolScaleMedium];
    UIImageSymbolConfiguration* colorConfig =
        [UIImageSymbolConfiguration configurationWithPaletteColors:@[
          [UIColor colorNamed:kBlue600Color],
          [UIColor colorNamed:kGroupedPrimaryBackgroundColor]
        ]];
    config = [config configurationByApplyingConfiguration:colorConfig];
    ellipsisImage = [ellipsisImage imageByApplyingSymbolConfiguration:config];
    [self.ellipsisButton setImage:ellipsisImage forState:UIControlStateNormal];

    __weak __typeof(self) weakSelf = self;
    UIAction* untrackAction = [UIAction
        actionWithTitle:l10n_util::GetNSString(
                            IDS_IOS_PARCEL_TRACKING_CONTEXT_MENU_UNTRACK)
                  image:[UIImage imageNamed:@"untrack_parcel"]
             identifier:nil
                handler:^(UIAction* action) {
                  [weakSelf untrackParcel];
                }];
    untrackAction.attributes = UIMenuElementAttributesDestructive;
    self.ellipsisButton.menu = [UIMenu menuWithChildren:@[ untrackAction ]];
    self.ellipsisButton.showsMenuAsPrimaryAction = YES;

    UIStackView* containerStackView =
        [[UIStackView alloc] initWithArrangedSubviews:@[
          _parcelTrackingView, emptySpaceFiller, self.ellipsisButton
        ]];
    containerStackView.axis = UILayoutConstraintAxisHorizontal;
    containerStackView.alignment = UIStackViewAlignmentCenter;
    containerStackView.translatesAutoresizingMaskIntoConstraints = NO;

    [self.contentView addSubview:containerStackView];
    AddSameConstraintsWithInsets(
        containerStackView, self.contentView,
        NSDirectionalEdgeInsetsMake(kParcelCellMargin, kParcelCellMargin,
                                    kParcelCellMargin, kParcelCellMargin));
  }
  return self;
}

- (void)configureCell:(ParcelTrackingItem*)config {
  self.parcelID = config.parcelID;
  _carrier = config.parcelType;
  [_parcelTrackingView configureView:config];
  self.accessibilityElements = @[ _parcelTrackingView, self.ellipsisButton ];
}

- (void)untrackParcel {
  [self.delegate untrackParcel:self.parcelID carrier:_carrier];
}

@end

// Model class for ParcelListCell.
@interface ParcelListItem : TableViewItem
// Config for the displayed Parcel
@property(nonatomic, strong) ParcelTrackingItem* config;
@end

@implementation ParcelListItem

- (instancetype)initWithType:(NSInteger)type {
  self = [super initWithType:type];
  if (self) {
    self.cellClass = [ParcelListCell class];
  }
  return self;
}

#pragma mark TableViewItem

- (void)configureCell:(ParcelListCell*)cell
           withStyler:(ChromeTableViewStyler*)styler {
  [super configureCell:cell withStyler:styler];
  [cell configureCell:self.config];
  cell.selectionStyle = UITableViewCellSelectionStyleNone;
}

@end

@interface MagicStackParcelListHalfSheetTableViewController () <
    ParcelListCellDelegate>
@end

@implementation MagicStackParcelListHalfSheetTableViewController {
  NSMutableArray<ParcelTrackingItem*>* _parcels;
}

- (instancetype)initWithParcels:(NSArray<ParcelTrackingItem*>*)parcels {
  self = [super initWithStyle:ChromeTableViewStyle()];
  if (self) {
    _parcels = [parcels mutableCopy];
  }
  return self;
}

- (void)viewDidLoad {
  [super viewDidLoad];
  self.title = l10n_util::GetNSString(
      IDS_IOS_CONTENT_SUGGESTIONS_PARCEL_TRACKING_MODULE_TITLE);
  UIBarButtonItem* dismissButton = [[UIBarButtonItem alloc]
      initWithBarButtonSystemItem:UIBarButtonSystemItemDone
                           target:self.delegate
                           action:@selector(dismissParcelListHalfSheet)];
  self.navigationItem.rightBarButtonItem = dismissButton;

  [self loadModel];
}

#pragma mark - LegacyChromeTableViewController

- (void)loadModel {
  [super loadModel];

  [self.tableViewModel addSectionWithIdentifier:SectionIdentifierParcelList];

  for (ParcelTrackingItem* item in _parcels) {
    ParcelListItem* parcelListItem =
        [[ParcelListItem alloc] initWithType:ItemTypeParcelItem];
    parcelListItem.config = item;
    [self.tableViewModel addItem:parcelListItem
         toSectionWithIdentifier:SectionIdentifierParcelList];
  }
}

#pragma mark - ParcelListCellDelegate

- (void)untrackParcel:(NSString*)parcelID carrier:(ParcelType)carrier {
  NSIndexPath* parcelItemIndexPath = [self indexPathOfParcelWithID:parcelID];
  CHECK(parcelItemIndexPath);
  [self.tableViewModel removeItemWithType:ItemTypeParcelItem
                fromSectionWithIdentifier:SectionIdentifierParcelList
                                  atIndex:parcelItemIndexPath.row];
  [self.tableView deleteRowsAtIndexPaths:@[ parcelItemIndexPath ]
                        withRowAnimation:UITableViewRowAnimationAutomatic];
  [_parcels removeObjectAtIndex:parcelItemIndexPath.row];
  [self.delegate untrackParcel:parcelID carrier:carrier];
}

#pragma mark UITableViewDelegate

- (UITableViewCell*)tableView:(UITableView*)tableView
        cellForRowAtIndexPath:(NSIndexPath*)indexPath {
  UITableViewCell* cell = [super tableView:tableView
                     cellForRowAtIndexPath:indexPath];
  ParcelListCell* parcelListCell =
      base::apple::ObjCCastStrict<ParcelListCell>(cell);
  parcelListCell.delegate = self;
  parcelListCell.ellipsisButton.accessibilityHint = [l10n_util::GetNSString(
      IDS_IOS_PARCEL_TRACKING_MODAL_INFOBAR_PACKAGE_NUMBER)
      stringByAppendingString:parcelListCell.parcelID];
  return cell;
}

#pragma mark Private

// Returns the indexPath location of the item with a matching `parcelID`.
- (NSIndexPath*)indexPathOfParcelWithID:(NSString*)parcelID {
  for (NSUInteger index = 0; index < [_parcels count]; index++) {
    ParcelTrackingItem* item = _parcels[index];
    if ([item.parcelID isEqualToString:parcelID]) {
      return
          [self.tableViewModel indexPathForItemType:ItemTypeParcelItem
                                  sectionIdentifier:SectionIdentifierParcelList
                                            atIndex:index];
    }
  }
  return nil;
}

@end