chromium/ios/chrome/browser/settings/model/sync/utils/sync_error_infobar_delegate.mm

// Copyright 2012 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/settings/model/sync/utils/sync_error_infobar_delegate.h"

#import <utility>

#import "base/check.h"
#import "base/memory/ptr_util.h"
#import "base/strings/sys_string_conversions.h"
#import "components/infobars/core/infobar.h"
#import "components/infobars/core/infobar_delegate.h"
#import "components/infobars/core/infobar_manager.h"
#import "components/sync/service/sync_service.h"
#import "components/sync/service/sync_service_utils.h"
#import "ios/chrome/browser/infobars/model/infobar_ios.h"
#import "ios/chrome/browser/infobars/model/infobar_type.h"
#import "ios/chrome/browser/infobars/model/infobar_utils.h"
#import "ios/chrome/browser/settings/model/sync/utils/sync_presenter.h"
#import "ios/chrome/browser/settings/model/sync/utils/sync_util.h"
#import "ios/chrome/browser/shared/model/profile/profile_ios.h"
#import "ios/chrome/browser/sync/model/sync_service_factory.h"

// static
bool SyncErrorInfoBarDelegate::Create(infobars::InfoBarManager* infobar_manager,
                                      ChromeBrowserState* browser_state,
                                      id<SyncPresenter> presenter) {
  DCHECK(infobar_manager);
  std::unique_ptr<SyncErrorInfoBarDelegate> delegate(
      new SyncErrorInfoBarDelegate(browser_state, presenter));
  std::unique_ptr<InfoBarIOS> infobar = std::make_unique<InfoBarIOS>(
      InfobarType::kInfobarTypeSyncError, std::move(delegate));
  return !!infobar_manager->AddInfoBar(std::move(infobar));
}

SyncErrorInfoBarDelegate::SyncErrorInfoBarDelegate(
    ChromeBrowserState* browser_state,
    id<SyncPresenter> presenter)
    : browser_state_(browser_state), presenter_(presenter) {
  DCHECK(!browser_state->IsOffTheRecord());
  syncer::SyncService* sync_service =
      SyncServiceFactory::GetForBrowserState(browser_state_);
  DCHECK(sync_service);
  // Set all of the UI based on the sync state at the same time to ensure
  // they all correspond to the same sync error.
  error_state_ = sync_service->GetUserActionableError();
  title_ = GetSyncErrorInfoBarTitleForBrowserState(browser_state_);
  message_ = base::SysNSStringToUTF16(
      GetSyncErrorMessageForBrowserState(browser_state_));
  button_text_ = base::SysNSStringToUTF16(
      GetSyncErrorButtonTitleForBrowserState(browser_state_));

  // Register for sync status changes.
  sync_service->AddObserver(this);
}

SyncErrorInfoBarDelegate::~SyncErrorInfoBarDelegate() {
  syncer::SyncService* sync_service =
      SyncServiceFactory::GetForBrowserState(browser_state_);
  sync_service->RemoveObserver(this);
}

infobars::InfoBarDelegate::InfoBarIdentifier
SyncErrorInfoBarDelegate::GetIdentifier() const {
  return SYNC_ERROR_INFOBAR_DELEGATE_IOS;
}

std::u16string SyncErrorInfoBarDelegate::GetMessageText() const {
  return message_;
}

std::u16string SyncErrorInfoBarDelegate::GetTitleText() const {
  return title_;
}

int SyncErrorInfoBarDelegate::GetButtons() const {
  return button_text_.empty() ? BUTTON_NONE : BUTTON_OK;
}

std::u16string SyncErrorInfoBarDelegate::GetButtonLabel(
    InfoBarButton button) const {
  DCHECK(button == BUTTON_OK);
  return button_text_;
}

bool SyncErrorInfoBarDelegate::Accept() {
  switch (error_state_) {
    case syncer::SyncService::UserActionableError::kSignInNeedsUpdate:
      [presenter_ showPrimaryAccountReauth];
      break;

    case syncer::SyncService::UserActionableError::kNone:
      DCHECK(ShouldShowSyncSettings(error_state_));
      [presenter_ showAccountSettings];
      break;

    case syncer::SyncService::UserActionableError::kNeedsPassphrase:
      [presenter_ showSyncPassphraseSettings];
      break;

    case syncer::SyncService::UserActionableError::
        kNeedsTrustedVaultKeyForPasswords:
    case syncer::SyncService::UserActionableError::
        kNeedsTrustedVaultKeyForEverything:
      [presenter_
          showTrustedVaultReauthForFetchKeysWithTrigger:
              syncer::TrustedVaultUserActionTriggerForUMA::kNewTabPageInfobar];
      break;

    case syncer::SyncService::UserActionableError::
        kTrustedVaultRecoverabilityDegradedForPasswords:
    case syncer::SyncService::UserActionableError::
        kTrustedVaultRecoverabilityDegradedForEverything:
      [presenter_
          showTrustedVaultReauthForDegradedRecoverabilityWithTrigger:
              syncer::TrustedVaultUserActionTriggerForUMA::kNewTabPageInfobar];
      break;
  }

  return false;
}

void SyncErrorInfoBarDelegate::OnStateChanged(syncer::SyncService* sync) {
  // If the inforbar is in the process of being removed, nothing must be done.
  infobars::InfoBar* infobar = this->infobar();
  if (!infobar) {
    return;
  }
  syncer::SyncService* sync_service =
      SyncServiceFactory::GetForBrowserState(browser_state_);
  syncer::SyncService::UserActionableError new_error_state =
      sync_service->GetUserActionableError();
  if (error_state_ == new_error_state) {
    return;
  }
  error_state_ = new_error_state;
  if (new_error_state == syncer::SyncService::UserActionableError::kNone) {
    infobar->RemoveSelf();
  } else {
    infobars::InfoBarManager* infobar_manager = infobar->owner();
    if (infobar_manager) {
      std::unique_ptr<ConfirmInfoBarDelegate> new_infobar_delegate(
          new SyncErrorInfoBarDelegate(browser_state_, presenter_));
      infobar_manager->ReplaceInfoBar(
          infobar, CreateConfirmInfoBar(std::move(new_infobar_delegate)));
    }
  }
}