mirror of
https://github.com/tiddly-gittly/TidGi-Desktop.git
synced 2025-12-06 02:30:47 -08:00
feat: shortcut to open window
This commit is contained in:
parent
93045cfbca
commit
756082ab2a
8 changed files with 53 additions and 36 deletions
|
|
@ -141,7 +141,7 @@ const commonInit = async (): Promise<void> => {
|
||||||
await workspaceViewService.initializeAllWorkspaceView();
|
await workspaceViewService.initializeAllWorkspaceView();
|
||||||
const attachToMenubar = await preferenceService.get('attachToMenubar');
|
const attachToMenubar = await preferenceService.get('attachToMenubar');
|
||||||
if (attachToMenubar) {
|
if (attachToMenubar) {
|
||||||
await windowService.enableMenubarWindow();
|
await windowService.openMenubarWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
ipcMain.emit('request-update-pause-notifications-info');
|
ipcMain.emit('request-update-pause-notifications-info');
|
||||||
|
|
|
||||||
|
|
@ -65,15 +65,15 @@ export class NativeService implements INativeService {
|
||||||
try {
|
try {
|
||||||
const key = `${String(serviceName)}.${String(methodName)}`;
|
const key = `${String(serviceName)}.${String(methodName)}`;
|
||||||
// Save to preferences
|
// Save to preferences
|
||||||
const preferenceService = container.get<IPreferenceService>('Preference');
|
const preferenceService = container.get<IPreferenceService>(serviceIdentifier.Preference);
|
||||||
const shortcuts = await this.getKeyboardShortcuts();
|
const shortcuts = await this.getKeyboardShortcuts();
|
||||||
shortcuts[key] = shortcut;
|
shortcuts[key] = shortcut;
|
||||||
await preferenceService.set('keyboardShortcuts', shortcuts);
|
await preferenceService.set('keyboardShortcuts', shortcuts);
|
||||||
// Register the shortcut
|
// Register the shortcut
|
||||||
await registerShortcutByKey(key, 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) {
|
} 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;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -84,7 +84,7 @@ export class NativeService implements INativeService {
|
||||||
const key = `${String(serviceName)}.${String(methodName)}`;
|
const key = `${String(serviceName)}.${String(methodName)}`;
|
||||||
|
|
||||||
// Remove from preferences
|
// Remove from preferences
|
||||||
const preferenceService = container.get<IPreferenceService>('Preference');
|
const preferenceService = container.get<IPreferenceService>(serviceIdentifier.Preference);
|
||||||
const shortcuts = await this.getKeyboardShortcuts();
|
const shortcuts = await this.getKeyboardShortcuts();
|
||||||
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
||||||
delete shortcuts[key];
|
delete shortcuts[key];
|
||||||
|
|
|
||||||
|
|
@ -25,9 +25,12 @@ export function getShortcutCallback(key: string): (() => void) | undefined {
|
||||||
try {
|
try {
|
||||||
// Get the service instance from container lazily
|
// Get the service instance from container lazily
|
||||||
const service = container.get<Record<string, (...arguments_: unknown[]) => unknown>>(serviceSymbol);
|
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') {
|
if (service && typeof service[methodName] === 'function') {
|
||||||
// Call the method with await if it's an async method
|
// Call the method with await if it's an async method
|
||||||
await service[methodName]();
|
await service[methodName]();
|
||||||
|
} else {
|
||||||
|
logger.warn('Shortcut target method not found', { key, service: serviceIdentifierName, method: methodName, function: 'getShortcutCallback' });
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(`Failed to execute shortcut callback for ${key}`, { error, function: 'getShortcutCallback' });
|
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);
|
const success = globalShortcut.register(shortcut, callback);
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
logger.info('Successfully registered shortcut', { key, shortcut });
|
logger.info('Successfully registered shortcut', { key, shortcut, function: 'registerShortcutByKey' });
|
||||||
} else {
|
} 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}`);
|
throw new Error(`Failed to register shortcut: ${shortcut}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -92,9 +92,9 @@ export class Preference implements IPreferenceService {
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case 'attachToMenubar': {
|
case 'attachToMenubar': {
|
||||||
if (value) {
|
if (value) {
|
||||||
await windowService.enableMenubarWindow();
|
await windowService.openMenubarWindow();
|
||||||
} else {
|
} else {
|
||||||
await windowService.disableMenubarWindow();
|
await windowService.closeMenubarWindow(true);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -344,11 +344,11 @@ export class Window implements IWindowService {
|
||||||
|
|
||||||
const isOpen = await this.isMenubarOpen();
|
const isOpen = await this.isMenubarOpen();
|
||||||
if (isOpen) {
|
if (isOpen) {
|
||||||
await this.disableMenubarWindow();
|
await this.closeMenubarWindow();
|
||||||
} else {
|
} else {
|
||||||
const attachToMenubar = await preferenceService.get('attachToMenubar');
|
const attachToMenubar = await preferenceService.get('attachToMenubar');
|
||||||
if (attachToMenubar) {
|
if (attachToMenubar) {
|
||||||
await this.enableMenubarWindow();
|
await this.openMenubarWindow();
|
||||||
} else {
|
} else {
|
||||||
logger.warn('Cannot open menubar window: attachToMenubar preference is disabled', { function: 'toggleMenubarWindow' });
|
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 {
|
try {
|
||||||
// Check if menubar is already enabled
|
// Check if menubar is already enabled
|
||||||
if (this.mainWindowMenuBar !== undefined) {
|
if (this.mainWindowMenuBar?.window !== undefined) {
|
||||||
logger.debug('Menubar is already enabled');
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create menubar window
|
// Create menubar window (create and open when enableIt is true)
|
||||||
await this.open(WindowNames.menuBar);
|
await this.open(WindowNames.menuBar);
|
||||||
logger.info('Menubar enabled', { function: 'enableMenubarWindow' });
|
if (enableIt) {
|
||||||
|
logger.debug('Menubar enabled', { function: 'openMenubarWindow' });
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('Failed to enable menubar', { error, function: 'enableMenubarWindow' });
|
logger.error('Failed to open menubar', { error, function: 'openMenubarWindow' });
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async disableMenubarWindow(): Promise<void> {
|
public async closeMenubarWindow(disableIt = false): Promise<void> {
|
||||||
try {
|
try {
|
||||||
// Check if menubar exists
|
// Check if menubar exists
|
||||||
if (this.mainWindowMenuBar === undefined) {
|
if (this.mainWindowMenuBar === undefined) {
|
||||||
logger.debug('Menubar is already disabled');
|
logger.debug('Menubar is already disabled', { function: 'closeMenubarWindow' });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close menubar window and clean up
|
// Close menubar window and clean up
|
||||||
await this.close(WindowNames.menuBar);
|
await this.close(WindowNames.menuBar);
|
||||||
|
|
||||||
// Clean up tray icon
|
// Clean up tray icon if disableIt is true (meaning fully disable), otherwise keep it
|
||||||
if (this.mainWindowMenuBar.tray && !this.mainWindowMenuBar.tray.isDestroyed()) {
|
if (disableIt) {
|
||||||
this.mainWindowMenuBar.tray.destroy();
|
if (this.mainWindowMenuBar.tray && !this.mainWindowMenuBar.tray.isDestroyed()) {
|
||||||
|
this.mainWindowMenuBar.tray.destroy();
|
||||||
|
}
|
||||||
|
this.mainWindowMenuBar = undefined;
|
||||||
|
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' });
|
||||||
}
|
}
|
||||||
|
|
||||||
this.mainWindowMenuBar = undefined;
|
|
||||||
logger.info('Menubar disabled successfully without restart');
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('Failed to disable menubar', { error });
|
logger.error('Failed to close menubar', { error });
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,10 +57,10 @@ export interface IWindowService {
|
||||||
stopFindInPage(close?: boolean, windowName?: WindowNames): Promise<void>;
|
stopFindInPage(close?: boolean, windowName?: WindowNames): Promise<void>;
|
||||||
toggleMenubarWindow(): Promise<void>;
|
toggleMenubarWindow(): Promise<void>;
|
||||||
updateWindowMeta<N extends WindowNames>(windowName: N, meta?: WindowMeta[N]): Promise<void>;
|
updateWindowMeta<N extends WindowNames>(windowName: N, meta?: WindowMeta[N]): Promise<void>;
|
||||||
/** Enable menubar without restart - hot reload */
|
/** Open menubar window without restart - hot reload. enableIt=true means fully enable and open. */
|
||||||
enableMenubarWindow(): Promise<void>;
|
openMenubarWindow(enableIt?: boolean): Promise<void>;
|
||||||
/** Disable menubar without restart - hot reload */
|
/** Close menubar window. disableIt=true means fully disable and cleanup tray. */
|
||||||
disableMenubarWindow(): Promise<void>;
|
closeMenubarWindow(disableIt?: boolean): Promise<void>;
|
||||||
/** Update window properties without restart - hot reload */
|
/** Update window properties without restart - hot reload */
|
||||||
updateWindowProperties(windowName: WindowNames, properties: { alwaysOnTop?: boolean }): Promise<void>;
|
updateWindowProperties(windowName: WindowNames, properties: { alwaysOnTop?: boolean }): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
@ -87,8 +87,8 @@ export const WindowServiceIPCDescriptor = {
|
||||||
stopFindInPage: ProxyPropertyType.Function,
|
stopFindInPage: ProxyPropertyType.Function,
|
||||||
toggleMenubarWindow: ProxyPropertyType.Function,
|
toggleMenubarWindow: ProxyPropertyType.Function,
|
||||||
updateWindowMeta: ProxyPropertyType.Function,
|
updateWindowMeta: ProxyPropertyType.Function,
|
||||||
enableMenubarWindow: ProxyPropertyType.Function,
|
openMenubarWindow: ProxyPropertyType.Function,
|
||||||
disableMenubarWindow: ProxyPropertyType.Function,
|
closeMenubarWindow: ProxyPropertyType.Function,
|
||||||
updateWindowProperties: ProxyPropertyType.Function,
|
updateWindowProperties: ProxyPropertyType.Function,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -129,12 +129,12 @@ export function TidGiMenubarWindow(props: Partial<ISectionProps>): React.JSX.Ele
|
||||||
<Box sx={{ p: 2 }}>
|
<Box sx={{ p: 2 }}>
|
||||||
<KeyboardShortcutRegister
|
<KeyboardShortcutRegister
|
||||||
label={t('Preference.MenubarShortcutKey')}
|
label={t('Preference.MenubarShortcutKey')}
|
||||||
value={preference.keyboardShortcuts?.['NativeService.toggleMenubarWindow'] || ''}
|
value={preference.keyboardShortcuts?.['Window.toggleMenubarWindow'] || ''}
|
||||||
onChange={async (value) => {
|
onChange={async (value) => {
|
||||||
if (value && value.trim() !== '') {
|
if (value && value.trim() !== '') {
|
||||||
await window.service.native.registerKeyboardShortcut<IWindowService>('NativeService', 'toggleMenubarWindow', value);
|
await window.service.native.registerKeyboardShortcut<IWindowService>('Window', 'toggleMenubarWindow', value);
|
||||||
} else {
|
} 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
|
||||||
Loading…
Add table
Add a link
Reference in a new issue