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

#import "base/metrics/histogram_functions.h"
#import "base/metrics/user_metrics.h"
#import "base/metrics/user_metrics_action.h"
#import "components/prefs/pref_service.h"
#import "ios/chrome/app/application_delegate/app_state.h"
#import "ios/chrome/app/tests_hook.h"
#import "ios/chrome/browser/discover_feed/model/discover_feed_service.h"
#import "ios/chrome/browser/discover_feed/model/discover_feed_service_factory.h"
#import "ios/chrome/browser/ntp/shared/metrics/feed_metrics_recorder.h"
#import "ios/chrome/browser/ntp/shared/metrics/new_tab_page_metrics_constants.h"
#import "ios/chrome/browser/ntp/ui_bundled/feed_header_view_controller.h"
#import "ios/chrome/browser/ntp/ui_bundled/feed_wrapper_view_controller.h"
#import "ios/chrome/browser/ntp/ui_bundled/new_tab_page_constants.h"
#import "ios/chrome/browser/ntp/ui_bundled/new_tab_page_header_view_controller.h"
#import "ios/chrome/browser/ntp/ui_bundled/new_tab_page_mediator.h"
#import "ios/chrome/browser/ntp/ui_bundled/new_tab_page_view_controller.h"
#import "ios/chrome/browser/search_engines/model/template_url_service_factory.h"
#import "ios/chrome/browser/shared/coordinator/scene/scene_state.h"
#import "ios/chrome/browser/shared/model/browser/browser.h"
#import "ios/chrome/browser/shared/model/prefs/pref_names.h"
#import "ios/chrome/browser/shared/model/profile/profile_ios.h"
#import "ios/chrome/browser/signin/model/authentication_service.h"
#import "ios/chrome/browser/signin/model/authentication_service_factory.h"
#import "ios/chrome/browser/signin/model/chrome_account_manager_service_factory.h"
#import "ios/chrome/browser/signin/model/identity_manager_factory.h"
#import "ios/chrome/browser/sync/model/sync_service_factory.h"
#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.h"
#import "ios/chrome/browser/ui/content_suggestions/user_account_image_update_delegate.h"
#import "ios/chrome/browser/url_loading/model/url_loading_browser_agent.h"
#import "ios/public/provider/chrome/browser/ui_utils/ui_utils_api.h"

namespace {

// The histogram name for the Lens button new badge status.
const char kNTPLensButtonNewBadgeShownHistogram[] =
    "IOS.NTP.LensButtonNewBadgeShown";

// The maximum number of times to show the new badge on the Lens entrypoint.
const NSInteger kMaxShowCountNTPLensButtonNewBadge = 3;

// Logs the Lens button new badge shown histogram.
void LogLensButtonNewBadgeShownHistogram(IOSNTPNewBadgeShownResult result) {
  base::UmaHistogramEnumeration(kNTPLensButtonNewBadgeShownHistogram, result);
}

}  // namespace

@implementation NewTabPageComponentFactory

#pragma mark - NewTabPageComponentFactoryProtocol methods

- (ContentSuggestionsCoordinator*)contentSuggestionsCoordinatorForBrowser:
    (Browser*)browser {
  return [[ContentSuggestionsCoordinator alloc]
      initWithBaseViewController:nil
                         browser:browser];
}

- (FeedMetricsRecorder*)feedMetricsRecorderForBrowser:(Browser*)browser {
  DiscoverFeedService* discoverFeedService =
      DiscoverFeedServiceFactory::GetForBrowserState(
          browser->GetBrowserState());
  return discoverFeedService->GetFeedMetricsRecorder();
}

- (NewTabPageHeaderViewController*)headerViewControllerForBrowser:
    (Browser*)browser {
  PrefService* prefService = browser->GetBrowserState()->GetPrefs();
  NSInteger lensNewBadgeShowCount =
      prefService->GetInteger(prefs::kNTPLensEntryPointNewBadgeShownCount);

  BOOL useNewBadgeForCustomizationMenu = NO;
  NSInteger customizationNewBadgeImpressionCount = prefService->GetInteger(
      prefs::kNTPHomeCustomizationNewBadgeImpressionCount);

  if (customizationNewBadgeImpressionCount <
      kCustomizationNewBadgeMaxImpressionCount) {
    useNewBadgeForCustomizationMenu = YES;
    base::RecordAction(
        base::UserMetricsAction(kNTPCustomizationNewBadgeShownAction));
    prefService->SetInteger(prefs::kNTPHomeCustomizationNewBadgeImpressionCount,
                            customizationNewBadgeImpressionCount + 1);
  }

  if (lensNewBadgeShowCount < kMaxShowCountNTPLensButtonNewBadge) {
    // Show the "New" badge and colored symbol.
    LogLensButtonNewBadgeShownHistogram(IOSNTPNewBadgeShownResult::kShown);
    prefService->SetInteger(prefs::kNTPLensEntryPointNewBadgeShownCount,
                            lensNewBadgeShowCount + 1);
    return [[NewTabPageHeaderViewController alloc]
        initWithUseNewBadgeForLensButton:YES
         useNewBadgeForCustomizationMenu:useNewBadgeForCustomizationMenu];
  } else {
    BOOL button_pressed = lensNewBadgeShowCount == INT_MAX;
    LogLensButtonNewBadgeShownHistogram(
        button_pressed ? IOSNTPNewBadgeShownResult::kNotShownButtonPressed
                       : IOSNTPNewBadgeShownResult::kNotShownLimitReached);
    return [[NewTabPageHeaderViewController alloc]
        initWithUseNewBadgeForLensButton:NO
         useNewBadgeForCustomizationMenu:useNewBadgeForCustomizationMenu];
  }
}

