// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// strings.m.js is generated when we enable it via UseStringsJs() in webUI
// controller. When loading it, it will populate data such as localized strings
// into |loadTimeData|.
import './strings.m.js';
import './parent_access_after.js';
import './parent_access_before.js';
import './parent_access_disabled.js';
import './parent_access_error.js';
import './parent_access_offline.js';
import './parent_access_ui.js';
import 'chrome://resources/ash/common/cr_elements/cros_color_overrides.css.js';
import 'chrome://resources/ash/common/cr_elements/cr_view_manager/cr_view_manager.js';
import {CrViewManagerElement} from 'chrome://resources/ash/common/cr_elements/cr_view_manager/cr_view_manager.js';
import {loadTimeData} from 'chrome://resources/ash/common/load_time_data.m.js';
import {ColorChangeUpdater} from 'chrome://resources/cr_components/color_change_listener/colors_css_updater.js';
import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {getTemplate} from './parent_access_app.html.js';
import {ParentAccessParams_FlowType, ParentAccessResult} from './parent_access_ui.mojom-webui.js';
import {getParentAccessParams, getParentAccessUiHandler} from './parent_access_ui_handler.js';
export interface ParentAccessApp {
$: {
viewManager: CrViewManagerElement,
};
}
export enum Screens {
AUTHENTICATION_FLOW = 'parent-access-ui',
BEFORE_FLOW = 'parent-access-before',
AFTER_FLOW = 'parent-access-after',
DISABLED = 'parent-access-disabled',
ERROR = 'parent-access-error',
OFFLINE = 'parent-access-offline',
}
export enum ParentAccessEvent {
SHOW_AFTER = 'show-after',
SHOW_AUTHENTICATION_FLOW = 'show-authentication-flow',
SHOW_ERROR = 'show-error',
// Individual screens can listen for this event to be notified when the screen
// becomes active.
ON_SCREEN_SWITCHED = 'on-screen-switched',
}
/**
* Returns true if the Parent Access Jelly feature flag is enabled.
* @return {boolean}
*/
export function isParentAccessJellyEnabled() {
return loadTimeData.valueExists('isParentAccessJellyEnabled') &&
loadTimeData.getBoolean('isParentAccessJellyEnabled');
}
export class ParentAccessApp extends PolymerElement {
static get is() {
return 'parent-access-app';
}
static get template() {
return getTemplate();
}
private currentScreen: Screens;
override ready() {
super.ready();
// TODO (b/297564545): Clean up Jelly flag logic after Jelly is enabled.
if (isParentAccessJellyEnabled()) {
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = 'chrome://theme/colors.css?sets=legacy,sys';
document.head.appendChild(link);
document.body.classList.add('jelly-enabled');
/** @suppress {checkTypes} */
(function() {
ColorChangeUpdater.forDocument().start();
})();
}
this.addEventListeners();
this.getInitialScreen().then((initialScreen: Screens) => {
this.switchScreen(navigator.onLine ? initialScreen : Screens.OFFLINE);
});
}
getCurrentScreenForTest(): Screens {
return this.currentScreen;
}
private addEventListeners() {
this.addEventListener(ParentAccessEvent.SHOW_AFTER, () => {
this.switchScreen(Screens.AFTER_FLOW);
});
this.addEventListener(ParentAccessEvent.SHOW_AUTHENTICATION_FLOW, () => {
this.switchScreen(Screens.AUTHENTICATION_FLOW);
getParentAccessUiHandler().onBeforeScreenDone();
});
this.addEventListener(ParentAccessEvent.SHOW_ERROR, () => {
this.onError();
});
window.addEventListener('online', () => {
// If the app comes back online, start from the initial screen.
this.getInitialScreen().then((initialScreen: Screens) => {
this.switchScreen(initialScreen);
});
});
window.addEventListener('offline', () => {
this.switchScreen(Screens.OFFLINE);
});
}
private async getInitialScreen() {
const response = await getParentAccessParams();
if (response!.params.isDisabled) {
return Screens.DISABLED;
}
switch (response!.params.flowType) {
case ParentAccessParams_FlowType.kExtensionAccess:
return Screens.BEFORE_FLOW;
case ParentAccessParams_FlowType.kWebsiteAccess:
default:
return Screens.AUTHENTICATION_FLOW;
}
}
/** Shows an error screen, which is a terminal state for the flow. */
private onError() {
this.switchScreen(Screens.ERROR);
getParentAccessUiHandler().onParentAccessDone(ParentAccessResult.kError);
}
private switchScreen(screen: Screens) {
if (this.isAppInTerminalState()) {
return;
}
this.currentScreen = screen;
this.$.viewManager.switchView(this.currentScreen);
this.shadowRoot!.querySelector(screen)!.dispatchEvent(
new CustomEvent(ParentAccessEvent.ON_SCREEN_SWITCHED));
}
/** Returns if the app can navigate away from the current screen. */
private isAppInTerminalState(): boolean {
return this.currentScreen === Screens.ERROR ||
this.currentScreen === Screens.DISABLED;
}
}
customElements.define(ParentAccessApp.is, ParentAccessApp);