blob: 896fdc5c8a9d8eafb8e8117b6d044a943dc9bf2b [file] [log] [blame]
// Copyright 2020 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_view_manager/cr_view_manager.js';
import 'chrome://resources/cr_elements/cr_lazy_render/cr_lazy_render_lit.js';
import './profile_picker_main_view.js';
import '/strings.m.js';
import type {CrViewManagerElement} from 'chrome://resources/cr_elements/cr_view_manager/cr_view_manager.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 {assert, assertNotReached} from 'chrome://resources/js/assert.js';
import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
import {CrLitElement} from 'chrome://resources/lit/v3_0/lit.rollup.js';
import {ensureLazyLoaded} from './ensure_lazy_loaded.js';
import type {AutogeneratedThemeColorInfo, ManageProfilesBrowserProxy} from './manage_profiles_browser_proxy.js';
import {ManageProfilesBrowserProxyImpl} from './manage_profiles_browser_proxy.js';
import {navigateTo, NavigationMixin, ProfileCreationSteps, Routes} from './navigation_mixin.js';
import {getCss} from './profile_picker_app.css.js';
import {getHtml} from './profile_picker_app.html.js';
import {isForceSigninEnabled, isGlicVersion, isProfileCreationAllowed} from './profile_picker_flags.js';
export interface ProfilePickerAppElement {
$: {
viewManager: CrViewManagerElement,
};
}
const ProfilePickerAppElementBase =
WebUiListenerMixinLit(I18nMixinLit(NavigationMixin(CrLitElement)));
// Helper enum to determine which 'mode' the app should display. Used in the CSS
// styling, where the string literals are used for attributes matching.
enum AppMode {
REGULAR = 'regular',
NO_BANNER = 'no-banner',
GLIC = 'glic',
}
export class ProfilePickerAppElement extends ProfilePickerAppElementBase {
static get is() {
return 'profile-picker-app';
}
static override get styles() {
return getCss();
}
override render() {
return getHtml.bind(this)();
}
static override get properties() {
return {
/**
* Suggested new profile theme info for the profile creation flow.
*/
newProfileThemeInfo: {
type: Object,
notify: true,
},
/**
* True if a new profile (local or signed-in) is being created, all
* buttons that create a new profile are then disabled (to avoid creating
* two profiles).
*/
profileCreationInProgress: {
type: Boolean,
notify: true,
},
// Reflected as `app-mode_` to be used in the CSS styling with attributes
// matching.
appMode_: {
type: String,
reflect: true,
},
};
}
accessor newProfileThemeInfo: AutogeneratedThemeColorInfo|undefined;
accessor profileCreationInProgress: boolean = false;
protected shouldDisplayVerticalBanners_: boolean = false;
private currentRoute_: Routes|null = null;
private manageProfilesBrowserProxy_: ManageProfilesBrowserProxy =
ManageProfilesBrowserProxyImpl.getInstance();
protected accessor appMode_: AppMode = AppMode.REGULAR;
override connectedCallback() {
super.connectedCallback();
this.setMinimumSize_();
}
override onRouteChange(route: Routes, step: string) {
if (!isProfileCreationAllowed() && route === Routes.NEW_PROFILE) {
navigateTo(Routes.MAIN);
return;
}
if (step === ProfileCreationSteps.LOAD_FORCE_SIGNIN) {
assert(
route === Routes.NEW_PROFILE,
'LOAD_FORCE_SIGNIN step must be a part of NEW_PROFILE route');
assert(
isForceSigninEnabled(),
'Force signin policy must be enabled to start the force signin flow');
// The force sign-in flow is displayed in a dialog on top of the main
// view. Load the main view if it isn't already shown.
// Do not call `navigateTo(Routes.MAIN)` to not update the history.
// It's fine to skip `initializeModules()` for the main view since the
// main view will never be lazy loaded.
if (this.currentRoute_ !== Routes.MAIN) {
this.currentRoute_ = Routes.MAIN;
document.title = this.getDocumentTitle_('mainView');
this.$.viewManager.switchView('mainView', 'fade-in', 'no-animation');
}
this.manageProfilesBrowserProxy_.selectNewAccount(null);
return;
}
assert(
step !== ProfileCreationSteps.LOAD_SIGNIN,
'LOAD_SIGNIN should not appear in navigation (only used for metrics)');
if (step === ProfileCreationSteps.LOCAL_PROFILE_CUSTOMIZATION) {
if (this.profileCreationInProgress) {
return;
}
this.profileCreationInProgress = true;
// TODO(crbug.com/40209493): Add createShortcut parameter.
this.initializeNewProfileThemeInfo_().then(
() => this.manageProfilesBrowserProxy_.continueWithoutAccount(
this.newProfileThemeInfo!.color));
return;
}
const setStep = () => {
document.title = this.getDocumentTitle_(step);
this.updateAppMode_(step);
this.$.viewManager.switchView(step, 'fade-in', 'no-animation');
};
// If the route changed, initialize modules for that route.
if (this.currentRoute_ !== route) {
this.currentRoute_ = route;
this.initializeModules_().then(setStep);
} else {
setStep();
}
}
private updateAppMode_(step: string) {
if (this.currentRoute_ === Routes.MAIN ||
(this.currentRoute_ === Routes.NEW_PROFILE &&
step === ProfileCreationSteps.PROFILE_TYPE_CHOICE)) {
this.appMode_ = isGlicVersion() ? AppMode.GLIC : AppMode.REGULAR;
} else {
assert(!isGlicVersion(), 'Only `Routes.MAIN` supports Glic version');
this.appMode_ = AppMode.NO_BANNER;
}
}
private getDocumentTitle_(step: string): string {
switch (step) {
case 'mainView':
// This is needed because some version of the title have parts of the
// text with special styling through the `class`.
return this.i18nAdvanced('mainViewTitle', {attrs: ['class']})
.toString();
case ProfileCreationSteps.PROFILE_TYPE_CHOICE:
return this.i18n('profileTypeChoiceTitle');
case ProfileCreationSteps.LOCAL_PROFILE_CUSTOMIZATION:
return this.i18n('localProfileCreationTitle');
case 'profileSwitch':
return this.i18n('profileSwitchTitle');
default:
return '';
}
}
private initializeModules_(): Promise<any> {
switch (this.currentRoute_) {
case Routes.MAIN:
return Promise.resolve();
case Routes.NEW_PROFILE:
return Promise.all(
[this.initializeNewProfileThemeInfo_(), ensureLazyLoaded()]);
case Routes.PROFILE_SWITCH:
return ensureLazyLoaded();
default:
// |this.currentRoute_| should be set by now.
assertNotReached();
}
}
private async initializeNewProfileThemeInfo_(): Promise<void> {
if (this.newProfileThemeInfo) {
return Promise.resolve();
}
this.newProfileThemeInfo = await this.manageProfilesBrowserProxy_
.getNewProfileSuggestedThemeInfo();
}
private setMinimumSize_() {
this.style.setProperty(
'--view-min-size', loadTimeData.getString('minimumPickerSize'));
}
}
declare global {
interface HTMLElementTagNameMap {
'profile-picker-app': ProfilePickerAppElement;
}
}
customElements.define(ProfilePickerAppElement.is, ProfilePickerAppElement);