- (NewTabPageMediator*)NTPMediatorForBrowser:(Browser*)browser
                    identityDiscImageUpdater:
                        (id<UserAccountImageUpdateDelegate>)imageUpdater {
  ChromeBrowserState* browserState = browser->GetBrowserState();
  TemplateURLService* templateURLService =
      ios::TemplateURLServiceFactory::GetForBrowserState(browserState);
  AuthenticationService* authService =
      AuthenticationServiceFactory::GetForBrowserState(browserState);
  DiscoverFeedService* discoverFeedService =
      DiscoverFeedServiceFactory::GetForBrowserState(browserState);
  PrefService* prefService =
      ChromeBrowserState::FromBrowserState(browser->GetBrowserState())
          ->GetPrefs();
  syncer::SyncService* syncService =
      SyncServiceFactory::GetForBrowserState(browser->GetBrowserState());
  BOOL isSafeMode = [browser->GetSceneState().appState resumingFromSafeMode];
  return [[NewTabPageMediator alloc]
      initWithTemplateURLService:templateURLService
                       URLLoader:UrlLoadingBrowserAgent::FromBrowser(browser)
                     authService:authService
                 identityManager:IdentityManagerFactory::GetForBrowserState(
                                     browserState)
           accountManagerService:ChromeAccountManagerServiceFactory::
                                     GetForBrowserState(browserState)
        identityDiscImageUpdater:imageUpdater
                     isIncognito:browserState->IsOffTheRecord()
             discoverFeedService:discoverFeedService
                     prefService:prefService
                     syncService:syncService
                      isSafeMode:isSafeMode];
}

- (NewTabPageViewController*)NTPViewController {
  return [[NewTabPageViewController alloc] init];
}

- (UIViewController*)discoverFeedForBrowser:(Browser*)browser
                viewControllerConfiguration:
                    (DiscoverFeedViewControllerConfiguration*)
                        viewControllerConfiguration {
  if (tests_hook::DisableDiscoverFeed()) {
    return nil;
  }

  // Get the feed factory from the `browser` and create the feed model.
  DiscoverFeedService* feedService =
      DiscoverFeedServiceFactory::GetForBrowserState(
          browser->GetBrowserState());
  FeedModelConfiguration* discoverFeedConfiguration =
      [FeedModelConfiguration discoverFeedModelConfiguration];
  feedService->CreateFeedModel(discoverFeedConfiguration);

  // Return Discover feed VC created with `viewControllerConfiguration`.
  return feedService->NewDiscoverFeedViewControllerWithConfiguration(
      viewControllerConfiguration);
}

- (UIViewController*)followingFeedForBrowser:(Browser*)browser
                 viewControllerConfiguration:
                     (DiscoverFeedViewControllerConfiguration*)
                         viewControllerConfiguration
                                    sortType:(FollowingFeedSortType)sortType {
  if (tests_hook::DisableDiscoverFeed()) {
    return nil;
  }

  // Get the feed factory from the `browser` and create the feed model. Content
  // is sorted by `sortType`.
  DiscoverFeedService* feedService =
      DiscoverFeedServiceFactory::GetForBrowserState(
          browser->GetBrowserState());
  FeedModelConfiguration* followingFeedConfiguration =
      [FeedModelConfiguration followingModelConfigurationWithSortType:sortType];
  feedService->CreateFeedModel(followingFeedConfiguration);

  // Return Following feed VC created with `viewControllerConfiguration`.
  return feedService->NewFollowingFeedViewControllerWithConfiguration(
      viewControllerConfiguration);
}

- (FeedWrapperViewController*)
    feedWrapperViewControllerWithDelegate:
        (id<FeedWrapperViewControllerDelegate>)delegate
                       feedViewController:
                           (UIViewController*)feedViewController {
  return
      [[FeedWrapperViewController alloc] initWithDelegate:delegate
                                       feedViewController:feedViewController];
}

- (FeedHeaderViewController*)feedHeaderViewControllerWithFollowingDotVisible:
    (BOOL)followingDotVisible {
  return [[FeedHeaderViewController alloc]
      initWithFollowingDotVisible:followingDotVisible];
}

@end