Skip to content

Commit c5f6447

Browse files
authored
feat(settings): tray icon color (#2249)
* feat(settings): tray icon color Signed-off-by: Adam Setch <[email protected]> * feat(settings): tray icon color Signed-off-by: Adam Setch <[email protected]> * feat(settings): tray icon color Signed-off-by: Adam Setch <[email protected]> * refactor to change language to highlight unread notifications Signed-off-by: Adam Setch <[email protected]> * refactor to change language to highlight unread notifications Signed-off-by: Adam Setch <[email protected]> --------- Signed-off-by: Adam Setch <[email protected]>
1 parent 3b44d8b commit c5f6447

File tree

18 files changed

+412
-181
lines changed

18 files changed

+412
-181
lines changed

src/main/index.ts

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ app.setAsDefaultProtocolClient(protocol);
7575
const appUpdater = new AppUpdater(mb, menuBuilder);
7676

7777
let shouldUseAlternateIdleIcon = false;
78+
let shouldUseUnreadActiveIcon = false;
7879

7980
app.whenReady().then(async () => {
8081
await onFirstRunMaybe();
@@ -160,14 +161,25 @@ app.whenReady().then(async () => {
160161
},
161162
);
162163

164+
onMainEvent(
165+
EVENTS.USE_UNREAD_ACTIVE_ICON,
166+
(_, useUnreadActiveIcon: boolean) => {
167+
shouldUseUnreadActiveIcon = useUnreadActiveIcon;
168+
169+
if (!shouldUseUnreadActiveIcon) {
170+
setIdleIcon();
171+
}
172+
},
173+
);
174+
163175
onMainEvent(EVENTS.ICON_ERROR, () => {
164176
if (!mb.tray.isDestroyed()) {
165177
mb.tray.setImage(TrayIcons.error);
166178
}
167179
});
168180

169181
onMainEvent(EVENTS.ICON_ACTIVE, () => {
170-
if (!mb.tray.isDestroyed()) {
182+
if (!mb.tray.isDestroyed() && shouldUseUnreadActiveIcon) {
171183
mb.tray.setImage(
172184
menuBuilder.isUpdateAvailable()
173185
? TrayIcons.activeWithUpdate
@@ -178,19 +190,7 @@ app.whenReady().then(async () => {
178190

179191
onMainEvent(EVENTS.ICON_IDLE, () => {
180192
if (!mb.tray.isDestroyed()) {
181-
if (shouldUseAlternateIdleIcon) {
182-
mb.tray.setImage(
183-
menuBuilder.isUpdateAvailable()
184-
? TrayIcons.idleAlternateWithUpdate
185-
: TrayIcons.idleAlternate,
186-
);
187-
} else {
188-
mb.tray.setImage(
189-
menuBuilder.isUpdateAvailable()
190-
? TrayIcons.idleWithUpdate
191-
: TrayIcons.idle,
192-
);
193-
}
193+
setIdleIcon();
194194
}
195195
});
196196

@@ -258,3 +258,19 @@ const handleURL = (url: string) => {
258258
sendRendererEvent(mb, EVENTS.AUTH_CALLBACK, url);
259259
}
260260
};
261+
262+
function setIdleIcon() {
263+
if (shouldUseAlternateIdleIcon) {
264+
mb.tray.setImage(
265+
menuBuilder.isUpdateAvailable()
266+
? TrayIcons.idleAlternateWithUpdate
267+
: TrayIcons.idleAlternate,
268+
);
269+
} else {
270+
mb.tray.setImage(
271+
menuBuilder.isUpdateAvailable()
272+
? TrayIcons.idleWithUpdate
273+
: TrayIcons.idle,
274+
);
275+
}
276+
}

src/preload/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ export const api = {
5353

5454
useAlternateIdleIcon: (value: boolean) =>
5555
sendMainEvent(EVENTS.USE_ALTERNATE_IDLE_ICON, value),
56+
57+
useUnreadActiveIcon: (value: boolean) =>
58+
sendMainEvent(EVENTS.USE_UNREAD_ACTIVE_ICON, value),
5659
},
5760

5861
notificationSoundPath: () => invokeMainEvent(EVENTS.NOTIFICATION_SOUND_PATH),

src/renderer/__helpers__/jest.setup.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ window.gitify = {
2929
updateIcon: jest.fn(),
3030
updateTitle: jest.fn(),
3131
useAlternateIdleIcon: jest.fn(),
32+
useUnreadActiveIcon: jest.fn(),
3233
},
3334
notificationSoundPath: jest.fn(),
3435
onAuthCallback: jest.fn(),

src/renderer/__mocks__/state-mocks.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
type SystemSettingsState,
1616
Theme,
1717
type Token,
18+
type TraySettingsState,
1819
} from '../types';
1920

2021
export const mockGitifyUser: GitifyUser = {
@@ -96,14 +97,18 @@ const mockNotificationSettings: NotificationSettingsState = {
9697
delayNotificationState: false,
9798
};
9899

100+
const mockTraySettings: TraySettingsState = {
101+
showNotificationsCountInTray: true,
102+
useUnreadActiveIcon: true,
103+
useAlternateIdleIcon: false,
104+
};
105+
99106
const mockSystemSettings: SystemSettingsState = {
100107
openLinks: OpenPreference.FOREGROUND,
101108
keyboardShortcut: true,
102-
showNotificationsCountInTray: true,
103109
showNotifications: true,
104110
playSound: true,
105111
notificationVolume: 20,
106-
useAlternateIdleIcon: false,
107112
openAtStartup: false,
108113
};
109114

@@ -119,6 +124,7 @@ const mockFilters: FilterSettingsState = {
119124
export const mockSettings: SettingsState = {
120125
...mockAppearanceSettings,
121126
...mockNotificationSettings,
127+
...mockTraySettings,
122128
...mockSystemSettings,
123129
...mockFilters,
124130
};

src/renderer/components/fields/Tooltip.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export const Tooltip: FC<ITooltip> = (props: ITooltip) => {
2222
>
2323
<QuestionIcon className="text-gitify-tooltip-icon" />
2424
{showTooltip && (
25-
<div className="absolute left-[-80px] z-10 w-60 rounded-sm border border-gray-300 p-2 shadow-sm bg-gitify-tooltip-popout">
25+
<div className="absolute left-[-80px] z-10 w-30 rounded-sm border border-gray-300 p-2 shadow-sm bg-gitify-tooltip-popout">
2626
<div className="text-left text-xs text-gitify-font">
2727
{props.tooltip}
2828
</div>

src/renderer/components/fields/__snapshots__/Tooltip.test.tsx.snap

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/renderer/components/settings/SystemSettings.test.tsx

Lines changed: 0 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -54,32 +54,6 @@ describe('renderer/components/settings/SystemSettings.tsx', () => {
5454
expect(updateSetting).toHaveBeenCalledWith('keyboardShortcut', false);
5555
});
5656

57-
it('should toggle the showNotificationsCountInTray checkbox', async () => {
58-
await act(async () => {
59-
render(
60-
<AppContext.Provider
61-
value={{
62-
auth: mockAuth,
63-
settings: mockSettings,
64-
updateSetting,
65-
}}
66-
>
67-
<SystemSettings />
68-
</AppContext.Provider>,
69-
);
70-
});
71-
72-
await userEvent.click(
73-
screen.getByTestId('checkbox-showNotificationsCountInTray'),
74-
);
75-
76-
expect(updateSetting).toHaveBeenCalledTimes(1);
77-
expect(updateSetting).toHaveBeenCalledWith(
78-
'showNotificationsCountInTray',
79-
false,
80-
);
81-
});
82-
8357
it('should toggle the showNotifications checkbox', async () => {
8458
await act(async () => {
8559
render(
@@ -197,27 +171,6 @@ describe('renderer/components/settings/SystemSettings.tsx', () => {
197171
});
198172
});
199173

200-
it('should toggle the useAlternateIdleIcon checkbox', async () => {
201-
await act(async () => {
202-
render(
203-
<AppContext.Provider
204-
value={{
205-
auth: mockAuth,
206-
settings: mockSettings,
207-
updateSetting,
208-
}}
209-
>
210-
<SystemSettings />
211-
</AppContext.Provider>,
212-
);
213-
});
214-
215-
await userEvent.click(screen.getByTestId('checkbox-useAlternateIdleIcon'));
216-
217-
expect(updateSetting).toHaveBeenCalledTimes(1);
218-
expect(updateSetting).toHaveBeenCalledWith('useAlternateIdleIcon', true);
219-
});
220-
221174
it('should toggle the openAtStartup checkbox', async () => {
222175
await act(async () => {
223176
render(

src/renderer/components/settings/SystemSettings.tsx

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -53,16 +53,6 @@ export const SystemSettings: FC = () => {
5353
}
5454
/>
5555

56-
<Checkbox
57-
checked={settings.showNotificationsCountInTray}
58-
label="Show notification count in tray"
59-
name="showNotificationsCountInTray"
60-
onChange={(evt) =>
61-
updateSetting('showNotificationsCountInTray', evt.target.checked)
62-
}
63-
visible={window.gitify.platform.isMacOS()}
64-
/>
65-
6656
<Checkbox
6757
checked={settings.showNotifications}
6858
label="Show system notifications"
@@ -141,27 +131,6 @@ export const SystemSettings: FC = () => {
141131
</ButtonGroup>
142132
</Stack>
143133

144-
<Checkbox
145-
checked={settings.useAlternateIdleIcon}
146-
label="Use alternate idle icon"
147-
name="useAlternateIdleIcon"
148-
onChange={(evt) =>
149-
updateSetting('useAlternateIdleIcon', evt.target.checked)
150-
}
151-
tooltip={
152-
<Stack direction="vertical" gap="condensed">
153-
<Text>
154-
Use a white {APPLICATION.NAME} logo (instead of the default
155-
black logo) when all notifications are read.
156-
</Text>
157-
<Text>
158-
This is particularly useful for devices which have a dark-themed
159-
menubar or taskbar.
160-
</Text>
161-
</Stack>
162-
}
163-
/>
164-
165134
<Checkbox
166135
checked={settings.openAtStartup}
167136
label="Open at startup"
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import { act, render, screen } from '@testing-library/react';
2+
import userEvent from '@testing-library/user-event';
3+
4+
import { mockAuth, mockSettings } from '../../__mocks__/state-mocks';
5+
import { AppContext } from '../../context/App';
6+
import { TraySettings } from './TraySettings';
7+
8+
describe('renderer/components/settings/TraySettings.tsx', () => {
9+
const updateSetting = jest.fn();
10+
11+
afterEach(() => {
12+
jest.clearAllMocks();
13+
});
14+
15+
it('should toggle the showNotificationsCountInTray checkbox', async () => {
16+
await act(async () => {
17+
render(
18+
<AppContext.Provider
19+
value={{
20+
auth: mockAuth,
21+
settings: mockSettings,
22+
updateSetting,
23+
}}
24+
>
25+
<TraySettings />
26+
</AppContext.Provider>,
27+
);
28+
});
29+
30+
await userEvent.click(
31+
screen.getByTestId('checkbox-showNotificationsCountInTray'),
32+
);
33+
34+
expect(updateSetting).toHaveBeenCalledTimes(1);
35+
expect(updateSetting).toHaveBeenCalledWith(
36+
'showNotificationsCountInTray',
37+
false,
38+
);
39+
});
40+
41+
it('should toggle the useUnreadActiveIcon checkbox', async () => {
42+
await act(async () => {
43+
render(
44+
<AppContext.Provider
45+
value={{
46+
auth: mockAuth,
47+
settings: mockSettings,
48+
updateSetting,
49+
}}
50+
>
51+
<TraySettings />
52+
</AppContext.Provider>,
53+
);
54+
});
55+
56+
await userEvent.click(screen.getByTestId('checkbox-useUnreadActiveIcon'));
57+
58+
expect(updateSetting).toHaveBeenCalledTimes(1);
59+
expect(updateSetting).toHaveBeenCalledWith('useUnreadActiveIcon', false);
60+
});
61+
62+
it('should toggle the useAlternateIdleIcon checkbox', async () => {
63+
await act(async () => {
64+
render(
65+
<AppContext.Provider
66+
value={{
67+
auth: mockAuth,
68+
settings: mockSettings,
69+
updateSetting,
70+
}}
71+
>
72+
<TraySettings />
73+
</AppContext.Provider>,
74+
);
75+
});
76+
77+
await userEvent.click(screen.getByTestId('checkbox-useAlternateIdleIcon'));
78+
79+
expect(updateSetting).toHaveBeenCalledTimes(1);
80+
expect(updateSetting).toHaveBeenCalledWith('useAlternateIdleIcon', true);
81+
});
82+
});

0 commit comments

Comments
 (0)