diff --git a/README.md b/README.md index 7e22421..850c896 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,6 @@ The challenge of work from home in the last 2 years with 2 young toddlers is tha ![image](https://user-images.githubusercontent.com/3792401/168950471-15589781-ee7f-442f-afa4-58c53e136abb.png) - ### Mac OSX Monterey ![demo-mac](https://user-images.githubusercontent.com/3792401/159141171-c6c8a6a5-4b7b-4fc6-af28-c082fc1bd723.gif) @@ -61,7 +60,6 @@ By default, we will give each display a name. You can rename the display to some ![image](https://user-images.githubusercontent.com/3792401/168950610-576cc751-14fa-4a6d-82bf-57874cafec04.png) - ### Toggling Dark Mode and Light Mode The toggle for dark and light mode is located at the bottom of the control, you can choose either dark mode or light mode. This change will update the system dark mode accordingly. So it's best to keep all your apps aware of the dark mode. So this way it will change the dark mode according to the app. @@ -235,6 +233,7 @@ This app has limited support for M1 Mac. Volume settings and individual display ![image](https://user-images.githubusercontent.com/3792401/177044893-8d3fd19e-4fbf-4557-9048-c4a0d6fd8b2f.png) This requires preferences JSON to be updated (`~/Library/Application Support/display-dj/preferences.json`) + ```js { // ... diff --git a/dist.js b/dist.js index ae70855..309da5a 100644 --- a/dist.js +++ b/dist.js @@ -94,6 +94,11 @@ async function doDistWork() { path.join(__dirname, `dist/display-dj-darwin-x64/display-dj.app/Contents/Resources`, `ddcctl`) ); + fs.copyFileSync( + path.join(__dirname, `src/binaries/darwin_m1ddc`), + path.join(__dirname, `dist/display-dj-darwin-x64/display-dj.app/Contents/Resources`, `m1ddc`) + ); + fs.copyFileSync( path.join(__dirname, `src/binaries/darwin_brightness`), path.join(__dirname, `dist/display-dj-darwin-x64/display-dj.app/Contents/Resources`, `brightness`) diff --git a/package.json b/package.json index 5be3bda..d67b6d3 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "display-dj", "private": true, - "version": "1.11.4", + "version": "1.11.6", "description": "A cross platform desktop application that supports brightness adjustment for integrated laptop monitor as well as external monitors and dark mode toggle supporting Windows and MacOSX at the moment.", "scripts": { "clean-dist": "rimraf dist", @@ -20,7 +20,7 @@ "fix-import": "npx import-fixer --groupImport --aggressive --transformRelativeImport --importQuote=single", "preformat": "npm run fix-import", "format": "concurrently \"npm run format-js\" \"npm run format-html\"", - "format-js": "npx prettier --config ./.prettierrc --no-error-on-unmatched-pattern --write **/**/**/**/**/*.{ts,tsx,js,jsx,scss,yml,html,json,md}", + "format-js": "npx prettier --config ./.prettierrc --no-error-on-unmatched-pattern --write src/**/**/**/**/**/*.{ts,tsx,js,jsx,scss,yml,html,json,md} **/*.{ts,tsx,js,jsx,scss,yml,html,json,md}", "format-html": "npx prettier --config ./.prettierrc --parser html --no-error-on-unmatched-pattern --write **/**/**/**/**/*.svg", "test-ci": "cross-env CI=true npm test", "test": "jest src", diff --git a/src/binaries/win32_ddcci.js b/src/binaries/win32_ddcci.js index e9f24b5..1ebff9d 100644 --- a/src/binaries/win32_ddcci.js +++ b/src/binaries/win32_ddcci.js @@ -10,26 +10,25 @@ let ddcci; const path = require('path'); const { spawn, exec } = require('child_process'); -process.on('message', async function(msg) { +process.on('message', async function (msg) { try { // first attempt to find ddcci as part of the dev mode (pure third party require) - ddcci = require("@hensm/ddcci"); - if(!ddcci){ - throw 'Cannot find local node module for ddcci' + ddcci = require('@hensm/ddcci'); + if (!ddcci) { + throw 'Cannot find local node module for ddcci'; } - } - catch(err){ + } catch (err) { // otherwise, will look into it from the msg[0] = process['resourcesPath'] - ddcci = require(path.join(msg[0], "node_modules/@hensm/ddcci")); + ddcci = require(path.join(msg[0], 'node_modules/@hensm/ddcci')); } const command = msg[1]; const targetMonitorId = msg[2]; const newBrightness = parseInt(msg[3]); - try{ + try { let res; - switch(command){ + switch (command) { case 'setBrightness': res = await _setBrightness(targetMonitorId, newBrightness); break; @@ -63,39 +62,38 @@ process.on('message', async function(msg) { break; default: - throw `Not supported command - ${command}` + throw `Not supported command - ${command}`; break; } - process.send({success: true, command, data: res}); - } catch(error){ - process.send({success: false, command, error: error.toString()}); + process.send({ success: true, command, data: res }); + } catch (error) { + process.send({ success: false, command, error: error.toString() }); } process.exit(); }); -function _setBrightness(targetMonitorId, newBrightness){ - if(isNaN(newBrightness) || newBrightness < 0 || newBrightness > 100){ - throw 'newBrightness needs to be a number between 0 and 100' +function _setBrightness(targetMonitorId, newBrightness) { + if (isNaN(newBrightness) || newBrightness < 0 || newBrightness > 100) { + throw 'newBrightness needs to be a number between 0 and 100'; } for (const monitorId of ddcci.getMonitorList()) { - if(monitorId === targetMonitorId){ - try{ + if (monitorId === targetMonitorId) { + try { return ddcci.setBrightness(monitorId, newBrightness); - } catch(err){ + } catch (err) { throw err; } - } } throw `targetMonitorId (${targetMonitorId}) not found`; } -function _getBrightness(targetMonitorId){ +function _getBrightness(targetMonitorId) { return ddcci.getBrightness(targetMonitorId); } -function _getMonitorList(){ +function _getMonitorList() { return ddcci.getMonitorList(); } diff --git a/src/main/index.ts b/src/main/index.ts index babac0e..4e2badc 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -1,6 +1,16 @@ // @ts-nocheck import AutoLaunch from 'auto-launch'; -import { app, BrowserWindow, dialog, globalShortcut, ipcMain, Menu, nativeTheme, shell, Tray } from 'electron'; +import { + app, + BrowserWindow, + dialog, + globalShortcut, + ipcMain, + Menu, + nativeTheme, + shell, + Tray, +} from 'electron'; import { EventEmitter } from 'events'; import path from 'path'; import { matchPath } from 'react-router-dom'; @@ -11,7 +21,11 @@ import PositionUtils from 'src/main/utils/PositionUtils'; import PreferenceUtils from 'src/main/utils/PreferenceUtils'; import { getJSON } from 'src/main/utils/RestUtils'; import SoundUtils from 'src/main/utils/SoundUtils'; -import { LOG_FILE_PATH, MONITOR_CONFIG_FILE_PATH, PREFERENCE_FILE_PATH } from 'src/main/utils/StorageUtils'; +import { + LOG_FILE_PATH, + MONITOR_CONFIG_FILE_PATH, + PREFERENCE_FILE_PATH, +} from 'src/main/utils/StorageUtils'; import 'src/main/utils/SetupShortcutForWin32'; // this is to set up the icon shortcut for win32 import 'src/main/utils/LogUtils'; @@ -113,7 +127,7 @@ async function setUpShortcuts() { global.emitAppEvent({ command }); } - if(keyBinding.notification){ + if (keyBinding.notification) { showNotification(keyBinding.notification); } }); @@ -163,7 +177,7 @@ async function setupCommandChannel() { global.subscribeAppEvent(async (data) => { const { command } = data; - if(command.includes(`command/refetch`)){ + if (command.includes(`command/refetch`)) { // global.emitAppEvent({ command: 'command/refetch' }); switch (command) { @@ -197,7 +211,11 @@ async function setupCommandChannel() { break; } - if(!isNaN(allMonitorBrightness) && allMonitorBrightness >= 0 && allMonitorBrightness <= 100){ + if ( + !isNaN(allMonitorBrightness) && + allMonitorBrightness >= 0 && + allMonitorBrightness <= 100 + ) { await DisplayUtils.batchUpdateBrightness(allMonitorBrightness, delta); } else { console.trace(`changeVolume failed due to invalid volume`, allMonitorBrightness, delta); @@ -229,11 +247,11 @@ async function setupCommandChannel() { if (command.includes(`command/changeVolume`)) { const volume = parseInt(command.replace('command/changeVolume/', '')); - if(!isNaN(volume) && volume >= 0 && volume <= 100){ + if (!isNaN(volume) && volume >= 0 && volume <= 100) { const promises = []; promises.push(SoundUtils.setMuted(volume === 0)); promises.push(SoundUtils.setVolume(volume)); - await Promise.all(promises) + await Promise.all(promises); _sendRefetchEventToFrontEnd('configs'); } else { console.trace(`changeVolume failed due to invalid volume`, volume); @@ -308,16 +326,16 @@ function _getTrayIcon() { return nativeTheme.shouldUseDarkColors ? DARK_ICON : LIGHT_ICON; } -async function _getLatestAppVersion(){ - try{ - const {version} = await getJSON(`https://synle.github.io/display-dj/release.json`); +async function _getLatestAppVersion() { + try { + const { version } = await getJSON(`https://synle.github.io/display-dj/release.json`); return version; - } catch(err){ + } catch (err) { return ''; } } -async function _getContextMenu(){ +async function _getContextMenu() { const brightnessPresets = await PreferenceUtils.getBrightnessPresets(); const volumePresets = await PreferenceUtils.getVolumePresets(); const latestAppVersion = await _getLatestAppVersion(); @@ -326,34 +344,34 @@ async function _getContextMenu(){ { label: `Use Light Mode`, click: async () => { - global.emitAppEvent({ command: 'command/changeDarkMode/light' }) + global.emitAppEvent({ command: 'command/changeDarkMode/light' }); showNotification(`Turn on Light Mode`); }, }, { label: `Use Dark Mode`, click: async () => { - global.emitAppEvent({ command: 'command/changeDarkMode/dark' }) + global.emitAppEvent({ command: 'command/changeDarkMode/dark' }); showNotification(`Turn on Dark Mode`); }, }, { type: 'separator', }, - ...brightnessPresets.map(brightnessPreset => ({ + ...brightnessPresets.map((brightnessPreset) => ({ label: `Change brightness to ${brightnessPreset.level}%`, click: async () => { - global.emitAppEvent({ command: `command/changeBrightness/${brightnessPreset.level}` }) + global.emitAppEvent({ command: `command/changeBrightness/${brightnessPreset.level}` }); showNotification(`Brightness of all monitors changed to ${brightnessPreset.level}%`); }, })), { type: 'separator', }, - ...volumePresets.map(volumePreset => ({ + ...volumePresets.map((volumePreset) => ({ label: `Change volume to ${volumePreset.level}%`, click: async () => { - global.emitAppEvent({ command: `command/changeVolume/${volumePreset.level}` }) + global.emitAppEvent({ command: `command/changeVolume/${volumePreset.level}` }); showNotification(`Volume changed to ${volumePreset.level}%`); }, })), @@ -386,8 +404,9 @@ async function _getContextMenu(){ }, { label: `New Version Available (${latestAppVersion})`, - click: async () => global.emitAppEvent({ command: 'command/openExternal/link/downloadNewVersion' }), - visible: await latestAppVersion !== process.env.APP_VERSION + click: async () => + global.emitAppEvent({ command: 'command/openExternal/link/downloadNewVersion' }), + visible: (await latestAppVersion) !== process.env.APP_VERSION, }, { type: 'separator', @@ -429,29 +448,29 @@ async function _getContextMenu(){ /** * @return None - Hide the dock icon for Mac... */ -async function setupDockIcon(){ - switch(process.platform){ +async function setupDockIcon() { + switch (process.platform) { case 'darwin': - try{ + try { app.dock.hide(); console.debug('Hide dock icon success'); - } catch(err){ + } catch (err) { console.error('Hide dock icon failed with error', err); } break; } } -function _sendRefetchEventToFrontEnd(type: 'all' | 'preferences' | 'configs' = 'all'){ +function _sendRefetchEventToFrontEnd(type: 'all' | 'preferences' | 'configs' = 'all') { const eventName = 'mainAppEvent/refetch'; - if(mainWindow){ - mainWindow.webContents.send(eventName, {type}); + if (mainWindow) { + mainWindow.webContents.send(eventName, { type }); } } -function _shouldTraceCall( method: string, url: string){ - if(method.toLowerCase() === 'get'){ - if(url.includes('/api/configs') || url.includes('/api/preferences')){ +function _shouldTraceCall(method: string, url: string) { + if (method.toLowerCase() === 'get') { + if (url.includes('/api/configs') || url.includes('/api/preferences')) { return false; } } @@ -517,7 +536,7 @@ ipcMain.on('mainAppEvent/fetch', async (event, data) => { ok = false; } - if(_shouldTraceCall(method, url)){ + if (_shouldTraceCall(method, url)) { console.trace( 'Response', status, @@ -598,4 +617,4 @@ ipcMain.on('mainAppEvent/fetch', async (event, data) => { } catch (err) { console.info('error', err); } -}); \ No newline at end of file +}); diff --git a/src/main/utils/DisplayAdapter.Darwin.ts b/src/main/utils/DisplayAdapter.Darwin.ts index 46a247c..0b75b50 100644 --- a/src/main/utils/DisplayAdapter.Darwin.ts +++ b/src/main/utils/DisplayAdapter.Darwin.ts @@ -25,12 +25,13 @@ function getCache() { const _getDdcctlBinaryForIntel = async () => path.join(process['resourcesPath'], `ddcctl`); const _getDdcctlBinaryForM1 = async () => path.join(process['resourcesPath'], `m1ddc`); + const _getBrightnessBinary = async () => path.join(process['resourcesPath'], `brightness`); -async function _isM1Mac(){ - try{ +async function _isM1Mac() { + try { const preferences = await PreferenceUtils.get(); return preferences.mode === 'm1_mac'; - } catch(err){ + } catch (err) { return false; } } @@ -109,13 +110,15 @@ async function _getUpdateBrightnessShellScript( newBrightness: number, ): Promise { return new Promise(async (resolve, reject) => { - if(await _isM1Mac() === true){ + if ((await _isM1Mac()) === true) { // for external display const whichDisplay = await _findWhichExternalDisplayById(targetMonitorId); if (whichDisplay === undefined) { return reject(`Display not found`); } - return resolve(`${await _getDdcctlBinaryForM1()} display ${whichDisplay} set luminance ${newBrightness}`); + return resolve( + `${await _getDdcctlBinaryForM1()} display ${whichDisplay} set luminance ${newBrightness}`, + ); } try { @@ -130,7 +133,9 @@ async function _getUpdateBrightnessShellScript( return reject(`Display not found`); } - return resolve(`${await _getDdcctlBinaryForIntel()} -d ${whichDisplay} -b ${newBrightness}`); + return resolve( + `${await _getDdcctlBinaryForIntel()} -d ${whichDisplay} -b ${newBrightness}`, + ); } } catch (err) { reject(err); @@ -223,4 +228,4 @@ const DisplayAdapter: IDisplayAdapter = { }, }; -export default DisplayAdapter; \ No newline at end of file +export default DisplayAdapter; diff --git a/src/main/utils/DisplayAdapter.Win32.ts b/src/main/utils/DisplayAdapter.Win32.ts index 4c44238..9e4c939 100644 --- a/src/main/utils/DisplayAdapter.Win32.ts +++ b/src/main/utils/DisplayAdapter.Win32.ts @@ -5,7 +5,7 @@ import { IDisplayAdapter, Monitor } from 'src/types.d'; const _getDdcciScript = async () => path.join(process['resourcesPath'], `win32_ddcci.js`); let LAPTOP_DISPLAY_MONITOR_ID = ''; -let EXTERNAL_DISPLAY_MONITOR_IDS = new Set() +let EXTERNAL_DISPLAY_MONITOR_IDS = new Set(); /** * get current laptop brightness. more info here @@ -32,7 +32,7 @@ function _getBrightnessDccCi(targetMonitorId: string): Promise { return _sendMessageToBackgroundScript('getBrightness', targetMonitorId); } -async function _getMonitorList(){ +async function _getMonitorList() { return _sendMessageToBackgroundScript('getMonitorList'); } @@ -40,18 +40,21 @@ async function _setBrightnessDccCi(targetMonitorId: string, newBrightness: numbe return _sendMessageToBackgroundScript('setBrightness', targetMonitorId, newBrightness); } -async function _sendMessageToBackgroundScript(command : 'customScript' | 'getBrightness'| 'setBrightness' | 'getMonitorList', ...extra: any) : Promise{ +async function _sendMessageToBackgroundScript( + command: 'customScript' | 'getBrightness' | 'setBrightness' | 'getMonitorList', + ...extra: any +): Promise { return new Promise(async (resolve, reject) => { const targetChildProcess = ChildProcess.fork(await _getDdcciScript()); - targetChildProcess.on('message', function(response: any) { + targetChildProcess.on('message', function (response: any) { console.debug(`ddcci child process returned`, command, response); - const {success, data} = response; + const { success, data } = response; success === true ? resolve(data) : reject(); }); targetChildProcess.send([process['resourcesPath'], command, ...extra]); - }) + }); } const DisplayAdapter: IDisplayAdapter = { @@ -59,11 +62,11 @@ const DisplayAdapter: IDisplayAdapter = { return _getMonitorList(); }, getMonitorType: async (targetMonitorId: string) => { - if(LAPTOP_DISPLAY_MONITOR_ID === targetMonitorId){ + if (LAPTOP_DISPLAY_MONITOR_ID === targetMonitorId) { return 'laptop_monitor'; } - if(EXTERNAL_DISPLAY_MONITOR_IDS.has(targetMonitorId)){ + if (EXTERNAL_DISPLAY_MONITOR_IDS.has(targetMonitorId)) { return 'external_monitor'; } @@ -93,8 +96,8 @@ const DisplayAdapter: IDisplayAdapter = { }, getMonitorBrightness: async (targetMonitorId: string) => { try { - if(LAPTOP_DISPLAY_MONITOR_ID === targetMonitorId){ - return _getBrightnessBuiltin(); + if (LAPTOP_DISPLAY_MONITOR_ID === targetMonitorId) { + return _getBrightnessBuiltin(); } return _getBrightnessDccCi(targetMonitorId); } catch (err) {} @@ -106,7 +109,11 @@ const DisplayAdapter: IDisplayAdapter = { await _setBrightnessDccCi(targetMonitorId, newBrightness); } catch (err) { // monitor is a laptop - console.trace(`Update brightness failed with ddcci, trying builtin method`, targetMonitorId, newBrightness); + console.trace( + `Update brightness failed with ddcci, trying builtin method`, + targetMonitorId, + newBrightness, + ); try { await _setBrightnessBuiltin(newBrightness); } catch (err) { @@ -141,7 +148,7 @@ const DisplayAdapter: IDisplayAdapter = { ); return new Promise(async (resolve) => { - const msg : string= await _sendMessageToBackgroundScript('customScript', shellToRun); + const msg: string = await _sendMessageToBackgroundScript('customScript', shellToRun); const lines = msg .toString() .split('\n') @@ -174,4 +181,4 @@ const DisplayAdapter: IDisplayAdapter = { }, }; -export default DisplayAdapter; \ No newline at end of file +export default DisplayAdapter; diff --git a/src/main/utils/DisplayUtils.ts b/src/main/utils/DisplayUtils.ts index 37129c8..8584cdd 100644 --- a/src/main/utils/DisplayUtils.ts +++ b/src/main/utils/DisplayUtils.ts @@ -1,5 +1,8 @@ import DisplayAdapter from 'src/main/utils/DisplayAdapter'; -import StorageUtils, { MONITOR_CONFIG_FILE_PATH, PREFERENCE_FILE_PATH } from 'src/main/utils/StorageUtils'; +import StorageUtils, { + MONITOR_CONFIG_FILE_PATH, + PREFERENCE_FILE_PATH, +} from 'src/main/utils/StorageUtils'; import { Monitor, SingleMonitorUpdateInput } from 'src/types.d'; function _getMonitorConfigs(): Record { return StorageUtils.readJSON(MONITOR_CONFIG_FILE_PATH) || {}; @@ -117,10 +120,10 @@ const DisplayUtils = { monitorsFromStorage[monitor.id] = { ...monitorsFromStorage[monitor.id], ...monitor, - ...{name: nameToUse} + ...{ name: nameToUse }, }; - if(monitor.brightness !== undefined){ + if (monitor.brightness !== undefined) { console.trace(`updateMonitor brightness`, monitor.id, monitor.brightness); await DisplayAdapter.updateMonitorBrightness( @@ -172,4 +175,4 @@ const DisplayUtils = { updateDarkMode: DisplayAdapter.updateDarkMode, }; -export default DisplayUtils; \ No newline at end of file +export default DisplayUtils; diff --git a/src/main/utils/Endpoints.js b/src/main/utils/Endpoints.js index 1958d3f..2a8c7e4 100644 --- a/src/main/utils/Endpoints.js +++ b/src/main/utils/Endpoints.js @@ -50,15 +50,15 @@ export function setUpDataEndpoints() { addDataEndpoint('get', '/api/configs', async (req, res) => { try { let volume = { - isDisabled: true + isDisabled: true, }; - try{ + try { volume = { ...(await SoundUtils.getVolume()), isDisabled: false, - } - } catch(err1){} + }; + } catch (err1) {} res.status(200).json({ darkMode: (await DisplayUtils.getDarkMode()) === true, @@ -133,14 +133,14 @@ export function setUpDataEndpoints() { let preferredBrightness; const preferences = await PreferenceUtils.get(); - for(const brightnessPreset of preferences.brightnessPresets){ - if(isDarkModeOn){ - if(brightnessPreset.syncedWithMode === 'dark'){ + for (const brightnessPreset of preferences.brightnessPresets) { + if (isDarkModeOn) { + if (brightnessPreset.syncedWithMode === 'dark') { preferredBrightness = brightnessPreset.level; break; } } else { - if(brightnessPreset.syncedWithMode === 'light'){ + if (brightnessPreset.syncedWithMode === 'light') { preferredBrightness = brightnessPreset.level; break; } @@ -151,7 +151,9 @@ export function setUpDataEndpoints() { const promisesUpdates = [ DisplayUtils.updateDarkMode(isDarkModeOn), - preferredBrightness >= 0 && preferredBrightness <= 100 ? DisplayUtils.batchUpdateBrightness(preferredBrightness) : Promise.resolve(), + preferredBrightness >= 0 && preferredBrightness <= 100 + ? DisplayUtils.batchUpdateBrightness(preferredBrightness) + : Promise.resolve(), ]; res.status(200).json(await Promise.all(promisesUpdates)); @@ -169,7 +171,7 @@ export function setUpDataEndpoints() { console.trace(`Update Volume`, volume, muted); - if(muted !== undefined && !isNaN(volume)){ + if (muted !== undefined && !isNaN(volume)) { const promises = []; promises.push(SoundUtils.setMuted(muted === true)); promises.push(SoundUtils.setVolume(volume)); @@ -186,4 +188,4 @@ export function setUpDataEndpoints() { }); } }); -} \ No newline at end of file +} diff --git a/src/main/utils/LogUtils.js b/src/main/utils/LogUtils.js index 3226fbb..e4a9887 100644 --- a/src/main/utils/LogUtils.js +++ b/src/main/utils/LogUtils.js @@ -46,9 +46,9 @@ String.prototype.red = function () { return `\x1b[31m${this}\x1b[0m`; }; -async function _initializeLogUtils(){ +async function _initializeLogUtils() { const preferences = await PreferenceUtils.get(); - if(preferences.logging === true){ + if (preferences.logging === true) { // enable logging const origConsole = console.log; console.log = (...data) => { @@ -79,12 +79,12 @@ async function _initializeLogUtils(){ }; } else { // disable logging - console.log = () => {} - console.info = () => {} - console.error = () => {} - console.debug = () => {} - console.trace = () => {} + console.log = () => {}; + console.info = () => {}; + console.error = () => {}; + console.debug = () => {}; + console.trace = () => {}; } } -_initializeLogUtils(); \ No newline at end of file +_initializeLogUtils(); diff --git a/src/main/utils/NotificationUtils.ts b/src/main/utils/NotificationUtils.ts index 7204384..725fb3b 100644 --- a/src/main/utils/NotificationUtils.ts +++ b/src/main/utils/NotificationUtils.ts @@ -1,21 +1,21 @@ import { Notification } from 'electron'; import { debounce } from 'src/renderer/utils/CommonUtils'; -let lastNotification : Notification | undefined; +let lastNotification: Notification | undefined; -export function dismissLastNotification(){ - if(lastNotification){ +export function dismissLastNotification() { + if (lastNotification) { lastNotification.close(); lastNotification = undefined; } } -export function showNotification (body: string, title: string = 'display-dj') { +export function showNotification(body: string, title: string = 'display-dj') { dismissLastNotification(); - lastNotification = new Notification({ title, body}); - lastNotification.show() + lastNotification = new Notification({ title, body }); + lastNotification.show(); - debouncedDismissNotification() + debouncedDismissNotification(); } -const debouncedDismissNotification = debounce(dismissLastNotification, 3000); \ No newline at end of file +const debouncedDismissNotification = debounce(dismissLastNotification, 3000); diff --git a/src/main/utils/PositionUtils.js b/src/main/utils/PositionUtils.js index 07d877b..aca6c0f 100644 --- a/src/main/utils/PositionUtils.js +++ b/src/main/utils/PositionUtils.js @@ -38,4 +38,4 @@ const PositionUtils = { }, }; -export default PositionUtils; \ No newline at end of file +export default PositionUtils; diff --git a/src/main/utils/PreferenceUtils.spec.ts b/src/main/utils/PreferenceUtils.spec.ts index d1705a8..b48ab9b 100644 --- a/src/main/utils/PreferenceUtils.spec.ts +++ b/src/main/utils/PreferenceUtils.spec.ts @@ -11,6 +11,9 @@ describe('PreferenceUtils', () => { test('get', async () => { const actual = await PreferenceUtils.get(); + + delete actual.mode; + expect(actual).toMatchInlineSnapshot(` Object { "brightnessDelta": 25, @@ -87,7 +90,6 @@ describe('PreferenceUtils', () => { }, ], "logging": false, - "mode": "intel_mac", "showIndividualDisplays": false, "volumePresets": Array [ Object { @@ -211,6 +213,9 @@ describe('PreferenceUtils', () => { ...oldPrefs, brightnessDelta: 30, }); + + delete actual.mode; + expect(actual).toMatchInlineSnapshot(` Object { "brightnessDelta": 30, @@ -287,7 +292,6 @@ describe('PreferenceUtils', () => { }, ], "logging": false, - "mode": "intel_mac", "showIndividualDisplays": false, "volumePresets": Array [ Object { diff --git a/src/main/utils/PreferenceUtils.ts b/src/main/utils/PreferenceUtils.ts index e56c88c..84711ba 100644 --- a/src/main/utils/PreferenceUtils.ts +++ b/src/main/utils/PreferenceUtils.ts @@ -1,7 +1,7 @@ import StorageUtils, { PREFERENCE_FILE_PATH } from 'src/main/utils/StorageUtils'; import { Preference } from 'src/types.d'; -const MIN_BRIGHTNESS = 10;// NOTE : here if we set it to 0, some monitors / laptops will turn off the backlit entirely and make it unusable... +const MIN_BRIGHTNESS = 10; // NOTE : here if we set it to 0, some monitors / laptops will turn off the backlit entirely and make it unusable... const DEFAULT_PREFERENCES: Preference = { mode: process.platform === 'win32' ? 'win32' : 'intel_mac', // whether it's m1 mac or not @@ -9,15 +9,11 @@ const DEFAULT_PREFERENCES: Preference = { logging: false, brightnessDelta: 25, brightnessPresets: [ - { level: MIN_BRIGHTNESS, syncedWithMode: 'dark', }, + { level: MIN_BRIGHTNESS, syncedWithMode: 'dark' }, { level: 50 }, - { level: 100, syncedWithMode: 'light', }, - ], - volumePresets: [ - { level: 0 }, - { level: 50 }, - { level: 100 }, + { level: 100, syncedWithMode: 'light' }, ], + volumePresets: [{ level: 0 }, { level: 50 }, { level: 100 }], keyBindings: [ { key: `Shift+Escape`, command: [`command/changeDarkMode/toggle`] }, { @@ -30,11 +26,23 @@ const DEFAULT_PREFERENCES: Preference = { command: [`command/changeDarkMode/light`, `command/changeBrightness/100`], notification: `Switching to Light Profile`, }, - { key: `Shift+F3`, command: [`command/changeBrightness/${MIN_BRIGHTNESS}`], notification: `Brightness is ${MIN_BRIGHTNESS}%`,}, - { key: `Shift+F4`, command: [`command/changeBrightness/50`],notification: `Brightness is 50%`, }, - { key: `Shift+F5`, command: [`command/changeBrightness/100`], notification: `Brightness is 100%`,}, - { key: `Shift+F6`, command: [`command/changeVolume/0`],notification: `Volume is Muted`, }, - { key: `Shift+F7`, command: [`command/changeVolume/100`],notification: `Volume is 100%`, }, + { + key: `Shift+F3`, + command: [`command/changeBrightness/${MIN_BRIGHTNESS}`], + notification: `Brightness is ${MIN_BRIGHTNESS}%`, + }, + { + key: `Shift+F4`, + command: [`command/changeBrightness/50`], + notification: `Brightness is 50%`, + }, + { + key: `Shift+F5`, + command: [`command/changeBrightness/100`], + notification: `Brightness is 100%`, + }, + { key: `Shift+F6`, command: [`command/changeVolume/0`], notification: `Volume is Muted` }, + { key: `Shift+F7`, command: [`command/changeVolume/100`], notification: `Volume is 100%` }, ], }; @@ -82,12 +90,12 @@ const PreferenceUtils = { getKeybindings: async () => { return (await PreferenceUtils.get()).keyBindings; }, - getBrightnessPresets: async() => { + getBrightnessPresets: async () => { return (await PreferenceUtils.get()).brightnessPresets; }, - getVolumePresets: async() => { + getVolumePresets: async () => { return (await PreferenceUtils.get()).volumePresets; - } + }, }; -export default PreferenceUtils; \ No newline at end of file +export default PreferenceUtils; diff --git a/src/main/utils/RestUtils.js b/src/main/utils/RestUtils.js index 019de87..47b1d0a 100644 --- a/src/main/utils/RestUtils.js +++ b/src/main/utils/RestUtils.js @@ -1,26 +1,27 @@ import https from 'https'; -export async function getText(url){ +export async function getText(url) { return new Promise(async (resolve, reject) => { - https.get(url, (resp) => { - let data = ''; + https + .get(url, (resp) => { + let data = ''; - // A chunk of data has been received. - resp.on('data', (chunk) => { - data += chunk; - }); + // A chunk of data has been received. + resp.on('data', (chunk) => { + data += chunk; + }); - // The whole response has been received. Print out the result. - resp.on('end', () => { - resolve(data); + // The whole response has been received. Print out the result. + resp.on('end', () => { + resolve(data); + }); + }) + .on('error', (err) => { + reject(err); }); - - }).on("error", (err) => { - reject(err); - }); - }) + }); } -export async function getJSON(url){ - return JSON.parse(await getText(url)) -} \ No newline at end of file +export async function getJSON(url) { + return JSON.parse(await getText(url)); +} diff --git a/src/main/utils/SetupShortcutForWin32.ts b/src/main/utils/SetupShortcutForWin32.ts index db7df46..19da94e 100644 --- a/src/main/utils/SetupShortcutForWin32.ts +++ b/src/main/utils/SetupShortcutForWin32.ts @@ -22,17 +22,17 @@ function _handleSquirrelEventForWindows() { const updateDotExe = path.resolve(path.join(rootAtomFolder, 'Update.exe')); const exeName = path.basename(process.execPath); - const spawn = function(command, args) { + const spawn = function (command, args) { let spawnedProcess, error; try { - spawnedProcess = ChildProcess.spawn(command, args, {detached: true}); + spawnedProcess = ChildProcess.spawn(command, args, { detached: true }); } catch (error) {} return spawnedProcess; }; - const spawnUpdate = function(args) { + const spawnUpdate = function (args) { return spawn(updateDotExe, args); }; @@ -53,8 +53,8 @@ function _handleSquirrelEventForWindows() { app.quit(); return true; } -}; +} if (_handleSquirrelEventForWindows()) { process.exit(); -} \ No newline at end of file +} diff --git a/src/main/utils/ShellUtils.ts b/src/main/utils/ShellUtils.ts index 2ed82f5..94ff18a 100644 --- a/src/main/utils/ShellUtils.ts +++ b/src/main/utils/ShellUtils.ts @@ -34,4 +34,4 @@ export function executeBash(shellToRun: string, delay = 25): Promise { }); }, delay); }); -} \ No newline at end of file +} diff --git a/src/main/utils/SoundUtils.Darwin.ts b/src/main/utils/SoundUtils.Darwin.ts index fe14a1f..8032df7 100644 --- a/src/main/utils/SoundUtils.Darwin.ts +++ b/src/main/utils/SoundUtils.Darwin.ts @@ -1,14 +1,14 @@ import loudness from 'loudness'; const SoundUtils = { - getVolume: async() => { + getVolume: async () => { return { value: await loudness.getVolume(), - muted: await loudness.getMuted() - } + muted: await loudness.getMuted(), + }; }, setVolume: async (value: number) => loudness.setVolume(value), setMuted: async (muted: boolean) => loudness.setMuted(muted), -} +}; -export default SoundUtils; \ No newline at end of file +export default SoundUtils; diff --git a/src/main/utils/SoundUtils.Win32.ts b/src/main/utils/SoundUtils.Win32.ts index 55c3594..98df4ca 100644 --- a/src/main/utils/SoundUtils.Win32.ts +++ b/src/main/utils/SoundUtils.Win32.ts @@ -1,25 +1,31 @@ import path from 'path'; import { executeBash } from 'src/main/utils/ShellUtils'; -const _getVolumeHelperBinary = async () => path.join(process['resourcesPath'], `win32_volume_helper.exe`); +const _getVolumeHelperBinary = async () => + path.join(process['resourcesPath'], `win32_volume_helper.exe`); const SoundUtils = { - getVolume: async() => { - const splits = (await executeBash(await _getVolumeHelperBinary())).split(/[ ]+/).map( s=> s.trim()).filter(s => s); + getVolume: async () => { + const splits = (await executeBash(await _getVolumeHelperBinary())) + .split(/[ ]+/) + .map((s) => s.trim()) + .filter((s) => s); const value: number = parseInt(splits[0]); const muted: boolean = splits[1] === '1'; - if(value > 100 || value < 0){ + if (value > 100 || value < 0) { throw 'Failed to get the volume'; } return { value, - muted - } + muted, + }; }, - setVolume: async (value: number) => await executeBash(`${await _getVolumeHelperBinary()} ${value}`), - setMuted: async (muted: boolean) => await executeBash(`${await _getVolumeHelperBinary()} ${muted ? 'mute' : 'unmute'}`), -} + setVolume: async (value: number) => + await executeBash(`${await _getVolumeHelperBinary()} ${value}`), + setMuted: async (muted: boolean) => + await executeBash(`${await _getVolumeHelperBinary()} ${muted ? 'mute' : 'unmute'}`), +}; -export default SoundUtils; \ No newline at end of file +export default SoundUtils; diff --git a/src/main/utils/StorageUtils.ts b/src/main/utils/StorageUtils.ts index f968185..13d2d12 100644 --- a/src/main/utils/StorageUtils.ts +++ b/src/main/utils/StorageUtils.ts @@ -50,4 +50,4 @@ const StorageUtils = { }, }; -export default StorageUtils; \ No newline at end of file +export default StorageUtils; diff --git a/src/renderer/hooks.ts b/src/renderer/hooks.ts index 900f016..dc68c1c 100644 --- a/src/renderer/hooks.ts +++ b/src/renderer/hooks.ts @@ -10,11 +10,11 @@ export const QUERY_KEY_PREFERENCE = 'preferences'; // app state (not used anymore, but left as is if we want to add new global state to the app) let _appState: UIAppState; -let _config : AppConfig; -let _preferences : Preference; +let _config: AppConfig; +let _preferences: Preference; export function useAppState() { - return useQuery(QUERY_KEY_APP_STATE, () => _appState, {notifyOnChangeProps: ['data', 'error']}); + return useQuery(QUERY_KEY_APP_STATE, () => _appState, { notifyOnChangeProps: ['data', 'error'] }); } export function useUpdateAppState() { @@ -32,12 +32,16 @@ export function useUpdateAppState() { // preference export function usePreferences() { - return useQuery(QUERY_KEY_PREFERENCE, async () => { - if(_preferences === undefined){ - _preferences = await ApiUtils.getPreferences(); - } - return _preferences; - }, {notifyOnChangeProps: ['data', 'error']}); + return useQuery( + QUERY_KEY_PREFERENCE, + async () => { + if (_preferences === undefined) { + _preferences = await ApiUtils.getPreferences(); + } + return _preferences; + }, + { notifyOnChangeProps: ['data', 'error'] }, + ); } export function useUpdatePreferences() { @@ -45,18 +49,22 @@ export function useUpdatePreferences() { return useMutation(ApiUtils.updatePreferences, { onSuccess: async () => { await refetchPreferences(); - } + }, }); } // configs export function useConfigs() { - return useQuery(QUERY_KEY_CONFIGS, async () => { - if(_config === undefined){ - _config = await ApiUtils.getConfigs(); - } - return _config; - }, {notifyOnChangeProps: ['data', 'error'],}); + return useQuery( + QUERY_KEY_CONFIGS, + async () => { + if (_config === undefined) { + _config = await ApiUtils.getConfigs(); + } + return _config; + }, + { notifyOnChangeProps: ['data', 'error'] }, + ); } export function useUpdateMonitor() { @@ -64,7 +72,7 @@ export function useUpdateMonitor() { return useMutation(ApiUtils.updateMonitor, { onSuccess: async () => { await refetchConfigs(); - } + }, }); } @@ -73,7 +81,7 @@ export function useBatchUpdateMonitors() { return useMutation(ApiUtils.batchUpdateMonitors, { onSuccess: async () => { await refetchConfigs(); - } + }, }); } @@ -82,7 +90,7 @@ export function useToggleDarkMode() { return useMutation(ApiUtils.updateDarkMode, { onSuccess: async () => { await refetchConfigs(); - } + }, }); } @@ -91,7 +99,7 @@ export function useUpdateVolume() { return useMutation(ApiUtils.updateVolume, { onSuccess: async () => { await refetchConfigs(); - } + }, }); } @@ -101,24 +109,20 @@ export function useUpdateAppPosition() { } // refetch -export function useRefetchConfigs(){ - const { data: preference } = usePreferences(); +export function useRefetchConfigs() { const queryClient = useQueryClient(); return async () => { - if(preference?.mode === 'm1_mac'){ - return; - } - console.log('>> Refetch Configs') + console.log('>> Refetch Configs'); _config = await ApiUtils.getConfigs(); - queryClient.invalidateQueries(QUERY_KEY_CONFIGS) + queryClient.invalidateQueries(QUERY_KEY_CONFIGS); }; } -export function useRefetchPreferences(){ +export function useRefetchPreferences() { const queryClient = useQueryClient(); return async () => { - console.log('>> Refetch preferences') + console.log('>> Refetch preferences'); _preferences = await ApiUtils.getPreferences(); - queryClient.invalidateQueries(QUERY_KEY_PREFERENCE) + queryClient.invalidateQueries(QUERY_KEY_PREFERENCE); }; } diff --git a/src/renderer/utils/ApiUtils.ts b/src/renderer/utils/ApiUtils.ts index 870c744..02fbbd5 100644 --- a/src/renderer/utils/ApiUtils.ts +++ b/src/renderer/utils/ApiUtils.ts @@ -1,5 +1,11 @@ import { fetch } from 'src/renderer/utils/FetchUtils'; -import { AppConfig, BatchMonitorUpdateInput, Preference, SingleMonitorUpdateInput, VolumeInput } from 'src/types.d'; +import { + AppConfig, + BatchMonitorUpdateInput, + Preference, + SingleMonitorUpdateInput, + VolumeInput, +} from 'src/types.d'; const ApiUtils = { // preferences @@ -43,4 +49,4 @@ const ApiUtils = { }), }; -export default ApiUtils; \ No newline at end of file +export default ApiUtils; diff --git a/src/renderer/utils/CommonUtils.ts b/src/renderer/utils/CommonUtils.ts index a3328f5..b636844 100644 --- a/src/renderer/utils/CommonUtils.ts +++ b/src/renderer/utils/CommonUtils.ts @@ -1,8 +1,8 @@ -export function debounce(cb: (...args: any []) => any, delay = 300){ - let timerId : any; +export function debounce(cb: (...args: any[]) => any, delay = 300) { + let timerId: any; return (...inputs: any[]) => { clearTimeout(timerId); timerId = setTimeout(() => cb(...inputs), delay); - } + }; } diff --git a/src/renderer/utils/FetchUtils.ts b/src/renderer/utils/FetchUtils.ts index 1e2b676..43d7e7a 100644 --- a/src/renderer/utils/FetchUtils.ts +++ b/src/renderer/utils/FetchUtils.ts @@ -80,4 +80,4 @@ export function fetch(input: string, initOptions?: RequestInit): Promise { const res: T = r; return res; }); -} \ No newline at end of file +} diff --git a/src/types.d.ts b/src/types.d.ts index 36334c1..702fa6f 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -89,7 +89,7 @@ export type IDisplayAdapter = { }; export type Preference = { - mode?: 'win32' |'m1_mac' | 'intel_mac', + mode?: 'win32' | 'm1_mac' | 'intel_mac'; showIndividualDisplays: boolean; logging: boolean; brightnessDelta: number;