diff --git a/main.js b/main.js index 62c530998..d1fc79aeb 100644 --- a/main.js +++ b/main.js @@ -1,4 +1,10 @@ -const { ipcMain: ipc, app, nativeTheme, Menu } = require('electron/main'); +const { + ipcMain: ipc, + app, + nativeTheme, + globalShortcut, + Menu, +} = require('electron/main'); const { menubar } = require('menubar'); const { autoUpdater } = require('electron-updater'); const { onFirstRunMaybe } = require('./first-run'); @@ -122,6 +128,24 @@ app.whenReady().then(async () => { } }); + ipc.on( + 'gitify:update-keyboard-shortcut', + (_, { enabled, keyboardShortcut }) => { + if (!enabled) { + globalShortcut.unregister(keyboardShortcut); + return; + } + + globalShortcut.register(keyboardShortcut, () => { + if (mb.window.isVisible()) { + mb.hideWindow(); + } else { + mb.showWindow(); + } + }); + }, + ); + ipc.on('gitify:update-auto-launch', (_, settings) => { app.setLoginItemSettings(settings); }); diff --git a/src/__mocks__/state-mocks.ts b/src/__mocks__/state-mocks.ts index cc2848e69..b68810171 100644 --- a/src/__mocks__/state-mocks.ts +++ b/src/__mocks__/state-mocks.ts @@ -83,6 +83,7 @@ export const mockSettings: SettingsState = { showAccountHostname: false, delayNotificationState: false, showPills: true, + keyboardShortcut: true, }; export const mockState: GitifyState = { diff --git a/src/context/App.test.tsx b/src/context/App.test.tsx index f7cc61913..0f6ec61b6 100644 --- a/src/context/App.test.tsx +++ b/src/context/App.test.tsx @@ -379,6 +379,7 @@ describe('context/App.tsx', () => { showAccountHostname: false, delayNotificationState: false, showPills: true, + keyboardShortcut: true, } as SettingsState, }); }); @@ -430,6 +431,7 @@ describe('context/App.tsx', () => { showAccountHostname: false, delayNotificationState: false, showPills: true, + keyboardShortcut: true, } as SettingsState, }); }); diff --git a/src/context/App.tsx b/src/context/App.tsx index 6114d3491..a9b6c33b6 100644 --- a/src/context/App.tsx +++ b/src/context/App.tsx @@ -31,7 +31,11 @@ import { getUserData, removeAccount, } from '../utils/auth/utils'; -import { setAutoLaunch, updateTrayTitle } from '../utils/comms'; +import { + setAutoLaunch, + setKeyboardShortcut, + updateTrayTitle, +} from '../utils/comms'; import Constants from '../utils/constants'; import { getNotificationCount } from '../utils/notifications'; import { clearState, loadState, saveState } from '../utils/storage'; @@ -57,6 +61,7 @@ export const defaultSettings: SettingsState = { showAccountHostname: false, delayNotificationState: false, showPills: true, + keyboardShortcut: true, }; interface AppContextState { @@ -140,6 +145,10 @@ export const AppProvider = ({ children }: { children: ReactNode }) => { } }, [settings.showNotificationsCountInTray, notifications]); + useEffect(() => { + setKeyboardShortcut(settings.keyboardShortcut); + }, [settings.keyboardShortcut]); + const updateSetting = useCallback( (name: keyof SettingsState, value: boolean | Theme) => { if (name === 'openAtStartup') { @@ -220,6 +229,7 @@ export const AppProvider = ({ children }: { children: ReactNode }) => { } if (existing.settings) { + setKeyboardShortcut(existing.settings.keyboardShortcut); setSettings({ ...defaultSettings, ...existing.settings }); return existing.settings; } diff --git a/src/routes/Settings.test.tsx b/src/routes/Settings.test.tsx index 399aaefe4..b316bb092 100644 --- a/src/routes/Settings.test.tsx +++ b/src/routes/Settings.test.tsx @@ -378,6 +378,31 @@ describe('routes/Settings.tsx', () => { }); describe('System section', () => { + it('should toggle the keyboardShortcut checkbox', async () => { + await act(async () => { + render( + + + + + , + ); + }); + + fireEvent.click(screen.getByLabelText('Enable keyboard shortcut'), { + target: { checked: true }, + }); + + expect(updateSetting).toHaveBeenCalledTimes(1); + expect(updateSetting).toHaveBeenCalledWith('keyboardShortcut', false); + }); + it('should toggle the showNotificationsCountInTray checkbox', async () => { await act(async () => { render( diff --git a/src/routes/Settings.tsx b/src/routes/Settings.tsx index cae398c57..2ae06c275 100644 --- a/src/routes/Settings.tsx +++ b/src/routes/Settings.tsx @@ -23,6 +23,7 @@ import { AppContext } from '../context/App'; import { BUTTON_CLASS_NAME } from '../styles/gitify'; import { Theme } from '../types'; import { getAppVersion, quitApp } from '../utils/comms'; +import Constants from '../utils/constants'; import { openGitHubParticipatingDocs, openGitifyReleaseNotes, @@ -211,7 +212,7 @@ export const SettingsRoute: FC = () => {
Keep the notification within Gitify window upon interaction (click, mark as read, mark as done, etc) until the next refresh - window (scheduled or user initiated) + window (scheduled or user initiated).
} /> @@ -221,6 +222,23 @@ export const SettingsRoute: FC = () => { System + + updateSetting('keyboardShortcut', evt.target.checked) + } + tooltip={ +
+ When enabled you can choose to use the hotkeys{' '} + + {Constants.DEFAULT_KEYBOARD_SHORTCUT} + {' '} + to show or hide Gitify. +
+ } + /> {isMacOS() && ( System +
+
+
+ +
+
+ +
+
+
diff --git a/src/types.ts b/src/types.ts index 410c5c95a..66b78dafd 100644 --- a/src/types.ts +++ b/src/types.ts @@ -74,6 +74,7 @@ interface SystemSettingsState { playSound: boolean; openAtStartup: boolean; showNotificationsCountInTray: boolean; + keyboardShortcut: boolean; } export interface GitifyState { diff --git a/src/utils/comms.ts b/src/utils/comms.ts index 815992ed8..e19bef005 100644 --- a/src/utils/comms.ts +++ b/src/utils/comms.ts @@ -1,5 +1,6 @@ import { ipcRenderer, shell } from 'electron'; import type { Link } from '../types'; +import Constants from './constants'; export function openExternalLink(url: Link): void { if (!url.toLowerCase().startsWith('file:///')) { @@ -30,6 +31,13 @@ export function setAutoLaunch(value: boolean): void { }); } +export function setKeyboardShortcut(keyboardShortcut: boolean): void { + ipcRenderer.send('gitify:update-keyboard-shortcut', { + enabled: keyboardShortcut, + keyboardShortcut: Constants.DEFAULT_KEYBOARD_SHORTCUT, + }); +} + export function updateTrayIcon(notificationsLength = 0): void { if (notificationsLength > 0) { ipcRenderer.send('gitify:icon-active'); diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 229c3708b..a199fac97 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -23,6 +23,8 @@ export const Constants = { FETCH_INTERVAL: 60000, + DEFAULT_KEYBOARD_SHORTCUT: 'CommandOrControl+Shift+G', + // GitHub Docs GITHUB_DOCS: { OAUTH_URL: