Skip to content

Commit 1d38636

Browse files
committed
refactor: move resize listener to global
Signed-off-by: Adam Setch <[email protected]>
1 parent 5b51c39 commit 1d38636

File tree

6 files changed

+123
-96
lines changed

6 files changed

+123
-96
lines changed

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

Lines changed: 15 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
import { act, fireEvent, screen } from '@testing-library/react';
1+
import { act, screen } from '@testing-library/react';
22
import userEvent from '@testing-library/user-event';
33

44
import { renderWithAppContext } from '../../__helpers__/test-utils';
55
import { mockGitHubAppAccount } from '../../__mocks__/account-mocks';
6+
import * as zoom from '../../utils/zoom';
67
import { AppearanceSettings } from './AppearanceSettings';
78

89
describe('renderer/components/settings/AppearanceSettings.tsx', () => {
910
const updateSettingMock = jest.fn();
10-
const zoomTimeout = () => new Promise((r) => setTimeout(r, 300));
1111

1212
afterEach(() => {
1313
jest.clearAllMocks();
@@ -45,28 +45,12 @@ describe('renderer/components/settings/AppearanceSettings.tsx', () => {
4545
expect(updateSettingMock).toHaveBeenCalledWith('increaseContrast', true);
4646
});
4747

48-
it('should update the zoom value when using CMD + and CMD -', async () => {
49-
window.gitify.zoom.getLevel = jest.fn().mockReturnValue(-1);
50-
51-
await act(async () => {
52-
renderWithAppContext(<AppearanceSettings />, {
53-
updateSetting: updateSettingMock,
54-
});
55-
});
56-
57-
fireEvent(window, new Event('resize'));
58-
await zoomTimeout();
59-
60-
expect(updateSettingMock).toHaveBeenCalledTimes(1);
61-
expect(updateSettingMock).toHaveBeenCalledWith('zoomPercentage', 50);
62-
});
63-
6448
it('should update the zoom values when using the zoom buttons', async () => {
65-
window.gitify.zoom.getLevel = jest.fn().mockReturnValue(0);
66-
window.gitify.zoom.setLevel = jest.fn().mockImplementation((level) => {
67-
window.gitify.zoom.getLevel = jest.fn().mockReturnValue(level);
68-
fireEvent(window, new Event('resize'));
69-
});
49+
const zoomOutSpy = jest.spyOn(zoom, 'decreaseZoom').mockImplementation();
50+
const zoomInSpy = jest.spyOn(zoom, 'increaseZoom').mockImplementation();
51+
const zoomResetSpy = jest
52+
.spyOn(zoom, 'resetZoomLevel')
53+
.mockImplementation();
7054

7155
await act(async () => {
7256
renderWithAppContext(<AppearanceSettings />, {
@@ -75,55 +59,19 @@ describe('renderer/components/settings/AppearanceSettings.tsx', () => {
7559
});
7660

7761
// Zoom Out
78-
await act(async () => {
79-
await userEvent.click(screen.getByTestId('settings-zoom-out'));
80-
await zoomTimeout();
81-
82-
expect(updateSettingMock).toHaveBeenCalledTimes(1);
83-
expect(updateSettingMock).toHaveBeenNthCalledWith(
84-
1,
85-
'zoomPercentage',
86-
90,
87-
);
88-
});
62+
await userEvent.click(screen.getByTestId('settings-zoom-out'));
63+
expect(zoomOutSpy).toHaveBeenCalledTimes(1);
8964

90-
await act(async () => {
91-
await userEvent.click(screen.getByTestId('settings-zoom-out'));
92-
await zoomTimeout();
93-
94-
expect(updateSettingMock).toHaveBeenCalledTimes(2);
95-
expect(updateSettingMock).toHaveBeenNthCalledWith(
96-
2,
97-
'zoomPercentage',
98-
80,
99-
);
100-
});
65+
await userEvent.click(screen.getByTestId('settings-zoom-out'));
66+
expect(zoomOutSpy).toHaveBeenCalledTimes(2);
10167

10268
// Zoom In
103-
await act(async () => {
104-
await userEvent.click(screen.getByTestId('settings-zoom-in'));
105-
await zoomTimeout();
106-
107-
expect(updateSettingMock).toHaveBeenCalledTimes(3);
108-
expect(updateSettingMock).toHaveBeenNthCalledWith(
109-
3,
110-
'zoomPercentage',
111-
90,
112-
);
113-
});
69+
await userEvent.click(screen.getByTestId('settings-zoom-in'));
70+
expect(zoomInSpy).toHaveBeenCalledTimes(1);
11471

11572
// Zoom Reset
116-
await act(async () => {
117-
await userEvent.click(screen.getByTestId('settings-zoom-reset'));
118-
await zoomTimeout();
119-
120-
expect(updateSettingMock).toHaveBeenCalledTimes(4);
121-
expect(updateSettingMock).toHaveBeenNthCalledWith(
122-
4,
123-
'zoomPercentage',
124-
100,
125-
);
126-
});
73+
await userEvent.click(screen.getByTestId('settings-zoom-reset'));
74+
expect(zoomResetSpy).toHaveBeenCalledTimes(1);
12775
});
12876

12977
it('should toggle account header checkbox', async () => {

src/renderer/components/settings/AppearanceSettings.tsx

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { type FC, useContext, useState } from 'react';
1+
import { type FC, useContext } from 'react';
22

33
import {
44
PaintbrushIcon,
@@ -23,33 +23,16 @@ import {
2323
canIncreaseZoom,
2424
decreaseZoom,
2525
increaseZoom,
26+
resetZoomLevel,
2627
zoomLevelToPercentage,
2728
} from '../../utils/zoom';
2829
import { Checkbox } from '../fields/Checkbox';
2930
import { FieldLabel } from '../fields/FieldLabel';
3031
import { Title } from '../primitives/Title';
3132

32-
let timeout: NodeJS.Timeout;
33-
const DELAY = 200;
34-
3533
export const AppearanceSettings: FC = () => {
3634
const { auth, settings, updateSetting } = useContext(AppContext);
37-
const [zoomPercentage, setZoomPercentage] = useState(
38-
zoomLevelToPercentage(window.gitify.zoom.getLevel()),
39-
);
40-
41-
window.addEventListener('resize', () => {
42-
// clear the timeout
43-
clearTimeout(timeout);
44-
// start timing for event "completion"
45-
timeout = setTimeout(() => {
46-
const zoomPercentage = zoomLevelToPercentage(
47-
window.gitify.zoom.getLevel(),
48-
);
49-
setZoomPercentage(zoomPercentage);
50-
updateSetting('zoomPercentage', zoomPercentage);
51-
}, DELAY);
52-
});
35+
const zoomPercentage = zoomLevelToPercentage(window.gitify.zoom.getLevel());
5336

5437
return (
5538
<fieldset>
@@ -148,7 +131,7 @@ export const AppearanceSettings: FC = () => {
148131
aria-label="Reset zoom"
149132
data-testid="settings-zoom-reset"
150133
icon={SyncIcon}
151-
onClick={() => window.gitify.zoom.setLevel(0)}
134+
onClick={() => resetZoomLevel()}
152135
size="small"
153136
unsafeDisableTooltip={true}
154137
variant="danger"

src/renderer/context/App.test.tsx

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ describe('renderer/context/App.tsx', () => {
5555
const markNotificationsAsDoneMock = jest.fn();
5656
const unsubscribeNotificationMock = jest.fn();
5757

58+
const zoomTimeout = () => new Promise((r) => setTimeout(r, 300));
59+
5860
const saveStateSpy = jest
5961
.spyOn(storage, 'saveState')
6062
.mockImplementation(jest.fn());
@@ -327,4 +329,22 @@ describe('renderer/context/App.tsx', () => {
327329
});
328330
});
329331
});
332+
333+
describe('zoom listeners', () => {
334+
const updateSettingMock = jest.fn();
335+
336+
it('should update the zoom value when using CMD + and CMD -', async () => {
337+
window.gitify.zoom.getLevel = jest.fn().mockReturnValue(-1);
338+
339+
renderWithAppContext(<AppProvider>{null}</AppProvider>, {
340+
updateSetting: updateSettingMock,
341+
});
342+
343+
fireEvent(window, new Event('resize'));
344+
await zoomTimeout();
345+
346+
expect(updateSettingMock).toHaveBeenCalledTimes(1);
347+
expect(updateSettingMock).toHaveBeenCalledWith('zoomPercentage', 50);
348+
});
349+
});
330350
});

src/renderer/context/App.tsx

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ import {
5959
mapThemeModeToColorScheme,
6060
} from '../utils/theme';
6161
import { setTrayIconColorAndTitle } from '../utils/tray';
62-
import { zoomPercentageToLevel } from '../utils/zoom';
62+
import { zoomLevelToPercentage, zoomPercentageToLevel } from '../utils/zoom';
6363
import { defaultAuth, defaultFilters, defaultSettings } from './defaults';
6464

6565
export interface AppContextState {
@@ -172,13 +172,6 @@ export const AppProvider = ({ children }: { children: ReactNode }) => {
172172
}
173173
}, Constants.REFRESH_ACCOUNTS_INTERVAL_MS);
174174

175-
// Apply zoom level when settings change
176-
useEffect(() => {
177-
globalThis.gitify.zoom.setLevel(
178-
zoomPercentageToLevel(settings.zoomPercentage),
179-
);
180-
}, [settings.zoomPercentage]);
181-
182175
useEffect(() => {
183176
const colorMode = mapThemeModeToColorMode(settings.theme);
184177
const colorScheme = mapThemeModeToColorScheme(
@@ -285,6 +278,37 @@ export const AppProvider = ({ children }: { children: ReactNode }) => {
285278
[updateSetting, settings],
286279
);
287280

281+
// Global window resize listener to sync zoom percentage
282+
// biome-ignore lint/correctness/useExhaustiveDependencies: We want to update on settings.zoomPercentage changes
283+
useEffect(() => {
284+
// Set the zoom level when settings.zoomPercentage changes
285+
globalThis.gitify.zoom.setLevel(
286+
zoomPercentageToLevel(settings.zoomPercentage),
287+
);
288+
289+
// Sync zoom percentage in settings when window is resized
290+
let timeout: NodeJS.Timeout;
291+
const DELAY = 200;
292+
293+
const handleResize = () => {
294+
clearTimeout(timeout);
295+
timeout = setTimeout(() => {
296+
const zoomPercentage = zoomLevelToPercentage(
297+
globalThis.gitify.zoom.getLevel(),
298+
);
299+
300+
updateSetting('zoomPercentage', zoomPercentage);
301+
}, DELAY);
302+
};
303+
304+
window.addEventListener('resize', handleResize);
305+
306+
return () => {
307+
window.removeEventListener('resize', handleResize);
308+
clearTimeout(timeout);
309+
};
310+
}, [settings.zoomPercentage]);
311+
288312
const isLoggedIn = useMemo(() => {
289313
return hasAccounts(auth);
290314
}, [auth]);

src/renderer/utils/zoom.test.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,20 @@ import type { Percentage } from '../types';
22
import {
33
canDecreaseZoom,
44
canIncreaseZoom,
5+
decreaseZoom,
6+
increaseZoom,
7+
resetZoomLevel,
58
zoomLevelToPercentage,
69
zoomPercentageToLevel,
710
} from './zoom';
811

912
describe('renderer/utils/zoom.ts', () => {
13+
window.gitify.zoom.setLevel = jest.fn();
14+
15+
afterEach(() => {
16+
jest.clearAllMocks();
17+
});
18+
1019
it('should convert percentage to zoom level', () => {
1120
expect(zoomPercentageToLevel(100 as Percentage)).toBe(0);
1221
expect(zoomPercentageToLevel(50 as Percentage)).toBe(-1);
@@ -37,4 +46,38 @@ describe('renderer/utils/zoom.ts', () => {
3746
expect(canIncreaseZoom(120 as Percentage)).toBe(false);
3847
expect(canIncreaseZoom(150 as Percentage)).toBe(false);
3948
});
49+
50+
describe('decrease zoom', () => {
51+
it('can decrease zoom within allowed range', () => {
52+
decreaseZoom(100 as Percentage);
53+
54+
expect(window.gitify.zoom.setLevel).toHaveBeenCalledWith(-0.2);
55+
});
56+
57+
it('cannot decrease zoom outside of allowed range', () => {
58+
decreaseZoom(0 as Percentage);
59+
60+
expect(window.gitify.zoom.setLevel).not.toHaveBeenCalled();
61+
});
62+
});
63+
64+
describe('increase zoom', () => {
65+
it('can increase zoom within allowed range', () => {
66+
increaseZoom(100 as Percentage);
67+
68+
expect(window.gitify.zoom.setLevel).toHaveBeenCalledWith(0.2);
69+
});
70+
71+
it('cannot increase zoom outside of allowed range', () => {
72+
increaseZoom(120 as Percentage);
73+
74+
expect(window.gitify.zoom.setLevel).not.toHaveBeenCalled();
75+
});
76+
});
77+
78+
it('can reset zoom level', () => {
79+
resetZoomLevel();
80+
81+
expect(window.gitify.zoom.setLevel).toHaveBeenCalledWith(0);
82+
});
4083
});

src/renderer/utils/zoom.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,12 @@ export function increaseZoom(zoomPercentage: Percentage) {
7171
);
7272
}
7373
}
74+
75+
/**
76+
* Reset zoom level
77+
*/
78+
export function resetZoomLevel() {
79+
window.gitify.zoom.setLevel(
80+
zoomPercentageToLevel(RECOMMENDED_ZOOM_PERCENTAGE),
81+
);
82+
}

0 commit comments

Comments
 (0)