| // Copyright 2022 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import 'chrome://resources/cr_elements/cr_button/cr_button.js'; |
| import 'chrome://resources/cr_elements/cr_icon/cr_icon.js'; |
| import 'chrome://resources/cr_elements/icons.html.js'; |
| import '/strings.m.js'; |
| |
| import type {CrButtonElement} from 'chrome://resources/cr_elements/cr_button/cr_button.js'; |
| import {I18nMixinLit} from 'chrome://resources/cr_elements/i18n_mixin_lit.js'; |
| import {WebUiListenerMixinLit} from 'chrome://resources/cr_elements/web_ui_listener_mixin_lit.js'; |
| import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; |
| import {CrLitElement} from 'chrome://resources/lit/v3_0/lit.rollup.js'; |
| |
| import type {IntroBrowserProxy} from './browser_proxy.js'; |
| import {IntroBrowserProxyImpl} from './browser_proxy.js'; |
| import {getCss} from './sign_in_promo.css.js'; |
| import {getHtml} from './sign_in_promo.html.js'; |
| |
| export interface SignInPromoElement { |
| $: { |
| acceptSignInButton: CrButtonElement, |
| buttonRow: HTMLElement, |
| contentArea: HTMLElement, |
| declineSignInButton: CrButtonElement, |
| disclaimerText: HTMLElement, |
| managedDeviceDisclaimer: HTMLElement, |
| safeZone: HTMLElement, |
| }; |
| } |
| |
| export interface BenefitCard { |
| title: string; |
| description: string; |
| iconId: string; |
| } |
| |
| const SignInPromoElementBase = |
| WebUiListenerMixinLit(I18nMixinLit(CrLitElement)); |
| |
| export class SignInPromoElement extends SignInPromoElementBase { |
| static get is() { |
| return 'sign-in-promo'; |
| } |
| |
| constructor() { |
| super(); |
| this.benefitCards_ = [ |
| { |
| title: this.i18n('devicesCardTitle'), |
| description: this.i18n('devicesCardDescription'), |
| iconId: 'devices', |
| }, |
| { |
| title: this.i18n('securityCardTitle'), |
| description: this.i18n('securityCardDescription'), |
| iconId: 'security', |
| }, |
| { |
| title: this.i18n('backupCardTitle'), |
| description: this.i18n('backupCardDescription'), |
| iconId: 'cloud-upload', |
| }, |
| ]; |
| } |
| |
| static override get styles() { |
| return getCss(); |
| } |
| |
| override render() { |
| return getHtml.bind(this)(); |
| } |
| |
| static override get properties() { |
| return { |
| /** |
| * The list of benefits the user will get when signed in to Chrome |
| */ |
| benefitCards_: {type: Array}, |
| |
| managedDeviceDisclaimer_: {type: String}, |
| isDeviceManaged_: {type: Boolean}, |
| anyButtonClicked_: {type: Boolean}, |
| }; |
| } |
| |
| private browserProxy_: IntroBrowserProxy = |
| IntroBrowserProxyImpl.getInstance(); |
| protected accessor benefitCards_: BenefitCard[]; |
| private divisionLineResizeObserver_: ResizeObserver|null = null; |
| protected accessor managedDeviceDisclaimer_: string = ''; |
| protected accessor isDeviceManaged_: boolean = |
| loadTimeData.getBoolean('isDeviceManaged'); |
| private accessor anyButtonClicked_: boolean = false; |
| |
| override connectedCallback() { |
| super.connectedCallback(); |
| |
| this.browserProxy_.initializeMainView(); |
| this.toggleDivisionLine_(); |
| |
| if (this.isDeviceManaged_) { |
| this.addWebUiListener( |
| 'managed-device-disclaimer-updated', |
| this.handleManagedDeviceDisclaimerUpdate_.bind(this)); |
| } |
| |
| this.addWebUiListener('reset-intro-buttons', this.resetButtons_.bind(this)); |
| } |
| |
| override disconnectedCallback() { |
| super.disconnectedCallback(); |
| this.divisionLineResizeObserver_!.disconnect(); |
| } |
| |
| override firstUpdated() { |
| this.addEventListener( |
| 'view-enter-start', this.onViewEnterStart_.bind(this)); |
| } |
| |
| private onViewEnterStart_() { |
| this.setTranslationHeightToAlignLogoAndAnimation_(); |
| } |
| |
| private toggleDivisionLine_() { |
| const safeZone = this.$.safeZone; |
| |
| this.divisionLineResizeObserver_ = new ResizeObserver(() => { |
| this.$.buttonRow.classList.toggle( |
| 'division-line', safeZone.scrollHeight > safeZone.clientHeight); |
| }); |
| this.divisionLineResizeObserver_.observe(safeZone); |
| } |
| |
| private resetButtons_() { |
| this.anyButtonClicked_ = false; |
| } |
| |
| private handleManagedDeviceDisclaimerUpdate_(disclaimer: string) { |
| this.managedDeviceDisclaimer_ = disclaimer; |
| } |
| |
| /** |
| * Disable buttons if the device is managed until the management |
| * disclaimer is loaded or if a button was clicked. |
| */ |
| protected areButtonsDisabled_(): boolean { |
| return (this.isDeviceManaged_ && |
| this.managedDeviceDisclaimer_.length === 0) || |
| this.anyButtonClicked_; |
| } |
| |
| // At the start of the signInPromo animation, the product logo should be at |
| // the same position as the splash view logo animation. To be able |
| // to do that, we had to translate the safeZone vertically up by the value |
| // calculated in the function below, after doing top:50%. |
| private setTranslationHeightToAlignLogoAndAnimation_() { |
| const contentAreaHeight = this.$.contentArea.clientHeight; |
| const safeZoneHeight = this.$.safeZone.clientHeight; |
| const productLogoMarginTop = parseInt( |
| getComputedStyle(this).getPropertyValue('--product-logo-margin-top')); |
| const productLogoSize = parseInt( |
| getComputedStyle(this).getPropertyValue('--product-logo-size')); |
| |
| const contentAreaAndSafeZoneHeightDifference = |
| contentAreaHeight < safeZoneHeight ? |
| safeZoneHeight - contentAreaHeight : |
| 0; |
| const translationHeight = contentAreaAndSafeZoneHeightDifference / 2 + |
| productLogoMarginTop + productLogoSize / 2; |
| |
| this.style.setProperty( |
| '--safe-zone-animation-translation-height', translationHeight + 'px'); |
| } |
| |
| protected onContinueWithAccountClick_() { |
| this.anyButtonClicked_ = true; |
| this.browserProxy_.continueWithAccount(); |
| } |
| |
| protected onContinueWithoutAccountClick_() { |
| this.anyButtonClicked_ = true; |
| this.browserProxy_.continueWithoutAccount(); |
| } |
| |
| // To keep the layout stable during animations, for managed devices it is |
| // invisible while we're fetching the text to display. |
| protected getDisclaimerVisibilityClass_() { |
| return this.managedDeviceDisclaimer_.length === 0 ? 'temporarily-hidden' : |
| 'fast-fade-in'; |
| } |
| } |
| |
| declare global { |
| interface HTMLElementTagNameMap { |
| 'sign-in-promo': SignInPromoElement; |
| } |
| } |
| |
| customElements.define(SignInPromoElement.is, SignInPromoElement); |