/* * Copyright (c) 2015-2017, Michael A. Updike All rights reserved. * Licensed under the BSD-3-Clause * https://opensource.org/licenses/BSD-3-Clause * https://github.com/opus1269/photo-screen-saver/blob/master/LICENSE.md */ window.app = window.app || {}; /** * Manage the extensions data * @namespace */ app.Data = (function() { 'use strict'; new ExceptionHandler(); const chromep = new ChromePromise(); /** * Version of localStorage - update when items are added, removed, changed * @type {int} * @default * @const * @private * @memberOf app.Data */ const _DATA_VERSION = 17; /** * A number and associated units * @typedef {Object} app.Data.UnitValue * @property {number} base - value in base unit * @property {number} display - value in display unit * @property {int} unit - display unit */ /** * Values for items in localStorage * @typedef {Object} app.Data.LocalStorage * @property {int} version - version of data * @property {boolean} enabled - is screensaver enabled * @property {string} permPicasa - optional permission for Picasa * @property {string} permBackground - optional permission to run in bg * @property {boolean} allowBackground - run Chrome in background * @property {app.Data.UnitValue} idleTime - idle time to display screensaver * @property {app.Data.UnitValue} transitionTime - time between photos * @property {boolean} skip - ignore extreme aspect ratio photos * @property {boolean} shuffle - randomize photo order * @property {int} photoSizing - photo display type * @property {int} photoTransition - transition animation * @property {boolean} interactive - vcr controls for screensaver * @property {int} showTime - time display format * @property {boolean} largeTime - display larger time label * @property {boolean} showPhotog - display name on own photos * @property {boolean} showLocation - display photo location * @property {string} background - background image * @property {boolean} keepAwake - manage computer poser settings * @property {boolean} chromeFullscreen - don't display over fullscreen * @property {boolean} allDisplays - show on all displays * @property {string} activeStart - Keep Wake start time '00:00' 24 hr * @property {string} activeStop - Keep Wake stop time '00:00' 24 hr * @property {boolean} allowSuspend - let computer sleep * @property {boolean} allowPhotoClicks - show photo source on left click * @property {boolean} useSpaceReddit - use this photo source * @property {boolean} useEarthReddit - use this photo source * @property {boolean} useAnimalReddit - use this photo source * @property {boolean} useEditors500px - use this photo source * @property {boolean} usePopular500px - use this photo source * @property {boolean} useYesterday500px - use this photo source * @property {boolean} useInterestingFlickr - use this photo source * @property {boolean} useChromecast - use this photo source * @property {boolean} useAuthors - use this photo source * @property {boolean} useSpaceReddit - use this photo source * @property {boolean} fullResGoogle - true for actual size Google photos * @property {boolean} isAlbumMode - true if Google Photos album mode * @property {boolean} useGoogle - use this photo source * @property {boolean} useGoogleAlbums - use this photo source * @property {Array} albumSelections - user's selected Google Photos albums * @property {boolean} useGooglePhotos - use this photo source */ /** * Default values in localStorage * @type {app.Data.LocalStorage} * @const * @private * @memberOf app.Data */ const _DEF_VALUES = { 'version': _DATA_VERSION, 'enabled': true, 'isAlbumMode': true, 'permPicasa': 'notSet', // enum: notSet allowed denied 'permBackground': 'notSet', // enum: notSet allowed denied 'allowBackground': false, 'idleTime': {'base': 5, 'display': 5, 'unit': 0}, // minutes 'transitionTime': {'base': 30, 'display': 30, 'unit': 0}, // seconds 'skip': true, 'shuffle': true, 'photoSizing': 0, 'photoTransition': 1, 'interactive': false, 'showTime': 2, // 24 hr format 'largeTime': false, 'fullResGoogle': false, 'showPhotog': true, 'showLocation': true, 'background': 'background:linear-gradient(to bottom, #3a3a3a, #b5bdc8)', 'keepAwake': false, 'chromeFullscreen': true, 'allDisplays': false, 'activeStart': '00:00', // 24 hr time 'activeStop': '00:00', // 24 hr time 'allowSuspend': false, 'allowPhotoClicks': true, 'useSpaceReddit': false, 'useEarthReddit': false, 'useAnimalReddit': false, 'useEditors500px': false, 'usePopular500px': false, 'useYesterday500px': false, 'useInterestingFlickr': false, 'useChromecast': true, 'useAuthors': false, 'useGoogle': true, 'useGoogleAlbums': true, 'albumSelections': [], 'useGooglePhotos': false, }; /** * Set state based on screensaver enabled flag * Note: this does not effect the keep awake settings so you could * use the extension as a display keep awake scheduler without * using the screensaver * @private * @memberOf app.Data */ function _processEnabled() { // update context menu text const label = Chrome.Storage.getBool('enabled') ? Chrome.Locale.localize( 'disable') : Chrome.Locale.localize('enable'); app.Alarm.updateBadgeText(); chromep.contextMenus.update('ENABLE_MENU', { title: label, }).catch(() => {}); } /** * Set power scheduling features * @private * @memberOf app.Data */ function _processKeepAwake() { Chrome.Storage.getBool('keepAwake') ? chrome.power.requestKeepAwake( 'display') : chrome.power.releaseKeepAwake(); app.Alarm.updateRepeatingAlarms(); app.Alarm.updateBadgeText(); } /** * Set wait time for screen saver display after machine is idle * @private * @memberOf app.Data */ function _processIdleTime() { chrome.idle.setDetectionInterval(app.Data.getIdleSeconds()); } /** * Get default time format based on locale * @returns {int} 12 or 24 * @private * @memberOf app.Data */ function _getTimeFormat() { let ret = 2; // 24 hr const format = Chrome.Locale.localize('time_format'); if (format && (format === '12')) { ret = 1; } return ret; } /** * Set the 'os' value * @returns {Promise} err on failure * @private * @memberOf app.Data */ function _setOS() { return chromep.runtime.getPlatformInfo().then((info) => { Chrome.Storage.set('os', info.os); return Promise.resolve(); }); } /** * Save the [_DEF_VALUES]{@link app.Data._DEF_VALUES} items, if they * do not already exist * @private * @memberOf app.Data */ function _addDefaults() { Object.keys(_DEF_VALUES).forEach(function(key) { if (Chrome.Storage.get(key) === null) { Chrome.Storage.set(key, _DEF_VALUES[key]); } }); } /** * Convert a setting-slider value due to addition of units * @param {!string} key - localStorage key * @private * @memberOf app.Data */ function _convertSliderValue(key) { const value = Chrome.Storage.get(key); if (value) { const newValue = { base: value, display: value, unit: 0, }; Chrome.Storage.set(key, newValue); } } return { /** * Initialize the data saved in localStorage * @memberOf app.Data */ initialize: function() { _addDefaults(); // set operating system _setOS().catch(() => {}); // and the last error Chrome.Storage.clearLastError().catch((err) => { Chrome.GA.error(err.message, 'Data.initialize'); }); // set time format based on locale Chrome.Storage.set('showTime', _getTimeFormat()); // update state app.Data.processState(); }, /** * Update the data saved in localStorage * @memberOf app.Data */ update: function() { // New items, changes, and removal of unused items can take place // here when the version changes const oldVersion = Chrome.Storage.getInt('version'); if (Number.isNaN(oldVersion) || (_DATA_VERSION > oldVersion)) { // update version number Chrome.Storage.set('version', _DATA_VERSION); } if (!Number.isNaN(oldVersion)) { if (oldVersion < 14) { // background used to be a required permission // installed extensions before the change will keep // this permission on update. // https://stackoverflow.com/a/38278824/4468645 Chrome.Storage.set('permBackground', 'allowed'); Chrome.Storage.set('allowBackground', true); } if (oldVersion < 12) { // picasa used to be a required permission // installed extensions before the change will keep // this permission on update. // https://stackoverflow.com/a/38278824/4468645 Chrome.Storage.set('permPicasa', 'allowed'); } if (oldVersion < 10) { // was setting this without quotes before const oldOS = localStorage.getItem('os'); if (oldOS) { Chrome.Storage.set('os', oldOS); } } if (oldVersion < 8) { // change setting-slider values due to adding units _convertSliderValue('transitionTime'); _convertSliderValue('idleTime'); } } _addDefaults(); // update state app.Data.processState(); }, /** * Restore default values for data saved in localStorage * @memberOf app.Data */ restoreDefaults: function() { Object.keys(_DEF_VALUES).forEach(function(key) { if (!key.includes('useGoogle') && (key !== 'googlePhotosSelections') && (key !== 'albumSelections')) { // skip Google photos settings Chrome.Storage.set(key, _DEF_VALUES[key]); } }); // restore default time format based on locale Chrome.Storage.set('showTime', _getTimeFormat()); // update state app.Data.processState(); }, /** * Process changes to localStorage items * @param {string} [key='all'] - the item that changed * @memberOf app.Data */ processState: function(key = 'all') { // Map processing functions to localStorage values const STATE_MAP = { 'enabled': _processEnabled, 'keepAwake': _processKeepAwake, 'activeStart': _processKeepAwake, 'activeStop': _processKeepAwake, 'allowSuspend': _processKeepAwake, 'idleTime': _processIdleTime, }; if (key === 'all') { // process everything Object.keys(STATE_MAP).forEach(function(ky) { const fn = STATE_MAP[ky]; fn(); }); // process photo SOURCES app.PhotoSources.processAll(); // set os, if not already if (!Chrome.Storage.get('os')) { _setOS().catch(() => {}); } } else { // individual change if (app.PhotoSources.isUseKey(key) || (key === 'fullResGoogle')) { // photo source change const useKey = (key === 'fullResGoogle') ? 'useGoogleAlbums' : key; app.PhotoSources.process(useKey).catch((err) => { // send message on processing error const msg = app.Msg.PHOTO_SOURCE_FAILED; msg.key = useKey; msg.error = err.message; return Chrome.Msg.send(msg); }).catch(() => {}); } else { const fn = STATE_MAP[key]; if (typeof(fn) !== 'undefined') { fn(); } } } }, /** * Get the idle time in seconds * @returns {int} idle time in seconds * @memberOf app.Utils */ getIdleSeconds: function() { const idle = Chrome.Storage.get('idleTime'); return idle.base * 60; }, }; })();