summaryrefslogtreecommitdiffstats
path: root/devtools/client/responsive/actions/devices.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/client/responsive/actions/devices.js')
-rw-r--r--devtools/client/responsive/actions/devices.js254
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,
+ };
+ },
+};