personalization: Stub in photos grid for Google Photos collection.
Demo: http://shortn/_jtLy7ONoQ6
Note 1: This CL assumes that the photos grid does not need to be
implemented in an untrusted iframe in order render images in the future.
Note 2: This CL does *not* use a 'grid' iron-list as the spec for the
Google Photos collection [1] requires grouping photos under a header by
date/location. That is not possible to do via a 'grid' iron-list, so
this CL uses a 'list' iron-list and constructs the grid manually.
Headers will be added in a future CL.
[1] http://shortn/_2eijfld3iS
Bug: b:204610310
Change-Id: I4945b0f65c8b8055839b3b0cb3da6c6e713f54c3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3253769
Commit-Queue: David Black <dmblack@google.com>
Reviewed-by: Jeffrey Young <cowmoo@chromium.org>
Cr-Commit-Position: refs/heads/main@{#938102}
diff --git a/ash/webui/personalization_app/resources/common/styles.js b/ash/webui/personalization_app/resources/common/styles.js
index d53ed05..8c465b6e 100644
--- a/ash/webui/personalization_app/resources/common/styles.js
+++ b/ash/webui/personalization_app/resources/common/styles.js
@@ -14,6 +14,10 @@
<template>
<style>
:host {
+ --personalization-app-grid-item-border-radius: 12px;
+ --personalization-app-grid-item-height: 120px;
+ --personalization-app-grid-item-spacing: 16px;
+
--personalization-app-text-shadow-elevation-1: 0 1px 3px
rgba(0, 0, 0, 15%), 0 1px 2px rgba(0, 0, 0, 30%);
@@ -37,10 +41,11 @@
}
.photo-container {
box-sizing: border-box;
- /* 8 + 120 + 8 */
- height: 136px;
+ height: calc(
+ var(--personalization-app-grid-item-height) +
+ var(--personalization-app-grid-item-spacing));
overflow: hidden;
- padding: 8px;
+ padding: calc(var(--personalization-app-grid-item-spacing) / 2);
/* Media queries in trusted and untrusted code will resize to 25% at
* correct widths. Subtract 0.34px to fix subpixel rounding issues with
* iron-list. This makes sure all photo containers on a row add up to at
@@ -54,7 +59,7 @@
elements ignoring parent interior padding. */
.photo-inner-container {
align-items: center;
- border-radius: 12px;
+ border-radius: var(--personalization-app-grid-item-border-radius);
display: flex;
cursor: pointer;
height: 100%;
diff --git a/ash/webui/personalization_app/resources/common/utils.js b/ash/webui/personalization_app/resources/common/utils.js
index 3b73b96..537967f8 100644
--- a/ash/webui/personalization_app/resources/common/utils.js
+++ b/ash/webui/personalization_app/resources/common/utils.js
@@ -86,3 +86,30 @@
export function getLoadingPlaceholderAnimationDelay(index) {
return `--animation-delay: ${index * 83}ms;`;
}
+
+/**
+ * Returns the number of grid items to render per row given the current inner
+ * width of the |window|.
+ * @return {number}
+ */
+export function getNumberOfGridItemsPerRow() {
+ return window.innerWidth > 688 ? 4 : 3;
+}
+
+/**
+ * Normalizes the given |key| for RTL.
+ * @param {string} key
+ * @param {boolean} isRTL
+ * @return {string}
+ */
+export function normalizeKeyForRTL(key, isRTL) {
+ if (isRTL) {
+ if (key === 'ArrowLeft') {
+ return 'ArrowRight';
+ }
+ if (key === 'ArrowRight') {
+ return 'ArrowLeft';
+ }
+ }
+ return key;
+}
diff --git a/ash/webui/personalization_app/resources/trusted/BUILD.gn b/ash/webui/personalization_app/resources/trusted/BUILD.gn
index 573426c4..4cb5659e 100644
--- a/ash/webui/personalization_app/resources/trusted/BUILD.gn
+++ b/ash/webui/personalization_app/resources/trusted/BUILD.gn
@@ -36,6 +36,7 @@
":personalization_store",
":styles",
"../common:styles",
+ "../common:utils",
"//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
]
}
diff --git a/ash/webui/personalization_app/resources/trusted/google_photos_element.html b/ash/webui/personalization_app/resources/trusted/google_photos_element.html
index d67e8309..f1c3196a 100644
--- a/ash/webui/personalization_app/resources/trusted/google_photos_element.html
+++ b/ash/webui/personalization_app/resources/trusted/google_photos_element.html
@@ -4,22 +4,32 @@
}
#main {
+ display: flex;
+ flex-direction: column;
height: 100%;
- overflow-y: auto;
+ overflow: hidden;
width: 100%;
}
- cr-button {
+ .tab-strip {
+ flex: 0 0 auto;
+ width: 100%;
+ }
+
+ .tab-strip > cr-button {
border: 0;
}
- cr-button[aria-pressed=false] {
+ .tab-strip > cr-button[aria-pressed='false'] {
color: var(--cros-text-color-secondary);
}
#albumsContent,
#photosContent {
+ flex: 1 1 auto;
height: 100%;
+ margin-top: var(--personalization-app-grid-item-spacing);
+ overflow: hidden;
width: 100%;
}
@@ -28,13 +38,64 @@
background-color: red;
}
- #photosContent {
- /** TODO(dmblack): Remove when implementing UI. */
- background-color: blue;
+ #photosContent > iron-list {
+ height: 100%;
+ width: 100%;
+ }
+
+ #photosContent > iron-list > .row {
+ display: flex;
+ flex-direction: row;
+ width: 100%;
+ }
+
+ #photosContent > iron-list > .row:focus-visible {
+ outline: 0;
+ }
+
+ #photosContent > iron-list > .row:not([rowindex='0']) {
+ padding-top: var(--personalization-app-grid-item-spacing);
+ }
+
+ #photosContent > iron-list > .row > .photo {
+ align-items: center;
+ background: rgba(0, 0, 0, 0.12);
+ border-radius: var(--personalization-app-grid-item-border-radius);
+ display: flex;
+ flex: 1 1 auto;
+ height: var(--personalization-app-grid-item-height);
+ justify-content: center;
+ position: relative;
+ width: 100%;
+ }
+
+ #photosContent > iron-list > .row > .photo:focus-visible {
+ outline: 0;
+ }
+
+ #photosContent > iron-list > .row > .photo:focus-visible::before {
+ border: 2px solid var(--cros-focus-ring-color);
+ border-radius: var(--personalization-app-grid-item-border-radius);
+ box-sizing: border-box;
+ content: '';
+ display: block;
+ height: 100%;
+ left: 0;
+ position: absolute;
+ top: 0;
+ width: 100%;
+ }
+
+ #photosContent > iron-list > .row > .photo:not(:first-of-type) {
+ margin-inline-start: calc(var(--personalization-app-grid-item-spacing) / 2);
+ }
+
+ #photosContent > iron-list > .row > .photo:not(:last-of-type) {
+ margin-inline-end: calc(var(--personalization-app-grid-item-spacing) / 2);
}
</style>
<main id="main" aria-label$="[[i18n('googlePhotosLabel')]]" tabindex="-1">
- <div>
+ <div class="tab-strip">
<cr-button id="photosTab" aria-pressed="[[isPhotosTabSelected_(tab_)]]"
on-click="onTabSelected_">
<div class="text">[[i18n('googlePhotosPhotosTabLabel')]]</div>
@@ -44,6 +105,20 @@
<div class="text">[[i18n('googlePhotosAlbumsTabLabel')]]</div>
</cr-button>
</div>
- <div id="photosContent" hidden$="[[!isPhotosTabSelected_(tab_)]]"></div>
+ <div id="photosContent" hidden$="[[!isPhotosTabSelected_(tab_)]]">
+ <iron-list id="photosGrid" items="[[photosByRow_]]" as="row">
+ <template>
+ <div class="row" rowindex$="[[index]]" tabindex$="[[tabIndex]]"
+ on-focus="onPhotosGridRowFocused_"
+ on-keydown="onPhotosGridRowKeyDown_">
+ <template is="dom-repeat" items="[[row]]" as="photo">
+ <div class="photo" colindex$="[[index]]" tabindex="-1">
+ [[photo]]
+ </div>
+ </template>
+ </div>
+ </template>
+ </iron-list>
+ </div>
<div id="albumsContent" hidden$="[[!isAlbumsTabSelected_(tab_)]]"></div>
</main>
diff --git a/ash/webui/personalization_app/resources/trusted/google_photos_element.js b/ash/webui/personalization_app/resources/trusted/google_photos_element.js
index 8c753ff..52f2e5d 100644
--- a/ash/webui/personalization_app/resources/trusted/google_photos_element.js
+++ b/ash/webui/personalization_app/resources/trusted/google_photos_element.js
@@ -7,11 +7,13 @@
* collection.
*/
+import 'chrome://resources/polymer/v3_0/iron-list/iron-list.js';
import 'chrome://resources/cr_elements/cr_button/cr_button.m.js';
import './styles.js';
import '../common/styles.js';
import {assertNotReached} from '/assert.m.js';
-import {html} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {afterNextRender, html} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {getNumberOfGridItemsPerRow, isNonEmptyArray, normalizeKeyForRTL} from '../common/utils.js';
import {getWallpaperProvider} from './mojo_interface_provider.js';
import {initializeGooglePhotosData} from './personalization_controller.js';
import {WithPersonalizationStore} from './personalization_store.js';
@@ -38,6 +40,16 @@
static get properties() {
return {
/**
+ * Whether or not this element is currently hidden.
+ * @type {boolean}
+ */
+ hidden: {
+ type: Boolean,
+ value: true,
+ reflectToAttribute: true,
+ },
+
+ /**
* The list of albums.
* @type {?Array<undefined>}
* @private
@@ -54,6 +66,7 @@
albumsLoading_: {
type: Boolean,
},
+
/**
* The list of photos.
* @type {?Array<undefined>}
@@ -64,6 +77,26 @@
},
/**
+ * The list of |photos_| split into the appropriate number of
+ * |photosPerRow_| so as to be rendered in a grid.
+ * @type {?Array<Array<undefined>>}
+ * @private
+ */
+ photosByRow_: {
+ type: Array,
+ },
+
+ /**
+ * The index of the currently focused column in the photos grid.
+ * @type {number}
+ * @private
+ */
+ photosGridFocusedColIndex_: {
+ type: Number,
+ value: 0,
+ },
+
+ /**
* Whether the list of photos is currently loading.
* @type {boolean}
* @private
@@ -73,6 +106,18 @@
},
/**
+ * The number of photos to render per row in a grid.
+ * @type {number}
+ * @private
+ */
+ photosPerRow_: {
+ type: Number,
+ value: function() {
+ return getNumberOfGridItemsPerRow();
+ },
+ },
+
+ /**
* The currently selected tab.
* @type {!Tab}
* @private
@@ -86,8 +131,9 @@
static get observers() {
return [
- 'onAlbumsLoaded_(albums_, albumsLoading_)',
- 'onPhotosLoaded_(photos_, photosLoading_)',
+ 'onHiddenChanged_(hidden)',
+ 'onAlbumsChanged_(albums_, albumsLoading_)',
+ 'onPhotosChanged_(photos_, photosLoading_, photosPerRow_)',
];
}
@@ -102,6 +148,8 @@
connectedCallback() {
super.connectedCallback();
+ this.addEventListener('iron-resize', this.onResized_.bind(this));
+
this.watch('albums_', state => state.googlePhotos.albums);
this.watch('albumsLoading_', state => state.loading.googlePhotos.albums);
this.watch('photos_', state => state.googlePhotos.photos);
@@ -112,23 +160,128 @@
}
/**
- * Invoked on changes to the list of albums and its loading state.
- * @param {?Array<undefined>} albums
- * @param {boolean} albumsLoading
+ * Invoked on changes to this element's hidden state.
* @private
*/
- onAlbumsLoaded_(albums, albumsLoading) {
+ onHiddenChanged_() {
+ if (this.hidden) {
+ return;
+ }
+
+ document.title = this.i18n('googlePhotosLabel');
+ this.shadowRoot.getElementById('main').focus();
+
+ // When iron-list items change while their parent element is hidden, the
+ // iron-list will render incorrectly. Force another layout to happen by
+ // firing an iron-resize event when this element becomes visible.
+ afterNextRender(this, () => {
+ [...this.shadowRoot.querySelectorAll('iron-list')].forEach(ironList => {
+ ironList.fire('iron-resize');
+ });
+ });
+ }
+
+ /**
+ * Invoked on changes to the list of albums and its loading state.
+ * @param {?Array<undefined>} albums
+ * @param {?boolean} albumsLoading
+ * @private
+ */
+ onAlbumsChanged_(albums, albumsLoading) {
// TODO(dmblack): Send event to untrusted via iframe API.
}
/**
- * Invoked on changes to the list of photos and its loading state.
+ * Invoked on changes to the list of photos, its loading state, and the
+ * number of photos to render per row in a grid.
* @param {?Array<undefined>} photos
- * @param {boolean} photosLoading
+ * @param {?boolean} photosLoading
+ * @param {?number} photosPerRow
* @private
*/
- onPhotosLoaded_(photos, photosLoading) {
- // TODO(dmblack): Send event to untrusted via iframe API.
+ onPhotosChanged_(photos, photosLoading, photosPerRow) {
+ if (photosLoading || !photosPerRow) {
+ return;
+ }
+ if (!isNonEmptyArray(photos)) {
+ this.photosByRow_ = null;
+ return;
+ }
+ let index = 0;
+ this.photosByRow_ = Array.from(
+ {length: Math.ceil(photos.length / photosPerRow)}, (_, i) => {
+ i *= photosPerRow;
+ const row = photos.slice(i, i + photosPerRow).map(photo => index++);
+ while (row.length < photosPerRow) {
+ row.push(undefined);
+ }
+ return row;
+ });
+ }
+
+ /**
+ * Invoked on focus of a photos grid row.
+ * @param {!Event } e
+ * @private
+ */
+ onPhotosGridRowFocused_(e) {
+ // When a grid row is focused, forward the focus event on to the grid item
+ // at the focused column index.
+ const selector = `.photo[colindex="${this.photosGridFocusedColIndex_}"]`;
+ e.currentTarget.querySelector(selector)?.focus();
+ }
+
+ /**
+ * Invoked on key down of a photos grid row.
+ * @param {!Event} e
+ * @private
+ */
+ onPhotosGridRowKeyDown_(e) {
+ const row = (/** @type {{row: Array<undefined>}} */ (e.model)).row;
+
+ switch (normalizeKeyForRTL(e.key, this.i18n('textdirection') === 'rtl')) {
+ case 'ArrowLeft':
+ if (this.photosGridFocusedColIndex_ > 0) {
+ // Left arrow moves focus to the preceding grid item.
+ this.photosGridFocusedColIndex_ -= 1;
+ this.$.photosGrid.focusItem(e.model.index);
+ } else if (e.model.index > 0) {
+ // Left arrow moves focus to the preceding grid item, wrapping to the
+ // preceding grid row.
+ this.photosGridFocusedColIndex_ = row.length - 1;
+ this.$.photosGrid.focusItem(e.model.index - 1);
+ }
+ return;
+ case 'ArrowRight':
+ if (this.photosGridFocusedColIndex_ < row.length - 1) {
+ // Right arrow moves focus to the succeeding grid item.
+ this.photosGridFocusedColIndex_ += 1;
+ this.$.photosGrid.focusItem(e.model.index);
+ } else if (e.model.index < this.photosByRow_.length - 1) {
+ // Right arrow moves focus to the succeeding grid item, wrapping to
+ // the succeeding grid row.
+ this.photosGridFocusedColIndex_ = 0;
+ this.$.photosGrid.focusItem(e.model.index + 1);
+ }
+ return;
+ case 'Tab':
+ // The grid contains a single |focusable| row which becomes a focus trap
+ // due to the synthetic redirect of focus events to grid items. To
+ // escape the trap, make the |focusable| row unfocusable until has
+ // advanced to the next candidate.
+ const focusable = this.$.photosGrid.querySelector('[tabindex="0"]');
+ focusable.setAttribute('tabindex', -1);
+ afterNextRender(focusable, () => focusable.setAttribute('tabindex', 0));
+ return;
+ }
+ }
+
+ /**
+ * Invoked on resize of this element.
+ * @private
+ */
+ onResized_() {
+ this.photosPerRow_ = getNumberOfGridItemsPerRow();
}
/**
diff --git a/ash/webui/personalization_app/resources/trusted/personalization_controller.js b/ash/webui/personalization_app/resources/trusted/personalization_controller.js
index 52415e6..e1f1dbab 100644
--- a/ash/webui/personalization_app/resources/trusted/personalization_controller.js
+++ b/ash/webui/personalization_app/resources/trusted/personalization_controller.js
@@ -85,9 +85,9 @@
store.dispatch(action.beginLoadGooglePhotosCountAction());
// TODO(dmblack): Create and wire up mojo API. For now, simulate an async
- // request that returns a zero count of Google Photos photos.
+ // request that returns a count of 1,000 Google Photos photos.
return new Promise(resolve => setTimeout(() => {
- store.dispatch(action.setGooglePhotosCountAction(0));
+ store.dispatch(action.setGooglePhotosCountAction(1000));
resolve();
}, 1000));
}
@@ -101,9 +101,10 @@
store.dispatch(action.beginLoadGooglePhotosPhotosAction());
// TODO(dmblack): Create and wire up mojo API. For now, simulate an async
- // request that returns an empty response list of Google Photos photos.
+ // request that returns a list of 1,000 Google Photos photos.
return new Promise(resolve => setTimeout(() => {
- store.dispatch(action.setGooglePhotosPhotosAction([]));
+ store.dispatch(action.setGooglePhotosPhotosAction(
+ Array.from({length: 1000})));
resolve();
}, 1000));
}
diff --git a/ash/webui/personalization_app/resources/trusted/personalization_router_element.html b/ash/webui/personalization_app/resources/trusted/personalization_router_element.html
index b522a35..6272d829 100644
--- a/ash/webui/personalization_app/resources/trusted/personalization_router_element.html
+++ b/ash/webui/personalization_app/resources/trusted/personalization_router_element.html
@@ -64,7 +64,7 @@
<wallpaper-images collection-id="[[queryParams_.id]]"
hidden="[[!shouldShowCollectionImages_(path_)]]"></wallpaper-images>
<template is="dom-if" if="[[isGooglePhotosIntegrationEnabled_()]]">
- <google-photos hidden$="[[!shouldShowGooglePhotosCollection_(path_)]]">
+ <google-photos hidden="[[!shouldShowGooglePhotosCollection_(path_)]]">
</google-photos>
</template>
<local-images hidden="[[!shouldShowLocalCollection_(path_)]]"></local-images>
diff --git a/ash/webui/personalization_app/resources/trusted/personalization_store.js b/ash/webui/personalization_app/resources/trusted/personalization_store.js
index 865f9a4..356296e 100644
--- a/ash/webui/personalization_app/resources/trusted/personalization_store.js
+++ b/ash/webui/personalization_app/resources/trusted/personalization_store.js
@@ -5,6 +5,7 @@
import {Store, StoreObserver} from 'chrome://resources/js/cr/ui/store.js';
import {StoreClient, StoreClientInterface} from 'chrome://resources/js/cr/ui/store_client.js';
import {I18nBehavior, I18nBehaviorInterface} from 'chrome://resources/js/i18n_behavior.m.js';
+import {IronResizableBehavior} from 'chrome://resources/polymer/v3_0/iron-resizable-behavior/iron-resizable-behavior.js';
import {mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {emptyState, PersonalizationState, reduce} from './personalization_reducers.js';
@@ -96,9 +97,14 @@
* @implements {StoreClientInterface}
* @implements {StoreObserver<PersonalizationState>}
* @implements {I18nBehavior}
+ * @implements {IronResizableBehavior}
*/
-export const PersonalizationStoreClient =
- [StoreClient, PersonalizationStoreClientImpl, I18nBehavior];
+export const PersonalizationStoreClient = [
+ StoreClient,
+ PersonalizationStoreClientImpl,
+ I18nBehavior,
+ IronResizableBehavior,
+];
/**
* @constructor
diff --git a/ash/webui/personalization_app/resources/untrusted/BUILD.gn b/ash/webui/personalization_app/resources/untrusted/BUILD.gn
index 3e09515..2fcb51e 100644
--- a/ash/webui/personalization_app/resources/untrusted/BUILD.gn
+++ b/ash/webui/personalization_app/resources/untrusted/BUILD.gn
@@ -13,6 +13,7 @@
"../../mojom:mojom_js_library_for_compile",
"../common:constants",
"../common:iframe_api",
+ "../common:utils",
"//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
]
}
diff --git a/ash/webui/personalization_app/resources/untrusted/collections_grid.js b/ash/webui/personalization_app/resources/untrusted/collections_grid.js
index 25677020..03a41a9 100644
--- a/ash/webui/personalization_app/resources/untrusted/collections_grid.js
+++ b/ash/webui/personalization_app/resources/untrusted/collections_grid.js
@@ -8,7 +8,7 @@
import {afterNextRender, html, PolymerElement} from 'chrome-untrusted://personalization/polymer/v3_0/polymer/polymer_bundled.min.js';
import {EventType, kMaximumLocalImagePreviews} from '../common/constants.js';
import {selectCollection, selectGooglePhotosCollection, selectLocalCollection, validateReceivedData} from '../common/iframe_api.js';
-import {getLoadingPlaceholderAnimationDelay, isNullOrArray, isNullOrNumber, isSelectionEvent} from '../common/utils.js';
+import {getLoadingPlaceholderAnimationDelay, getNumberOfGridItemsPerRow, isNullOrArray, isNullOrNumber, isSelectionEvent} from '../common/utils.js';
/**
* @fileoverview Responds to |SendCollectionsEvent| from trusted. Handles user
@@ -18,9 +18,6 @@
const kGooglePhotosCollectionId = 'google_photos_';
const kLocalCollectionId = 'local_';
-/** Width in pixels of when the app switches from 3 to 4 tiles wide. */
-const k3to4WidthCutoffPx = 688;
-
/** Height in pixels of a tile. */
const kTileHeightPx = 136;
@@ -236,7 +233,7 @@
value() {
// Fill the view with loading tiles. Will be adjusted to the correct
// number of tiles when collections are received.
- const x = window.innerWidth > k3to4WidthCutoffPx ? 4 : 3;
+ const x = getNumberOfGridItemsPerRow();
const y = Math.floor(window.innerHeight / kTileHeightPx);
return Array.from({length: x * y}, () => ({type: TileType.loading}));
}
diff --git a/chrome/test/data/webui/chromeos/personalization_app/personalization_app_controller_test.js b/chrome/test/data/webui/chromeos/personalization_app/personalization_app_controller_test.js
index 91e279c..0f31ae5 100644
--- a/chrome/test/data/webui/chromeos/personalization_app/personalization_app_controller_test.js
+++ b/chrome/test/data/webui/chromeos/personalization_app/personalization_app_controller_test.js
@@ -59,21 +59,21 @@
},
{
name: 'set_google_photos_count',
- count: 0,
+ count: 1000,
},
{
name: 'begin_load_google_photos_albums',
},
{
+ name: 'begin_load_google_photos_photos',
+ },
+ {
name: 'set_google_photos_albums',
albums: [],
},
{
- name: 'begin_load_google_photos_photos',
- },
- {
name: 'set_google_photos_photos',
- photos: [],
+ photos: Array.from({length: 1000}),
},
],
personalizationStore.actions);
@@ -101,7 +101,7 @@
photos: false,
},
googlePhotos: {
- count: 0,
+ count: 1000,
albums: undefined,
photos: undefined,
},
@@ -114,7 +114,20 @@
photos: false,
},
googlePhotos: {
- count: 0,
+ count: 1000,
+ albums: undefined,
+ photos: undefined,
+ },
+ },
+ // BEGIN_LOAD_GOOGLE_PHOTOS_PHOTOS.
+ {
+ 'loading.googlePhotos': {
+ count: false,
+ albums: true,
+ photos: true,
+ },
+ googlePhotos: {
+ count: 1000,
albums: undefined,
photos: undefined,
},
@@ -124,23 +137,10 @@
'loading.googlePhotos': {
count: false,
albums: false,
- photos: false,
- },
- googlePhotos: {
- count: 0,
- albums: [],
- photos: undefined,
- },
- },
- // BEGIN_LOAD_GOOGLE_PHOTOS_PHOTOS.
- {
- 'loading.googlePhotos': {
- count: false,
- albums: false,
photos: true,
},
googlePhotos: {
- count: 0,
+ count: 1000,
albums: [],
photos: undefined,
},
@@ -153,9 +153,9 @@
photos: false,
},
googlePhotos: {
- count: 0,
+ count: 1000,
albums: [],
- photos: [],
+ photos: Array.from({length: 1000}),
},
},
],