chromium/chrome/browser/ui/webui/password_manager/promo_cards/move_passwords_promo.cc

// 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.

#include "chrome/browser/ui/webui/password_manager/promo_cards/move_passwords_promo.h"

#include "chrome/browser/signin/identity_manager_factory.h"
#include "chrome/browser/sync/sync_service_factory.h"
#include "chrome/grit/generated_resources.h"
#include "components/password_manager/core/browser/features/password_manager_features_util.h"
#include "components/signin/public/identity_manager/identity_manager.h"
#include "components/sync/service/sync_service.h"
#include "components/sync/service/sync_service_utils.h"
#include "ui/base/l10n/l10n_util.h"

namespace {
constexpr base::TimeDelta kMovePasswordsPromoPeriod = base::Days(7);

using extensions::api::passwords_private::CredentialGroup;
using extensions::api::passwords_private::PasswordUiEntry;

constexpr char kMovePasswordsId[] = "move_passwords_promo";

syncer::SyncService* GetSyncService(Profile* profile) {
  return SyncServiceFactory::IsSyncAllowed(profile)
             ? SyncServiceFactory::GetForProfile(profile)
             : nullptr;
}

// Checks if there are passwords saved only to this device.
bool HasLocalPasswords(extensions::PasswordsPrivateDelegate* delegate) {
  if (!delegate) {
    return false;
  }

  auto is_entry_saved_locally = [](const PasswordUiEntry& entry) {
    return entry.stored_in == extensions::api::passwords_private::
                                  PasswordStoreSet::kDeviceAndAccount ||
           entry.stored_in ==
               extensions::api::passwords_private::PasswordStoreSet::kDevice;
  };

  auto has_credential_group_with_local_passwords =
      [&is_entry_saved_locally](const CredentialGroup& credential_group) {
        return std::ranges::any_of(credential_group.entries,
                                   is_entry_saved_locally);
      };

  return std::ranges::any_of(delegate->GetCredentialGroups(),
                             has_credential_group_with_local_passwords);
}

std::u16string GetPrimaryAccountEmailFromProfile(Profile* profile) {
  if (!profile) {
    return std::u16string();
  }
  signin::IdentityManager* identity_manager =
      IdentityManagerFactory::GetForProfile(profile);
  if (!identity_manager) {
    return std::u16string();
  }
  return base::UTF8ToUTF16(
      identity_manager->GetPrimaryAccountInfo(signin::ConsentLevel::kSignin)
          .email);
}

}  // namespace

MovePasswordsPromo::MovePasswordsPromo(
    Profile* profile,
    extensions::PasswordsPrivateDelegate* delegate)
    : password_manager::PasswordPromoCardBase(kMovePasswordsId,
                                              profile->GetPrefs()),
      profile_(profile) {
  CHECK(delegate);
  delegate_ = delegate->AsWeakPtr();
}

MovePasswordsPromo::~MovePasswordsPromo() = default;

std::string MovePasswordsPromo::GetPromoID() const {
  return kMovePasswordsId;
}

password_manager::PromoCardType MovePasswordsPromo::GetPromoCardType() const {
  return password_manager::PromoCardType::kMovePasswords;
}

bool MovePasswordsPromo::ShouldShowPromo() const {
  CHECK(profile_);
  syncer::SyncService* sync_service = GetSyncService(profile_);
  if (!sync_service ||
      !password_manager::features_util::IsOptedInForAccountStorage(
          profile_->GetPrefs(), sync_service)) {
    return false;
  }

  // If promo card was dismissed or shown already for
  // `kPromoDisplayLimit` times, show it in a week next time.
  bool should_suppress =
      was_dismissed_ ||
      number_of_times_shown_ >= PasswordPromoCardBase::kPromoDisplayLimit;

  bool bubble_is_not_over_prompted =
      !should_suppress ||
      base::Time().Now() - last_time_shown_ > kMovePasswordsPromoPeriod;

  return bubble_is_not_over_prompted && HasLocalPasswords(delegate_.get());
}

std::u16string MovePasswordsPromo::GetTitle() const {
  return l10n_util::GetStringUTF16(
      IDS_PASSWORD_MANAGER_UI_MOVE_PASSWORDS_PROMO_CARD_TITLE);
}

std::u16string MovePasswordsPromo::GetDescription() const {
  CHECK(profile_);
  return l10n_util::GetStringFUTF16(
      IDS_PASSWORD_MANAGER_UI_MOVE_PASSWORDS_PROMO_CARD_DESCRIPTION,
      GetPrimaryAccountEmailFromProfile(profile_));
}

std::u16string MovePasswordsPromo::GetActionButtonText() const {
  return l10n_util::GetStringUTF16(
      IDS_PASSWORD_MANAGER_UI_MOVE_PASSWORDS_PROMO_CARD_ACTION_BUTTON);
}