diff options
Diffstat (limited to 'devtools/client/responsive/actions/devices.js')
-rw-r--r-- | devtools/client/responsive/actions/devices.js | 254 |
1 files changed, 254 insertions, 0 deletions
diff --git a/devtools/client/responsive/actions/devices.js b/devtools/client/responsive/actions/devices.js new file mode 100644 index 0000000000..b3f2bab982 --- /dev/null +++ b/devtools/client/responsive/actions/devices.js @@ -0,0 +1,254 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +const asyncStorage = require("resource://devtools/shared/async-storage.js"); + +const { + ADD_DEVICE, + ADD_DEVICE_TYPE, + EDIT_DEVICE, + LOAD_DEVICE_LIST_START, + LOAD_DEVICE_LIST_ERROR, + LOAD_DEVICE_LIST_END, + REMOVE_DEVICE, + UPDATE_DEVICE_DISPLAYED, + UPDATE_DEVICE_MODAL, +} = require("resource://devtools/client/responsive/actions/index.js"); +const { + post, +} = require("resource://devtools/client/responsive/utils/message.js"); + +const { + addDevice, + editDevice, + getDevices, + removeDevice, +} = require("resource://devtools/client/shared/devices.js"); +const { + changeUserAgent, + toggleTouchSimulation, +} = require("resource://devtools/client/responsive/actions/ui.js"); +const { + changeDevice, + changePixelRatio, + changeViewportAngle, +} = require("resource://devtools/client/responsive/actions/viewports.js"); + +const DISPLAYED_DEVICES_PREF = "devtools.responsive.html.displayedDeviceList"; + +/** + * Returns an object containing the user preference of displayed devices. + * + * @return {Object} containing two Sets: + * - added: Names of the devices that were explicitly enabled by the user + * - removed: Names of the devices that were explicitly removed by the user + */ +function loadPreferredDevices() { + const preferredDevices = { + added: new Set(), + removed: new Set(), + }; + + if (Services.prefs.prefHasUserValue(DISPLAYED_DEVICES_PREF)) { + try { + let savedData = Services.prefs.getStringPref(DISPLAYED_DEVICES_PREF); + savedData = JSON.parse(savedData); + if (savedData.added && savedData.removed) { + preferredDevices.added = new Set(savedData.added); + preferredDevices.removed = new Set(savedData.removed); + } + } catch (e) { + console.error(e); + } + } + + return preferredDevices; +} + +/** + * Update the displayed device list preference with the given device list. + * + * @param {Object} containing two Sets: + * - added: Names of the devices that were explicitly enabled by the user + * - removed: Names of the devices that were explicitly removed by the user + */ +function updatePreferredDevices(devices) { + let devicesToSave = { + added: Array.from(devices.added), + removed: Array.from(devices.removed), + }; + devicesToSave = JSON.stringify(devicesToSave); + Services.prefs.setStringPref(DISPLAYED_DEVICES_PREF, devicesToSave); +} + +module.exports = { + // This function is only exported for testing purposes + _loadPreferredDevices: loadPreferredDevices, + + updatePreferredDevices, + + addCustomDevice(device) { + return async function ({ dispatch }) { + // Add custom device to device storage + await addDevice(device, "custom"); + dispatch({ + type: ADD_DEVICE, + device, + deviceType: "custom", + }); + }; + }, + + addDevice(device, deviceType) { + return { + type: ADD_DEVICE, + device, + deviceType, + }; + }, + + addDeviceType(deviceType) { + return { + type: ADD_DEVICE_TYPE, + deviceType, + }; + }, + + editCustomDevice(viewport, oldDevice, newDevice) { + return async function ({ dispatch }) { + // Edit custom device in storage + await editDevice(oldDevice, newDevice, "custom"); + // Notify the window that the device should be updated in the device selector. + post(window, { + type: "change-device", + device: newDevice, + viewport, + }); + + // Update UI if the device is selected. + if (viewport) { + dispatch(changeUserAgent(newDevice.userAgent)); + dispatch(toggleTouchSimulation(newDevice.touch)); + } + + dispatch({ + type: EDIT_DEVICE, + deviceType: "custom", + viewport, + oldDevice, + newDevice, + }); + }; + }, + + removeCustomDevice(device) { + return async function ({ dispatch }) { + // Remove custom device from device storage + await removeDevice(device, "custom"); + dispatch({ + type: REMOVE_DEVICE, + device, + deviceType: "custom", + }); + }; + }, + + updateDeviceDisplayed(device, deviceType, displayed) { + return { + type: UPDATE_DEVICE_DISPLAYED, + device, + deviceType, + displayed, + }; + }, + + loadDevices() { + return async function ({ dispatch }) { + dispatch({ type: LOAD_DEVICE_LIST_START }); + const preferredDevices = loadPreferredDevices(); + let deviceByTypes; + + try { + deviceByTypes = await getDevices(); + } catch (e) { + console.error("Could not load device list: " + e); + dispatch({ type: LOAD_DEVICE_LIST_ERROR }); + return; + } + + for (const [type, devices] of deviceByTypes.entries()) { + dispatch(module.exports.addDeviceType(type)); + for (const device of devices) { + if (device.os == "fxos") { + continue; + } + + const newDevice = Object.assign({}, device, { + displayed: + preferredDevices.added.has(device.name) || + (device.featured && !preferredDevices.removed.has(device.name)), + }); + + dispatch(module.exports.addDevice(newDevice, type)); + } + } + + // Add an empty "custom" type if it doesn't exist in device storage + if (!deviceByTypes.has("custom")) { + dispatch(module.exports.addDeviceType("custom")); + } + + dispatch({ type: LOAD_DEVICE_LIST_END }); + }; + }, + + restoreDeviceState() { + return async function ({ dispatch, getState }) { + const deviceState = await asyncStorage.getItem( + "devtools.responsive.deviceState" + ); + if (!deviceState) { + return; + } + + const { id, device: deviceName, deviceType } = deviceState; + const devices = getState().devices; + + if (!devices.types.includes(deviceType)) { + // Can't find matching device type. + return; + } + + const device = devices[deviceType].find(d => d.name === deviceName); + if (!device) { + // Can't find device with the same device name. + return; + } + + const viewport = getState().viewports[0]; + + post(window, { + type: "change-device", + device, + viewport, + }); + + dispatch(changeDevice(id, device.name, deviceType)); + dispatch(changeViewportAngle(id, viewport.angle)); + dispatch(changePixelRatio(id, device.pixelRatio)); + dispatch(changeUserAgent(device.userAgent)); + dispatch(toggleTouchSimulation(device.touch)); + }; + }, + + updateDeviceModal(isOpen, modalOpenedFromViewport = null) { + return { + type: UPDATE_DEVICE_MODAL, + isOpen, + modalOpenedFromViewport, + }; + }, +}; |