mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-05-12 07:09:40 +08:00
🐛 fix(window): 修复 Windows 最大化还原后文字变大
- 将缩放修正改为去抖检查,避免 focus/resize/visibilitychange 连续触发 - 最大化/还原改为显式切换窗口状态,减少重复 toggle 带来的抖动 - 补充 Windows 缩放修正相关工具测试
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
import { Layout, Button, ConfigProvider, theme, message, Modal, Spin, Slider, Progress, Switch, Input, InputNumber, Select, Segmented, Tooltip } from 'antd';
|
||||
import zhCN from 'antd/locale/zh_CN';
|
||||
import { PlusOutlined, ConsoleSqlOutlined, UploadOutlined, DownloadOutlined, CloudDownloadOutlined, BugOutlined, ToolOutlined, GlobalOutlined, InfoCircleOutlined, GithubOutlined, SkinOutlined, CheckOutlined, MinusOutlined, BorderOutlined, CloseOutlined, SettingOutlined, LinkOutlined, BgColorsOutlined, AppstoreOutlined, RobotOutlined, FolderOpenOutlined, HddOutlined, SafetyCertificateOutlined, SwitcherOutlined } from '@ant-design/icons';
|
||||
import { BrowserOpenURL, Environment, EventsOn, Quit, WindowFullscreen, WindowGetPosition, WindowGetSize, WindowIsFullscreen, WindowIsMaximised, WindowIsMinimised, WindowIsNormal, WindowMaximise, WindowMinimise, WindowSetPosition, WindowSetSize, WindowToggleMaximise, WindowUnfullscreen } from '../wailsjs/runtime';
|
||||
import { BrowserOpenURL, Environment, EventsOn, Quit, WindowFullscreen, WindowGetPosition, WindowGetSize, WindowIsFullscreen, WindowIsMaximised, WindowIsMinimised, WindowIsNormal, WindowMaximise, WindowMinimise, WindowSetPosition, WindowSetSize, WindowUnfullscreen, WindowUnmaximise } from '../wailsjs/runtime';
|
||||
import Sidebar from './components/Sidebar';
|
||||
import TabManager from './components/TabManager';
|
||||
import ConnectionModal from './components/ConnectionModal';
|
||||
@@ -69,7 +69,7 @@ import {
|
||||
isShortcutMatch,
|
||||
normalizeShortcutCombo,
|
||||
} from './utils/shortcuts';
|
||||
import { resolveTitleBarToggleIconKey, shouldToggleMaximisedWindowForScaleFix } from './utils/windowStateUi';
|
||||
import { resolveTitleBarToggleIconKey, resolveWindowsScaleCheckDelayMs, shouldApplyWindowsScaleFix, shouldToggleMaximisedWindowForScaleFix, type WindowsScaleCheckTrigger } from './utils/windowStateUi';
|
||||
import { resolveVisibleStartupWindowBounds } from './utils/windowRestoreBounds';
|
||||
import {
|
||||
SIDEBAR_UTILITY_ITEM_KEYS,
|
||||
@@ -630,6 +630,7 @@ function App() {
|
||||
let lastRatio = Number(window.devicePixelRatio) || 1;
|
||||
let lastFixAt = 0;
|
||||
let activationTimer: number | null = null;
|
||||
let resizeTimer: number | null = null;
|
||||
|
||||
const wait = (ms: number) => new Promise<void>((resolve) => window.setTimeout(resolve, ms));
|
||||
|
||||
@@ -669,12 +670,12 @@ function App() {
|
||||
}
|
||||
|
||||
try {
|
||||
WindowToggleMaximise();
|
||||
await wait(48);
|
||||
WindowToggleMaximise();
|
||||
await wait(64);
|
||||
WindowUnmaximise();
|
||||
await wait(96);
|
||||
WindowMaximise();
|
||||
await wait(96);
|
||||
} catch (e) {
|
||||
console.warn("Wails Window maximise toggle unavailable in fixWindowScaleIfNeeded", e);
|
||||
console.warn("Wails Window maximise restore unavailable in fixWindowScaleIfNeeded", e);
|
||||
}
|
||||
window.dispatchEvent(new Event('resize'));
|
||||
lastFixAt = Date.now();
|
||||
@@ -687,7 +688,7 @@ function App() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (reason !== 'ratio-change' && !hasViewportScaleDrift) {
|
||||
if (!shouldApplyWindowsScaleFix(reason, hasViewportScaleDrift)) {
|
||||
window.dispatchEvent(new Event('resize'));
|
||||
lastFixAt = Date.now();
|
||||
return;
|
||||
@@ -718,6 +719,24 @@ function App() {
|
||||
void fixWindowScaleIfNeeded('ratio-change');
|
||||
};
|
||||
|
||||
const scheduleDevicePixelRatioCheck = (trigger: WindowsScaleCheckTrigger) => {
|
||||
if (cancelled) return;
|
||||
const delayMs = resolveWindowsScaleCheckDelayMs(trigger);
|
||||
if (delayMs <= 0) {
|
||||
checkDevicePixelRatio();
|
||||
return;
|
||||
}
|
||||
|
||||
if (resizeTimer !== null) {
|
||||
window.clearTimeout(resizeTimer);
|
||||
}
|
||||
resizeTimer = window.setTimeout(() => {
|
||||
resizeTimer = null;
|
||||
if (cancelled) return;
|
||||
checkDevicePixelRatio();
|
||||
}, delayMs);
|
||||
};
|
||||
|
||||
const scheduleActivationFix = () => {
|
||||
if (cancelled) return;
|
||||
if (activationTimer !== null) {
|
||||
@@ -732,7 +751,7 @@ function App() {
|
||||
|
||||
const handleWindowFocus = () => {
|
||||
if (cancelled) return;
|
||||
checkDevicePixelRatio();
|
||||
scheduleDevicePixelRatioCheck('focus');
|
||||
scheduleActivationFix();
|
||||
};
|
||||
|
||||
@@ -741,18 +760,22 @@ function App() {
|
||||
if (document.visibilityState !== 'visible') {
|
||||
return;
|
||||
}
|
||||
checkDevicePixelRatio();
|
||||
scheduleDevicePixelRatioCheck('visibilitychange');
|
||||
scheduleActivationFix();
|
||||
};
|
||||
|
||||
const handlePageShow = () => {
|
||||
if (cancelled) return;
|
||||
checkDevicePixelRatio();
|
||||
scheduleDevicePixelRatioCheck('pageshow');
|
||||
scheduleActivationFix();
|
||||
};
|
||||
|
||||
const handleWindowResize = () => {
|
||||
scheduleDevicePixelRatioCheck('resize');
|
||||
};
|
||||
|
||||
const pollTimer = window.setInterval(checkDevicePixelRatio, 900);
|
||||
window.addEventListener('resize', checkDevicePixelRatio);
|
||||
window.addEventListener('resize', handleWindowResize);
|
||||
window.addEventListener('focus', handleWindowFocus);
|
||||
window.addEventListener('pageshow', handlePageShow);
|
||||
document.addEventListener('visibilitychange', handleVisibilityChange);
|
||||
@@ -762,8 +785,11 @@ function App() {
|
||||
if (activationTimer !== null) {
|
||||
window.clearTimeout(activationTimer);
|
||||
}
|
||||
if (resizeTimer !== null) {
|
||||
window.clearTimeout(resizeTimer);
|
||||
}
|
||||
window.clearInterval(pollTimer);
|
||||
window.removeEventListener('resize', checkDevicePixelRatio);
|
||||
window.removeEventListener('resize', handleWindowResize);
|
||||
window.removeEventListener('focus', handleWindowFocus);
|
||||
window.removeEventListener('pageshow', handlePageShow);
|
||||
document.removeEventListener('visibilitychange', handleVisibilityChange);
|
||||
@@ -2202,9 +2228,15 @@ function App() {
|
||||
void emitWindowDiagnostic('action:titlebar-toggle:after-fullscreen');
|
||||
return;
|
||||
}
|
||||
await WindowToggleMaximise();
|
||||
const isMaximised = await WindowIsMaximised().catch(() => false);
|
||||
if (isMaximised) {
|
||||
WindowUnmaximise();
|
||||
} else {
|
||||
WindowMaximise();
|
||||
}
|
||||
await new Promise((resolve) => window.setTimeout(resolve, 96));
|
||||
await syncWindowStateFromRuntime();
|
||||
void emitWindowDiagnostic('action:titlebar-toggle:after-toggle-maximise');
|
||||
void emitWindowDiagnostic('action:titlebar-toggle:after-set-maximise-state');
|
||||
} catch (_) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
@@ -1,12 +1,28 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { resolveTitleBarToggleIconKey, shouldToggleMaximisedWindowForScaleFix } from './windowStateUi';
|
||||
import {
|
||||
resolveTitleBarToggleIconKey,
|
||||
resolveWindowsScaleCheckDelayMs,
|
||||
shouldApplyWindowsScaleFix,
|
||||
shouldToggleMaximisedWindowForScaleFix,
|
||||
} from './windowStateUi';
|
||||
|
||||
describe('windowStateUi', () => {
|
||||
it('does not re-toggle a maximized window on activation when focus returns', () => {
|
||||
expect(shouldToggleMaximisedWindowForScaleFix('activation', true)).toBe(false);
|
||||
});
|
||||
|
||||
it('only applies the Windows scale fix on real ratio drift', () => {
|
||||
expect(shouldApplyWindowsScaleFix('activation', true)).toBe(false);
|
||||
expect(shouldApplyWindowsScaleFix('ratio-change', true)).toBe(true);
|
||||
});
|
||||
|
||||
it('debounces resize-triggered Windows scale checks until window transitions settle', () => {
|
||||
expect(resolveWindowsScaleCheckDelayMs('resize')).toBeGreaterThan(0);
|
||||
expect(resolveWindowsScaleCheckDelayMs('focus')).toBe(0);
|
||||
expect(resolveWindowsScaleCheckDelayMs('poll')).toBe(0);
|
||||
});
|
||||
|
||||
it('switches the titlebar toggle icon to restore when the window is maximized', () => {
|
||||
expect(resolveTitleBarToggleIconKey('maximized')).toBe('restore');
|
||||
});
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
export type WindowVisualState = 'normal' | 'maximized' | 'fullscreen';
|
||||
export type WindowScaleFixReason = 'activation' | 'ratio-change';
|
||||
export type WindowsScaleCheckTrigger = 'focus' | 'pageshow' | 'poll' | 'resize' | 'visibilitychange';
|
||||
export type TitleBarToggleIconKey = 'maximize' | 'restore';
|
||||
|
||||
export const shouldToggleMaximisedWindowForScaleFix = (
|
||||
export const shouldApplyWindowsScaleFix = (
|
||||
reason: WindowScaleFixReason,
|
||||
hasViewportScaleDrift: boolean,
|
||||
): boolean => reason === 'ratio-change' && hasViewportScaleDrift;
|
||||
|
||||
export const shouldToggleMaximisedWindowForScaleFix = shouldApplyWindowsScaleFix;
|
||||
|
||||
export const resolveWindowsScaleCheckDelayMs = (trigger: WindowsScaleCheckTrigger): number =>
|
||||
trigger === 'resize' ? 240 : 0;
|
||||
|
||||
export const resolveTitleBarToggleIconKey = (windowState: WindowVisualState): TitleBarToggleIconKey =>
|
||||
windowState === 'maximized' ? 'restore' : 'maximize';
|
||||
|
||||
Reference in New Issue
Block a user