diff --git a/apps/readest-app/src/__tests__/utils/window.test.ts b/apps/readest-app/src/__tests__/utils/window.test.ts index bf148582..65c0cce7 100644 --- a/apps/readest-app/src/__tests__/utils/window.test.ts +++ b/apps/readest-app/src/__tests__/utils/window.test.ts @@ -24,7 +24,7 @@ vi.mock('@/utils/event', () => ({ import { getCurrentWindow } from '@tauri-apps/api/window'; import { type as osType } from '@tauri-apps/plugin-os'; -import { tauriHandleOnCloseWindow } from '@/utils/window'; +import { tauriHandleOnCloseWindow, tauriHandleToggleFullScreen } from '@/utils/window'; type CloseHandler = (event: { preventDefault: () => void }) => Promise | void; @@ -113,3 +113,62 @@ describe('tauriHandleOnCloseWindow', () => { expect(win.destroy).toHaveBeenCalled(); }); }); + +function makeFullscreenWindow({ + isFullscreen, + isMaximized, +}: { + isFullscreen: boolean; + isMaximized: boolean; +}) { + return { + isFullscreen: vi.fn().mockResolvedValue(isFullscreen), + isMaximized: vi.fn().mockResolvedValue(isMaximized), + setFullscreen: vi.fn().mockResolvedValue(undefined), + unmaximize: vi.fn().mockResolvedValue(undefined), + toggleMaximize: vi.fn().mockResolvedValue(undefined), + innerSize: vi.fn().mockResolvedValue({ width: 800, height: 600 }), + setSize: vi.fn().mockResolvedValue(undefined), + }; +} + +describe('tauriHandleToggleFullScreen', () => { + test('enters fullscreen when the window is maximized (Phosh / Windows-maximized case)', async () => { + // On Phosh the window is always maximized, and on Windows users often run + // maximized. The fullscreen button must still enter fullscreen instead of + // just unmaximizing the window (issue #4034). + vi.mocked(osType).mockReturnValue('linux'); + const win = makeFullscreenWindow({ isFullscreen: false, isMaximized: true }); + vi.mocked(getCurrentWindow).mockReturnValue( + win as unknown as ReturnType, + ); + + await tauriHandleToggleFullScreen(); + + expect(win.setFullscreen).toHaveBeenCalledWith(true); + }); + + test('exits fullscreen when already fullscreen', async () => { + vi.mocked(osType).mockReturnValue('windows'); + const win = makeFullscreenWindow({ isFullscreen: true, isMaximized: false }); + vi.mocked(getCurrentWindow).mockReturnValue( + win as unknown as ReturnType, + ); + + await tauriHandleToggleFullScreen(); + + expect(win.setFullscreen).toHaveBeenCalledWith(false); + }); + + test('enters fullscreen when neither maximized nor fullscreen', async () => { + vi.mocked(osType).mockReturnValue('macos'); + const win = makeFullscreenWindow({ isFullscreen: false, isMaximized: false }); + vi.mocked(getCurrentWindow).mockReturnValue( + win as unknown as ReturnType, + ); + + await tauriHandleToggleFullScreen(); + + expect(win.setFullscreen).toHaveBeenCalledWith(true); + }); +}); diff --git a/apps/readest-app/src/utils/window.ts b/apps/readest-app/src/utils/window.ts index 206bf7d0..aa78168e 100644 --- a/apps/readest-app/src/utils/window.ts +++ b/apps/readest-app/src/utils/window.ts @@ -71,12 +71,11 @@ export const tauriHandleOnCloseWindow = async (callback: () => void) => { export const tauriHandleToggleFullScreen = async () => { const currentWindow = getCurrentWindow(); const isFullscreen = await currentWindow.isFullscreen(); - const isMaximized = await currentWindow.isMaximized(); - if (isMaximized) { - await currentWindow.unmaximize(); - } else { - await currentWindow.setFullscreen(!isFullscreen); - } + // Toggle fullscreen regardless of the maximized state. Previously a maximized + // window was only unmaximized here, so the fullscreen button did nothing when + // the window was maximized, which is always the case on mobile shells like + // Phosh and common on Windows (issue #4034). + await currentWindow.setFullscreen(!isFullscreen); if ((await osType()) === 'linux') { linuxWindowRestoreTransparentBg(); }