blob: f166e606e0ca9501903f2e032cfa94d8883fd74a [file] [log] [blame]
// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import {assert} from 'chrome://resources/js/assert.m.js'
import {isNonEmptyArray} from '../common/utils.js';
import * as action from './personalization_actions.js';
import {WallpaperLayout, WallpaperType} from './personalization_reducers.js';
import {PersonalizationStore} from './personalization_store.js';
/**
* @fileoverview contains all of the functions to interact with C++ side through
* mojom calls. Handles setting |PersonalizationStore| state in response to
* mojom data.
* TODO(b/181697575) handle errors and allow user to retry these functions.
*/
/**
* Fetch wallpaper collections and save them to the store.
* @param {!chromeos.personalizationApp.mojom.WallpaperProviderInterface}
* provider
* @param {!PersonalizationStore} store
*/
async function fetchCollections(provider, store) {
let {collections} = await provider.fetchCollections();
if (!isNonEmptyArray(collections)) {
console.warn('Failed to fetch wallpaper collections');
collections = null;
}
store.dispatch(action.setCollectionsAction(collections));
}
/**
* Fetch all of the wallpaper collections one at a time.
* @param {!chromeos.personalizationApp.mojom.WallpaperProviderInterface}
* provider
* @param {!PersonalizationStore} store
*/
async function fetchAllImagesForCollections(provider, store) {
const collections = store.data.backdrop.collections;
if (!Array.isArray(collections)) {
console.warn(
'Cannot fetch data for collections when it is not initialized');
return;
}
store.dispatch(action.beginLoadImagesForCollectionsAction(collections));
for (const {id} of /** @type {!Array<{id: string}>} */ (collections)) {
let {images} = await provider.fetchImagesForCollection(id);
if (!isNonEmptyArray(images)) {
console.warn('Failed to fetch images for collection id', id);
images = null;
}
store.dispatch(action.setImagesForCollectionAction(id, images));
}
}
/**
* Get list of local images from disk and save it to the store.
* @param {!chromeos.personalizationApp.mojom.WallpaperProviderInterface}
* provider
* @param {!PersonalizationStore} store
*/
async function getLocalImages(provider, store) {
store.dispatch(action.beginLoadLocalImagesAction());
const {images} = await provider.getLocalImages();
if (images == null) {
console.warn('Failed to fetch local images');
}
store.dispatch(action.setLocalImagesAction(images));
}
/**
* Because thumbnail loading can happen asynchronously and is triggered
* on page load and on window focus, multiple "threads" can be fetching
* thumbnails simultaneously. Synchronize them with a task queue.
* @type {Set<string>}
*/
const imageThumbnailsToFetch = new Set();
/**
* Get an image thumbnail one at a time for every local image that does not have
* a thumbnail yet.
* @param {!chromeos.personalizationApp.mojom.WallpaperProviderInterface}
* provider
* @param {!PersonalizationStore} store
*/
async function getMissingLocalImageThumbnails(provider, store) {
if (!Array.isArray(store.data.local.images)) {
console.warn('Cannot fetch thumbnails with invalid image list');
return;
}
// Set correct loading state for each image thumbnail. Do in a batch update to
// reduce number of times that polymer must re-render.
store.beginBatchUpdate();
for (const filePath of store.data.local.images) {
if (store.data.local.data[filePath.path] ||
store.data.loading.local.data[filePath.path] ||
imageThumbnailsToFetch.has(filePath.path)) {
// Do not re-load thumbnail if already present, or already loading.
continue;
}
imageThumbnailsToFetch.add(filePath.path);
store.dispatch(action.beginLoadLocalImageDataAction(filePath));
}
store.endBatchUpdate();
// There may be multiple async tasks triggered that pull off this queue.
while (imageThumbnailsToFetch.size) {
const path = imageThumbnailsToFetch.values().next().value;
imageThumbnailsToFetch.delete(path);
const {data} = await provider.getLocalImageThumbnail({path});
if (!data) {
console.warn('Failed to fetch local image data', path);
}
store.dispatch(action.setLocalImageDataAction({path}, data));
}
}
/**
* @param {!chromeos.personalizationApp.mojom.WallpaperImage |
* !mojoBase.mojom.FilePath} image
* @param {!chromeos.personalizationApp.mojom.WallpaperProviderInterface}
* provider
* @param {!PersonalizationStore} store
*/
export async function selectWallpaper(image, provider, store) {
// Batch these changes together to reduce polymer churn as multiple state
// fields change quickly.
store.beginBatchUpdate();
store.dispatch(action.beginSelectImageAction(image));
store.dispatch(action.beginLoadSelectedImageAction());
const {tabletMode} = await provider.isInTabletMode();
const shouldPreview =
tabletMode && loadTimeData.getBoolean('fullScreenPreviewEnabled');
if (shouldPreview) {
store.dispatch(action.setFullscreenEnabledAction(/*enabled=*/ true))
}
store.endBatchUpdate();
const {success} = await (() => {
if (image.hasOwnProperty('assetId')) {
return provider.selectWallpaper(
image.assetId, /*preview_mode=*/ shouldPreview);
} else if (image.path) {
return provider.selectLocalImage(
/** @type {!mojoBase.mojom.FilePath} */ (image),
/*preview_mode=*/ shouldPreview);
} else {
console.warn('Image must be a local image or a WallpaperImage');
return {success: false};
}
})();
store.beginBatchUpdate();
store.dispatch(action.endSelectImageAction(image, success));
if (!success) {
console.warn('Error setting wallpaper');
store.dispatch(action.setSelectedImageAction(store.data.currentSelected));
}
store.endBatchUpdate();
}
/**
* @param {!chromeos.personalizationApp.mojom.WallpaperLayout} layout
* @param {!chromeos.personalizationApp.mojom.WallpaperProviderInterface}
* provider
* @param {!PersonalizationStore} store
*/
export async function setCustomWallpaperLayout(layout, provider, store) {
const image = store.data.currentSelected;
assert(image.type === WallpaperType.kCustomized);
assert(
layout === WallpaperLayout.kCenter ||
layout === WallpaperLayout.kCenterCropped);
if (image.layout === layout)
return;
store.dispatch(action.beginLoadSelectedImageAction());
await provider.setCustomWallpaperLayout(layout);
}
/**
* @param {string} collectionId
* @param {!chromeos.personalizationApp.mojom.WallpaperProviderInterface}
* provider
* @param {!PersonalizationStore} store
*/
export async function setDailyRefreshCollectionId(
collectionId, provider, store) {
await provider.setDailyRefreshCollectionId(collectionId);
// Dispatch action to highlight enabled daily refresh.
getDailyRefreshCollectionId(provider, store);
}
/**
* Get the daily refresh collection id. It can be empty if daily refresh is not
* enabled.
* @param {!chromeos.personalizationApp.mojom.WallpaperProviderInterface}
* provider
* @param {!PersonalizationStore} store
*/
export async function getDailyRefreshCollectionId(provider, store) {
const {collectionId} = await provider.getDailyRefreshCollectionId();
store.dispatch(action.setDailyRefreshCollectionIdAction(collectionId));
}
/**
* Refresh the wallpaper. Noop if daily refresh is not enabled.
* @param {!chromeos.personalizationApp.mojom.WallpaperProviderInterface}
* provider
* @param {!PersonalizationStore} store
*/
export async function updateDailyRefreshWallpaper(provider, store) {
store.dispatch(action.beginUpdateDailyRefreshImageAction());
store.dispatch(action.beginLoadSelectedImageAction());
const {success} = await provider.updateDailyRefreshWallpaper();
if (success) {
store.dispatch(action.setUpdatedDailyRefreshImageAction());
}
}
/**
* Confirm and set preview wallpaper as actual wallpaper.
* @param {!chromeos.personalizationApp.mojom.WallpaperProviderInterface}
* provider
*/
export async function confirmPreviewWallpaper(provider) {
await provider.confirmPreviewWallpaper();
}
/**
* Cancel preview wallpaper and show the previous wallpaper.
* @param {!chromeos.personalizationApp.mojom.WallpaperProviderInterface}
* provider
*/
export async function cancelPreviewWallpaper(provider) {
await provider.cancelPreviewWallpaper();
}
/**
* Fetches list of collections, then fetches list of images for each collection.
* @param {!chromeos.personalizationApp.mojom.WallpaperProviderInterface}
* provider
* @param {!PersonalizationStore} store
*/
export async function initializeBackdropData(provider, store) {
await fetchCollections(provider, store);
await fetchAllImagesForCollections(provider, store);
}
/**
* Gets list of local images, then fetches image thumbnails for each local
* image.
* @param {!chromeos.personalizationApp.mojom.WallpaperProviderInterface}
* provider
* @param {!PersonalizationStore} store
*/
export async function fetchLocalData(provider, store) {
// Do not restart loading local image list if a load is already in progress.
if (!store.data.loading.local.images) {
await getLocalImages(provider, store);
}
await getMissingLocalImageThumbnails(provider, store);
}