blob: 2352cc405510d53621b1475149eefb083422fe8b [file] [log] [blame]
// 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.
/**
* @fileoverview A polymer component that displays the currently selected
* wallpaper.
*/
import 'chrome://resources/cr_elements/cr_button/cr_button.js';
import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js';
import 'chrome://resources/polymer/v3_0/iron-iconset-svg/iron-iconset-svg.js';
import '../../common/icons.html.js';
import '../../css/wallpaper.css.js';
import '../../css/cros_button_style.css.js';
import './info_svg_element.js';
import './google_photos_shared_album_dialog_element.js';
import {loadTimeData} from 'chrome://resources/ash/common/load_time_data.m.js';
import {assert} from 'chrome://resources/js/assert_ts.js';
import {CurrentWallpaper, GooglePhotosPhoto, WallpaperLayout, WallpaperType} from '../../personalization_app.mojom-webui.js';
import {isGooglePhotosSharedAlbumsEnabled, isPersonalizationJellyEnabled} from '../load_time_booleans.js';
import {Paths} from '../personalization_router_element.js';
import {WithPersonalizationStore} from '../personalization_store.js';
import {getCheckmarkIcon, isNonEmptyArray} from '../utils.js';
import {getLocalStorageAttribution, getWallpaperLayoutEnum, getWallpaperSrc} from './utils.js';
import {getDailyRefreshState, selectGooglePhotosAlbum, setCurrentWallpaperLayout, setDailyRefreshCollectionId, updateDailyRefreshWallpaper} from './wallpaper_controller.js';
import {getWallpaperProvider} from './wallpaper_interface_provider.js';
import {WallpaperObserver} from './wallpaper_observer.js';
import {getTemplate} from './wallpaper_selected_element.html.js';
import {DailyRefreshState} from './wallpaper_state.js';
export class WallpaperSelected extends WithPersonalizationStore {
static get is() {
return 'wallpaper-selected';
}
static get template() {
return getTemplate();
}
static get properties() {
return {
/**
* The current collection id to display.
*/
collectionId: String,
/**
* Whether the google photos album is shared.
*/
isGooglePhotosAlbumShared: {
type: Boolean,
value: false,
},
/**
* The current Google Photos Album id to display.
*/
googlePhotosAlbumId: String,
/**
* The current path of the page.
*/
path: String,
photosByAlbumId_: Object,
image_: {
type: Object,
observer: 'onImageChanged_',
},
imageTitle_: {
type: String,
computed: 'computeImageTitle_(image_, dailyRefreshState_)',
},
imageOtherAttribution_: {
type: Array,
computed: 'computeImageOtherAttribution_(image_)',
},
dailyRefreshState_: Object,
isLoading_: Boolean,
hasError_: {
type: Boolean,
computed: 'computeHasError_(image_, isLoading_, error_)',
},
showDailyRefreshConfirmationDialog_: Boolean,
showImage_: {
type: Boolean,
computed: 'computeShowImage_(image_, isLoading_)',
},
showLayoutOptions_: {
type: Boolean,
computed:
'computeShowLayoutOptions_(image_, path, googlePhotosAlbumId)',
},
showDescriptionButton_: {
type: Boolean,
computed: 'computeShowDescriptionButton_(image_)',
},
showDescriptionDialog_: Boolean,
showDailyRefreshButton_: {
type: Boolean,
computed:
'computeShowDailyRefreshButton_(path,collectionId,googlePhotosAlbumId,photosByAlbumId_)',
},
showRefreshButton_: {
type: Boolean,
computed:
'computeShowRefreshButton_(path,collectionId,googlePhotosAlbumId,dailyRefreshState_)',
},
dailyRefreshIcon_: {
type: String,
computed:
'computeDailyRefreshIcon_(collectionId,googlePhotosAlbumId,dailyRefreshState_)',
},
ariaPressed_: {
type: String,
computed:
'computeAriaPressed_(collectionId,googlePhotosAlbumId,dailyRefreshState_)',
},
fillIcon_: {
type: String,
computed: 'computeFillIcon_(image_)',
},
centerIcon_: {
type: String,
computed: 'computeCenterIcon_(image_)',
},
error_: {
type: String,
value: null,
},
googlePhotosSharedAlbumsEnabled_: {
type: Boolean,
value() {
return isGooglePhotosSharedAlbumsEnabled();
},
},
};
}
// Only one of |collectionId| and |googlePhotosAlbumId| should ever be set,
// since we can't be in a Backdrop collection or a Google Photos album
// simultaneously
collectionId: string|undefined;
isGooglePhotosAlbumShared: boolean;
googlePhotosAlbumId: string|undefined;
path: string;
private image_: CurrentWallpaper|null;
private imageTitle_: string;
private imageOtherAttribution_: string[];
private dailyRefreshState_: DailyRefreshState|null;
private isLoading_: boolean;
private hasError_: boolean;
private showDailyRefreshConfirmationDialog_: boolean;
private showImage_: boolean;
private showLayoutOptions_: boolean;
private showDescriptionButton_: boolean;
private showDescriptionDialog_: boolean;
private showDailyRefreshButton_: boolean;
private showRefreshButton_: boolean;
private dailyRefreshIcon_: string;
private ariaPressed_: string;
private fillIcon_: string;
private centerIcon_: string;
private error_: string;
private googlePhotosSharedAlbumsEnabled_: boolean;
private photosByAlbumId_: Record<string, GooglePhotosPhoto[]|null|undefined>|
undefined;
override connectedCallback() {
super.connectedCallback();
WallpaperObserver.initWallpaperObserverIfNeeded();
this.watch('error_', state => state.error);
this.watch('image_', state => state.wallpaper.currentSelected);
this.watch(
'isLoading_',
state => state.wallpaper.loading.setImage > 0 ||
state.wallpaper.loading.selected ||
state.wallpaper.loading.refreshWallpaper);
this.watch('dailyRefreshState_', state => state.wallpaper.dailyRefresh);
this.watch(
'photosByAlbumId_',
state => state.wallpaper.googlePhotos.photosByAlbumId);
this.updateFromStore();
getDailyRefreshState(getWallpaperProvider(), this.getStore());
}
private computeShowImage_(image: CurrentWallpaper|null, loading: boolean):
boolean {
// Specifically check === false to avoid undefined case while component is
// initializing.
return loading === false && !!image;
}
private computeImageTitle_(
image: CurrentWallpaper|null,
dailyRefreshState: DailyRefreshState|null): string {
if (!image) {
return this.i18n('unknownImageAttribution');
}
if (image.type === WallpaperType.kDefault) {
return this.i18n('defaultWallpaper');
}
const isDailyRefreshActive = !!dailyRefreshState;
if (isNonEmptyArray(image.attribution)) {
const title = image.attribution[0];
return isDailyRefreshActive ? this.i18n('dailyRefresh') + ': ' + title :
title;
} else {
// Fallback to cached attribution.
const attribution = getLocalStorageAttribution(image.key);
if (isNonEmptyArray(attribution)) {
const title = attribution[0];
return isDailyRefreshActive ? this.i18n('dailyRefresh') + ': ' + title :
title;
}
}
return this.i18n('unknownImageAttribution');
}
private computeImageOtherAttribution_(image: CurrentWallpaper|
null): string[] {
if (!image) {
return [];
}
if (isNonEmptyArray(image.attribution)) {
return image.attribution.slice(1);
}
// Fallback to cached attribution.
const attribution = getLocalStorageAttribution(image.key);
if (isNonEmptyArray(attribution)) {
return attribution.slice(1);
}
return [];
}
private computeShowLayoutOptions_(
image: CurrentWallpaper|null, path: string,
googlePhotosAlbumId: string): boolean {
return !!image &&
((image.type === WallpaperType.kCustomized &&
path === Paths.LOCAL_COLLECTION ||
(image.type === WallpaperType.kOnceGooglePhotos &&
path === Paths.GOOGLE_PHOTOS_COLLECTION && !googlePhotosAlbumId)));
}
private computeShowDescriptionButton_(image: CurrentWallpaper|null) {
// Only show the description dialog if title and content exist.
return isPersonalizationJellyEnabled() && image?.descriptionContent &&
image?.descriptionTitle;
}
private isCollectionPath_(path: string): boolean {
return path === Paths.COLLECTION_IMAGES ||
path === Paths.GOOGLE_PHOTOS_COLLECTION;
}
private computeShowDailyRefreshButton_(
path: string, collectionId: string, googlePhotosAlbumId: string|undefined,
photosByAlbumId: Record<string, GooglePhotosPhoto[]|null|undefined>) {
if (!this.isCollectionPath_(path)) {
return false;
}
// Special collection where daily refresh is disabled.
if (collectionId ===
loadTimeData.getString('timeOfDayWallpaperCollectionId')) {
return false;
}
const isNonEmptyGooglePhotosAlbum = !!googlePhotosAlbumId &&
!!photosByAlbumId &&
isNonEmptyArray(photosByAlbumId[googlePhotosAlbumId]);
return path === Paths.COLLECTION_IMAGES ||
(path === Paths.GOOGLE_PHOTOS_COLLECTION &&
isNonEmptyGooglePhotosAlbum);
}
private computeShowRefreshButton_(
path: string, collectionId: string|undefined,
googlePhotosAlbumId: string|undefined,
dailyRefreshState: DailyRefreshState|null) {
if (!this.isCollectionPath_(path)) {
return false;
}
return (!collectionId && !googlePhotosAlbumId) ?
false :
this.isDailyRefreshId_(
collectionId! || googlePhotosAlbumId!, dailyRefreshState);
}
private getWallpaperSrc_(image: CurrentWallpaper|null): string|null {
return getWallpaperSrc(image);
}
private getCenterAriaPressed_(image: CurrentWallpaper): string {
return (!!image && image.layout === WallpaperLayout.kCenter).toString();
}
private getFillAriaPressed_(image: CurrentWallpaper): string {
return (!!image && image.layout === WallpaperLayout.kCenterCropped)
.toString();
}
private computeFillIcon_(image: CurrentWallpaper): string {
if (!!image && image.layout === WallpaperLayout.kCenterCropped) {
return getCheckmarkIcon();
}
return 'personalization:layout_fill';
}
private computeCenterIcon_(image: CurrentWallpaper): string {
if (!!image && image.layout === WallpaperLayout.kCenter) {
return getCheckmarkIcon();
}
return 'personalization:layout_center';
}
private onClickLayoutIcon_(event: Event) {
const eventTarget = event.currentTarget as HTMLElement;
const layout = getWallpaperLayoutEnum(eventTarget.dataset['layout']!);
setCurrentWallpaperLayout(layout, getWallpaperProvider(), this.getStore());
}
private computeDailyRefreshIcon_(
collectionId: string, googlePhotosAlbumId: string,
dailyRefreshState: DailyRefreshState|null): string {
if (this.isDailyRefreshId_(
collectionId || googlePhotosAlbumId, dailyRefreshState)) {
return getCheckmarkIcon();
}
return 'personalization:change-daily';
}
private computeAriaPressed_(
collectionId: string|undefined, googlePhotosAlbumId: string|undefined,
dailyRefreshState: DailyRefreshState|null): string {
if (this.isDailyRefreshId_(
collectionId || googlePhotosAlbumId, dailyRefreshState)) {
return 'true';
}
return 'false';
}
private onClickDailyRefreshToggle_() {
const dailyRefreshEnabled = this.isDailyRefreshId_(
this.collectionId || this.googlePhotosAlbumId, this.dailyRefreshState_);
if (dailyRefreshEnabled) {
this.disableDailyRefresh_();
} else {
this.enableDailyRefresh_();
}
}
/**
* Determine the current collection view belongs to the collection that is
* enabled with daily refresh. If true, highlight the toggle and display the
* refresh button
*/
private isDailyRefreshId_(
id: string|undefined,
dailyRefreshState: DailyRefreshState|null): boolean {
return dailyRefreshState ? id === dailyRefreshState.id : false;
}
private disableDailyRefresh_() {
if (this.googlePhotosAlbumId) {
assert(!this.collectionId);
selectGooglePhotosAlbum(
/*albumId=*/ '', getWallpaperProvider(), this.getStore());
} else {
setDailyRefreshCollectionId(
/*collectionId=*/ '', getWallpaperProvider(), this.getStore());
}
}
private enableDailyRefresh_() {
if (this.googlePhotosAlbumId) {
assert(!this.collectionId);
if (this.googlePhotosSharedAlbumsEnabled_ &&
this.isGooglePhotosAlbumShared) {
this.showDailyRefreshConfirmationDialog_ = true;
} else {
this.enableGooglePhotosAlbumDailyRefresh_();
}
} else {
setDailyRefreshCollectionId(
this.collectionId!, getWallpaperProvider(), this.getStore());
}
}
private enableGooglePhotosAlbumDailyRefresh_() {
selectGooglePhotosAlbum(
this.googlePhotosAlbumId!, getWallpaperProvider(), this.getStore());
}
private onClickShowDescription_() {
assert(
isPersonalizationJellyEnabled(),
'description dialog only available if personalization jelly enabled');
assert(
this.showDescriptionButton_,
'description dialog can only be opened if button is visible');
this.showDescriptionDialog_ = true;
}
private closeDescriptionDialog_() {
this.showDescriptionDialog_ = false;
}
private closeDailyRefreshConfirmationDialog_() {
this.showDailyRefreshConfirmationDialog_ = false;
this.shadowRoot!.getElementById('dailyRefresh')?.focus();
}
private onAcceptDailyRefreshDialog_() {
this.enableGooglePhotosAlbumDailyRefresh_();
this.closeDailyRefreshConfirmationDialog_();
}
private onClickUpdateDailyRefreshWallpaper_() {
updateDailyRefreshWallpaper(getWallpaperProvider(), this.getStore());
}
/**
* Determine whether there is an error in showing selected image. An error
* happens when there is no previously loaded image and either no new image
* is being loaded or there is an error from upstream.
*/
private computeHasError_(
image: CurrentWallpaper|null, loading: boolean,
error: string|null): boolean {
return (!loading || !!error) && !image;
}
private getAriaLabel_(
image: CurrentWallpaper|null,
dailyRefreshState: DailyRefreshState|null): string {
if (!image) {
return this.i18n('currentlySet') + ' ' +
this.i18n('unknownImageAttribution');
}
if (image.type === WallpaperType.kDefault) {
return `${this.i18n('currentlySet')} ${this.i18n('defaultWallpaper')}`;
}
const isDailyRefreshActive = !!dailyRefreshState;
if (isNonEmptyArray(image.attribution)) {
return isDailyRefreshActive ?
[
this.i18n('currentlySet'),
this.i18n('dailyRefresh'),
...image.attribution,
].join(' ') :
[this.i18n('currentlySet'), ...image.attribution].join(' ');
}
// Fallback to cached attribution.
const attribution = getLocalStorageAttribution(image.key);
if (isNonEmptyArray(attribution)) {
return isDailyRefreshActive ?
[
this.i18n('currentlySet'),
this.i18n('dailyRefresh'),
...image.attribution,
].join(' ') :
[this.i18n('currentlySet'), ...attribution].join(' ');
}
return this.i18n('currentlySet') + ' ' +
this.i18n('unknownImageAttribution');
}
/**
* Returns hidden state of loading placeholder.
*/
private showPlaceholders_(loading: boolean, showImage: boolean): boolean {
return loading || !showImage;
}
/**
* Cache the attribution in local storage when image is updated
* Populate the attribution map in local storage when image is updated
*/
private async onImageChanged_(
newImage: CurrentWallpaper|null, oldImage: CurrentWallpaper|null) {
const attributionMap =
JSON.parse((window.localStorage['attribution'] || '{}'));
if (attributionMap.size == 0 ||
!!newImage && !!oldImage && newImage.key !== oldImage.key) {
if (newImage) {
attributionMap[newImage.key] = newImage.attribution;
}
if (oldImage) {
delete attributionMap[oldImage.key];
}
window.localStorage['attribution'] = JSON.stringify(attributionMap);
}
}
/**
* Return a container class depending on loading state.
*/
private getContainerClass_(isLoading: boolean, showImage: boolean): string {
return this.showPlaceholders_(isLoading, showImage) ? 'loading' : '';
}
}
customElements.define(WallpaperSelected.is, WallpaperSelected);