chromium/ios/chrome/browser/bring_android_tabs/ui_bundled/tab_list_from_android_mediator.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/bring_android_tabs/ui_bundled/tab_list_from_android_mediator.h"

#import "base/memory/raw_ptr.h"
#import "base/metrics/histogram_functions.h"
#import "base/strings/sys_string_conversions.h"
#import "ios/chrome/browser/bring_android_tabs/model/bring_android_tabs_to_ios_service.h"
#import "ios/chrome/browser/bring_android_tabs/model/metrics.h"
#import "ios/chrome/browser/favicon/model/favicon_loader.h"
#import "ios/chrome/browser/net/model/crurl.h"
#import "ios/chrome/browser/shared/ui/list_model/list_model.h"
#import "ios/chrome/browser/synced_sessions/model/distant_tab.h"
#import "ios/chrome/browser/synced_sessions/model/synced_sessions_util.h"
#import "ios/chrome/browser/bring_android_tabs/ui_bundled/constants.h"
#import "ios/chrome/browser/bring_android_tabs/ui_bundled/tab_list_from_android_consumer.h"
#import "ios/chrome/browser/bring_android_tabs/ui_bundled/tab_list_from_android_table_view_item.h"
#import "ios/chrome/common/ui/favicon/favicon_constants.h"

namespace {

typedef NS_ENUM(NSInteger, ItemType) {
  TabItemType = kItemTypeEnumZero,
};

}  // namespace

@implementation TabListFromAndroidMediator {
  // Keyed service to retrieve active tabs from Android.
  raw_ptr<BringAndroidTabsToIOSService> _bringAndroidTabsService;
  // URL loader to open tabs when needed.
  raw_ptr<UrlLoadingBrowserAgent> _URLLoader;
  // Favicon loader.
  raw_ptr<FaviconLoader> _faviconLoader;
}

- (instancetype)
    initWithBringAndroidTabsService:(BringAndroidTabsToIOSService*)service
                          URLLoader:(UrlLoadingBrowserAgent*)URLLoader
                      faviconLoader:(FaviconLoader*)faviconLoader {
  DCHECK(service != nil);
  if ((self = [super init])) {
    _bringAndroidTabsService = service;
    _URLLoader = URLLoader;
    _faviconLoader = faviconLoader;
  }
  return self;
}

- (void)setConsumer:(id<TabListFromAndroidConsumer>)consumer {
  _consumer = consumer;
  [_consumer setTabListItems:[self tableViewItemArray]];
}

#pragma mark - TableViewFaviconDataSource

- (void)faviconForPageURL:(CrURL*)URL
               completion:(void (^)(FaviconAttributes*))completion {
  _faviconLoader->FaviconForPageUrl(
      URL.gurl, kBringAndroidTabsFaviconSize, kMinFaviconSizePt,
      /*fallback_to_google_server=*/true, ^(FaviconAttributes* attributes) {
        completion(attributes);
      });
}

#pragma mark - TabListFromAndroidViewControllerDelegate

- (void)tabListFromAndroidViewControllerDidDismissWithSwipe:(BOOL)swiped
                                     numberOfDeselectedTabs:
                                         (int)countDeselected {
  bring_android_tabs::TabsListActionType action =
      swiped ? bring_android_tabs::TabsListActionType::kSwipeDown
             : bring_android_tabs::TabsListActionType::kCancel;
  base::UmaHistogramEnumeration(bring_android_tabs::kTabListActionHistogramName,
                                action);
  base::UmaHistogramCounts1000(
      bring_android_tabs::kDeselectedTabCountHistogramName, countDeselected);
  // The user journey to bring recent tabs on Android to iOS has finished.
  // Reload the service to update/clear the tabs.
  _bringAndroidTabsService->LoadTabs();
}

- (void)tabListFromAndroidViewControllerDidTapOpenButtonWithTabIndices:
    (NSArray<NSNumber*>*)tabIndices {
  base::UmaHistogramEnumeration(
      bring_android_tabs::kTabListActionHistogramName,
      bring_android_tabs::TabsListActionType::kOpenTabs);

  size_t numTabs = static_cast<size_t>([tabIndices count]);
  int deselected = static_cast<int>(
      _bringAndroidTabsService->GetNumberOfAndroidTabs() - numTabs);
  base::UmaHistogramCounts1000(
      bring_android_tabs::kDeselectedTabCountHistogramName, deselected);

  std::vector<size_t> indicesVector;
  for (size_t i = 0; i < numTabs; i++) {
    NSUInteger idx = [[tabIndices objectAtIndex:i] unsignedIntValue];
    indicesVector.push_back(static_cast<size_t>(idx));
  }
  _bringAndroidTabsService->OpenTabsAtIndices(indicesVector, _URLLoader);
}

#pragma mark - Private

// Returns an array of table view items corresponding to the user's tabs from
// Android.
- (NSArray<TabListFromAndroidTableViewItem*>*)tableViewItemArray {
  NSMutableArray<TabListFromAndroidTableViewItem*>* itemArray =
      [[NSMutableArray alloc] init];
  for (size_t idx = 0; idx < _bringAndroidTabsService->GetNumberOfAndroidTabs();
       idx++) {
    synced_sessions::DistantTab* distantTab =
        _bringAndroidTabsService->GetTabAtIndex(idx);
    TabListFromAndroidTableViewItem* tabListItem =
        [[TabListFromAndroidTableViewItem alloc] initWithType:TabItemType];
    tabListItem.title = base::SysUTF16ToNSString(distantTab->title);
    tabListItem.URL = [[CrURL alloc] initWithGURL:distantTab->virtual_url];
    [itemArray addObject:tabListItem];
  }
  return itemArray;
}

@end