diff --git a/main.js b/main.js index a6d61e19b..832a0162a 100644 --- a/main.js +++ b/main.js @@ -75,6 +75,11 @@ menubarApp.on('ready', () => { } } }); + ipcMain.on('update-title', (_, title) => { + if (!menubarApp.tray.isDestroyed()) { + menubarApp.tray.setTitle(title); + } + }); ipcMain.on('set-login-item-settings', (event, settings) => { app.setLoginItemSettings(settings); }); diff --git a/src/__mocks__/mock-state.ts b/src/__mocks__/mock-state.ts index bb8b7a3cc..59b9fcbcb 100644 --- a/src/__mocks__/mock-state.ts +++ b/src/__mocks__/mock-state.ts @@ -12,6 +12,7 @@ export const mockSettings: SettingsState = { playSound: true, showNotifications: true, showBots: true, + showNotificationsCountInTray: false, openAtStartup: false, theme: Theme.SYSTEM, colors: false, diff --git a/src/context/App.test.tsx b/src/context/App.test.tsx index d31f24631..00a5acdc2 100644 --- a/src/context/App.test.tsx +++ b/src/context/App.test.tsx @@ -8,6 +8,7 @@ import { useNotifications } from '../hooks/useNotifications'; import * as apiRequests from '../utils/api-requests'; import * as comms from '../utils/comms'; import * as storage from '../utils/storage'; +import * as notifications from '../utils/notifications'; jest.mock('../hooks/useNotifications'); @@ -35,6 +36,11 @@ describe('context/App.tsx', () => { describe('api methods', () => { const apiRequestAuthMock = jest.spyOn(apiRequests, 'apiRequestAuth'); + const getNotificationCountMock = jest.spyOn( + notifications, + 'getNotificationCount', + ); + getNotificationCountMock.mockReturnValue(1); const fetchNotificationsMock = jest.fn(); const markNotificationMock = jest.fn(); @@ -285,12 +291,13 @@ describe('context/App.tsx', () => { expect(saveStateMock).toHaveBeenCalledWith( { enterpriseAccounts: [], token: null, user: null }, { - theme: 'SYSTEM', - openAtStartup: false, participating: true, playSound: true, showNotifications: true, showBots: true, + showNotificationsCountInTray: false, + openAtStartup: false, + theme: 'SYSTEM', colors: null, markAsDoneOnOpen: false, }, @@ -324,12 +331,13 @@ describe('context/App.tsx', () => { expect(saveStateMock).toHaveBeenCalledWith( { enterpriseAccounts: [], token: null, user: null }, { - theme: 'SYSTEM', - openAtStartup: true, participating: false, playSound: true, showNotifications: true, showBots: true, + showNotificationsCountInTray: false, + openAtStartup: true, + theme: 'SYSTEM', colors: null, markAsDoneOnOpen: false, }, diff --git a/src/context/App.tsx b/src/context/App.tsx index 6fe2e7587..8d7907a04 100644 --- a/src/context/App.tsx +++ b/src/context/App.tsx @@ -19,10 +19,11 @@ import { import { apiRequestAuth } from '../utils/api-requests'; import { setTheme } from '../utils/theme'; import { addAccount, authGitHub, getToken, getUserData } from '../utils/auth'; -import { setAutoLaunch } from '../utils/comms'; +import { setAutoLaunch, updateTrayTitle } from '../utils/comms'; import Constants from '../utils/constants'; import { generateGitHubAPIUrl } from '../utils/helpers'; import { clearState, loadState, saveState } from '../utils/storage'; +import { getNotificationCount } from '../utils/notifications'; const defaultAccounts: AuthState = { token: null, @@ -35,6 +36,7 @@ export const defaultSettings: SettingsState = { playSound: true, showNotifications: true, showBots: true, + showNotificationsCountInTray: false, openAtStartup: false, theme: Theme.SYSTEM, colors: null, @@ -98,6 +100,16 @@ export const AppProvider = ({ children }: { children: React.ReactNode }) => { fetchNotifications(accounts, settings); }, [accounts.token, accounts.enterpriseAccounts.length]); + useEffect(() => { + const count = getNotificationCount(notifications); + + if (settings.showNotificationsCountInTray && count > 0) { + updateTrayTitle(count.toString()); + } else { + updateTrayTitle(); + } + }, [settings.showNotificationsCountInTray, notifications]); + useInterval(() => { fetchNotifications(accounts, settings); }, 60000); diff --git a/src/routes/Settings.test.tsx b/src/routes/Settings.test.tsx index 4fe105b75..e8b608b9e 100644 --- a/src/routes/Settings.test.tsx +++ b/src/routes/Settings.test.tsx @@ -71,8 +71,9 @@ describe('routes/Settings.tsx', () => { expect(logoutMock).toHaveBeenCalledTimes(1); - expect(ipcRenderer.send).toHaveBeenCalledTimes(1); + expect(ipcRenderer.send).toHaveBeenCalledTimes(2); expect(ipcRenderer.send).toHaveBeenCalledWith('update-icon'); + expect(ipcRenderer.send).toHaveBeenCalledWith('update-title', ''); expect(mockNavigate).toHaveBeenNthCalledWith(1, -1); }); @@ -155,6 +156,37 @@ describe('routes/Settings.tsx', () => { expect(updateSetting).toHaveBeenCalledWith('showBots', false); }); + it('should toggle the showNotificationsCountInTray checkbox', async () => { + let getByLabelText; + + await act(async () => { + const { getByLabelText: getByLabelTextLocal } = render( + + + + + , + ); + getByLabelText = getByLabelTextLocal; + }); + + fireEvent.click(getByLabelText('Show notifications count in tray'), { + target: { checked: true }, + }); + + expect(updateSetting).toHaveBeenCalledTimes(1); + expect(updateSetting).toHaveBeenCalledWith( + 'showNotificationsCountInTray', + false, + ); + }); + it('should toggle the playSound checkbox', async () => { let getByLabelText; diff --git a/src/routes/Settings.tsx b/src/routes/Settings.tsx index 6a45de3d5..3017d2941 100644 --- a/src/routes/Settings.tsx +++ b/src/routes/Settings.tsx @@ -20,7 +20,11 @@ import { AppContext } from '../context/App'; import { Theme } from '../types'; import { apiRequestAuth } from '../utils/api-requests'; import { setTheme } from '../utils/theme'; -import { openExternalLink, updateTrayIcon } from '../utils/comms'; +import { + openExternalLink, + updateTrayIcon, + updateTrayTitle, +} from '../utils/comms'; import Constants from '../utils/constants'; import { generateGitHubAPIUrl } from '../utils/helpers'; @@ -71,6 +75,7 @@ export const SettingsRoute: React.FC = () => { logout(); navigate(-1); updateTrayIcon(); + updateTrayTitle(); }, []); const quitApp = useCallback(() => { @@ -168,6 +173,14 @@ export const SettingsRoute: React.FC = () => { System + + updateSetting('showNotificationsCountInTray', evt.target.checked) + } + /> System +
+
+ +
+
+ +
+
diff --git a/src/types.ts b/src/types.ts index 9fcc62997..f1a752847 100644 --- a/src/types.ts +++ b/src/types.ts @@ -25,6 +25,7 @@ interface NotificationSettingsState { interface SystemSettingsState { playSound: boolean; openAtStartup: boolean; + showNotificationsCountInTray: boolean; } export enum Theme { diff --git a/src/utils/comms.ts b/src/utils/comms.ts index 03beca86a..b14c62ddd 100644 --- a/src/utils/comms.ts +++ b/src/utils/comms.ts @@ -21,6 +21,10 @@ export function updateTrayIcon(notificationsLength = 0): void { } } +export function updateTrayTitle(title: string = ''): void { + ipcRenderer.send('update-title', title); +} + export function restoreSetting(setting, value): void { ipcRenderer.send(setting, value); }