feat: shortcut to open window

This commit is contained in:
lin onetwo 2025-10-16 04:02:17 +08:00
parent 93045cfbca
commit 756082ab2a
8 changed files with 53 additions and 36 deletions

View file

@ -141,7 +141,7 @@ const commonInit = async (): Promise<void> => {
await workspaceViewService.initializeAllWorkspaceView();
const attachToMenubar = await preferenceService.get('attachToMenubar');
if (attachToMenubar) {
await windowService.enableMenubarWindow();
await windowService.openMenubarWindow();
}
ipcMain.emit('request-update-pause-notifications-info');

View file

@ -65,15 +65,15 @@ export class NativeService implements INativeService {
try {
const key = `${String(serviceName)}.${String(methodName)}`;
// Save to preferences
const preferenceService = container.get<IPreferenceService>('Preference');
const preferenceService = container.get<IPreferenceService>(serviceIdentifier.Preference);
const shortcuts = await this.getKeyboardShortcuts();
shortcuts[key] = shortcut;
await preferenceService.set('keyboardShortcuts', shortcuts);
// Register the shortcut
await registerShortcutByKey(key, shortcut);
logger.info('Successfully registered new keyboard shortcut', { key, shortcut });
logger.info('Successfully registered new keyboard shortcut', { key, shortcut, function: 'NativeService.registerKeyboardShortcut' });
} catch (error) {
logger.error('Failed to register keyboard shortcut', { error, serviceIdentifier: serviceName, methodName, shortcut });
logger.error('Failed to register keyboard shortcut', { error, serviceIdentifier: serviceName, methodName, shortcut, function: 'NativeService.registerKeyboardShortcut' });
throw error;
}
}
@ -84,7 +84,7 @@ export class NativeService implements INativeService {
const key = `${String(serviceName)}.${String(methodName)}`;
// Remove from preferences
const preferenceService = container.get<IPreferenceService>('Preference');
const preferenceService = container.get<IPreferenceService>(serviceIdentifier.Preference);
const shortcuts = await this.getKeyboardShortcuts();
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete shortcuts[key];

View file

@ -25,9 +25,12 @@ export function getShortcutCallback(key: string): (() => void) | undefined {
try {
// Get the service instance from container lazily
const service = container.get<Record<string, (...arguments_: unknown[]) => unknown>>(serviceSymbol);
logger.debug('Shortcut triggered', { key, service: serviceIdentifierName, method: methodName, function: 'getShortcutCallback' });
if (service && typeof service[methodName] === 'function') {
// Call the method with await if it's an async method
await service[methodName]();
} else {
logger.warn('Shortcut target method not found', { key, service: serviceIdentifierName, method: methodName, function: 'getShortcutCallback' });
}
} catch (error) {
logger.error(`Failed to execute shortcut callback for ${key}`, { error, function: 'getShortcutCallback' });
@ -57,9 +60,9 @@ export async function registerShortcutByKey(key: string, shortcut: string): Prom
const success = globalShortcut.register(shortcut, callback);
if (success) {
logger.info('Successfully registered shortcut', { key, shortcut });
logger.info('Successfully registered shortcut', { key, shortcut, function: 'registerShortcutByKey' });
} else {
logger.error('Failed to register shortcut', { key, shortcut });
logger.error('Failed to register shortcut', { key, shortcut, function: 'registerShortcutByKey' });
throw new Error(`Failed to register shortcut: ${shortcut}`);
}
}

View file

@ -92,9 +92,9 @@ export class Preference implements IPreferenceService {
switch (key) {
case 'attachToMenubar': {
if (value) {
await windowService.enableMenubarWindow();
await windowService.openMenubarWindow();
} else {
await windowService.disableMenubarWindow();
await windowService.closeMenubarWindow(true);
}
return;
}

View file

@ -344,11 +344,11 @@ export class Window implements IWindowService {
const isOpen = await this.isMenubarOpen();
if (isOpen) {
await this.disableMenubarWindow();
await this.closeMenubarWindow();
} else {
const attachToMenubar = await preferenceService.get('attachToMenubar');
if (attachToMenubar) {
await this.enableMenubarWindow();
await this.openMenubarWindow();
} else {
logger.warn('Cannot open menubar window: attachToMenubar preference is disabled', { function: 'toggleMenubarWindow' });
}
@ -358,43 +358,57 @@ export class Window implements IWindowService {
}
}
public async enableMenubarWindow(): Promise<void> {
public async openMenubarWindow(enableIt = true): Promise<void> {
try {
// Check if menubar is already enabled
if (this.mainWindowMenuBar !== undefined) {
logger.debug('Menubar is already enabled');
if (this.mainWindowMenuBar?.window !== undefined) {
logger.debug('Menubar is already enabled, bring it to front', { function: 'openMenubarWindow' });
const existingWin = this.mainWindowMenuBar.window;
if (existingWin !== undefined) {
if (existingWin.isMinimized?.()) {
existingWin.restore();
}
existingWin.show();
existingWin.focus();
}
return;
}
// Create menubar window
// Create menubar window (create and open when enableIt is true)
await this.open(WindowNames.menuBar);
logger.info('Menubar enabled', { function: 'enableMenubarWindow' });
if (enableIt) {
logger.debug('Menubar enabled', { function: 'openMenubarWindow' });
}
} catch (error) {
logger.error('Failed to enable menubar', { error, function: 'enableMenubarWindow' });
logger.error('Failed to open menubar', { error, function: 'openMenubarWindow' });
throw error;
}
}
public async disableMenubarWindow(): Promise<void> {
public async closeMenubarWindow(disableIt = false): Promise<void> {
try {
// Check if menubar exists
if (this.mainWindowMenuBar === undefined) {
logger.debug('Menubar is already disabled');
logger.debug('Menubar is already disabled', { function: 'closeMenubarWindow' });
return;
}
// Close menubar window and clean up
await this.close(WindowNames.menuBar);
// Clean up tray icon
// Clean up tray icon if disableIt is true (meaning fully disable), otherwise keep it
if (disableIt) {
if (this.mainWindowMenuBar.tray && !this.mainWindowMenuBar.tray.isDestroyed()) {
this.mainWindowMenuBar.tray.destroy();
}
this.mainWindowMenuBar = undefined;
logger.info('Menubar disabled successfully without restart');
logger.debug('Menubar disabled successfully without restart', { function: 'closeMenubarWindow' });
} else {
// Keep mainWindowMenuBar reference for quicker re-open
logger.debug('Menubar closed (kept enabled)', { function: 'closeMenubarWindow' });
}
} catch (error) {
logger.error('Failed to disable menubar', { error });
logger.error('Failed to close menubar', { error });
throw error;
}
}

View file

@ -57,10 +57,10 @@ export interface IWindowService {
stopFindInPage(close?: boolean, windowName?: WindowNames): Promise<void>;
toggleMenubarWindow(): Promise<void>;
updateWindowMeta<N extends WindowNames>(windowName: N, meta?: WindowMeta[N]): Promise<void>;
/** Enable menubar without restart - hot reload */
enableMenubarWindow(): Promise<void>;
/** Disable menubar without restart - hot reload */
disableMenubarWindow(): Promise<void>;
/** Open menubar window without restart - hot reload. enableIt=true means fully enable and open. */
openMenubarWindow(enableIt?: boolean): Promise<void>;
/** Close menubar window. disableIt=true means fully disable and cleanup tray. */
closeMenubarWindow(disableIt?: boolean): Promise<void>;
/** Update window properties without restart - hot reload */
updateWindowProperties(windowName: WindowNames, properties: { alwaysOnTop?: boolean }): Promise<void>;
}
@ -87,8 +87,8 @@ export const WindowServiceIPCDescriptor = {
stopFindInPage: ProxyPropertyType.Function,
toggleMenubarWindow: ProxyPropertyType.Function,
updateWindowMeta: ProxyPropertyType.Function,
enableMenubarWindow: ProxyPropertyType.Function,
disableMenubarWindow: ProxyPropertyType.Function,
openMenubarWindow: ProxyPropertyType.Function,
closeMenubarWindow: ProxyPropertyType.Function,
updateWindowProperties: ProxyPropertyType.Function,
},
};

View file

@ -129,12 +129,12 @@ export function TidGiMenubarWindow(props: Partial<ISectionProps>): React.JSX.Ele
<Box sx={{ p: 2 }}>
<KeyboardShortcutRegister
label={t('Preference.MenubarShortcutKey')}
value={preference.keyboardShortcuts?.['NativeService.toggleMenubarWindow'] || ''}
value={preference.keyboardShortcuts?.['Window.toggleMenubarWindow'] || ''}
onChange={async (value) => {
if (value && value.trim() !== '') {
await window.service.native.registerKeyboardShortcut<IWindowService>('NativeService', 'toggleMenubarWindow', value);
await window.service.native.registerKeyboardShortcut<IWindowService>('Window', 'toggleMenubarWindow', value);
} else {
await window.service.native.unregisterKeyboardShortcut<IWindowService>('NativeService', 'toggleMenubarWindow');
await window.service.native.unregisterKeyboardShortcut<IWindowService>('Window', 'toggleMenubarWindow');
}
}}
/>

@ -1 +1 @@
Subproject commit a7d3f4c939f6b939e2c63e2d2ece440e0367080a
Subproject commit 1ea80618e04b848572535a827b5a1fb663fdaa1d