From c5b190b5223a5d148933afffc83a5c4c05727699 Mon Sep 17 00:00:00 2001 From: jhyang0 Date: Sun, 13 Jul 2025 04:57:09 +0900 Subject: [PATCH] ui fix --- src/bridge/windowBridge.js | 153 +++++++- .../common/services/localProgressTracker.js | 45 +-- src/preload.js | 326 +++++++++++++++--- src/ui/app/ApiKeyHeader.js | 104 +++--- src/ui/app/HeaderController.js | 61 ++-- src/ui/app/MainHeader.js | 50 ++- src/ui/app/PermissionHeader.js | 28 +- src/ui/app/PickleGlassApp.js | 16 +- src/ui/app/content.html | 18 +- src/ui/app/header.html | 2 +- src/ui/ask/AskView.js | 50 ++- src/ui/listen/ListenView.js | 10 +- src/ui/listen/audioCore/listenCapture.js | 43 ++- src/ui/listen/audioCore/renderer.js | 3 +- src/ui/listen/stt/SttView.js | 10 +- src/ui/listen/summary/SummaryView.js | 16 +- src/ui/settings/SettingsView.js | 192 +++++------ src/ui/settings/ShortCutSettingsView.js | 21 +- src/window/windowManager.js | 185 ++-------- 19 files changed, 749 insertions(+), 584 deletions(-) diff --git a/src/bridge/windowBridge.js b/src/bridge/windowBridge.js index 2b0ae06..825e1f4 100644 --- a/src/bridge/windowBridge.js +++ b/src/bridge/windowBridge.js @@ -1,10 +1,155 @@ // src/bridge/windowBridge.js -const { ipcMain, BrowserWindow } = require('electron'); -const { windowPool, settingsHideTimer, app, shell } = require('../window/windowManager'); // 필요 변수 require +const { ipcMain, BrowserWindow, globalShortcut } = require('electron'); module.exports = { - // Renderer로부터의 요청을 수신 - initialize() { + // windowManager에서 필요한 변수들을 매개변수로 받도록 수정 + initialize(windowPool, app, shell, getCurrentDisplay, createFeatureWindows, movementManager, getContentProtectionStatus, setContentProtection, updateLayout) { + let settingsHideTimer = null; + + // 기존 + ipcMain.on('window:hide', (e) => BrowserWindow.fromWebContents(e.sender)?.hide()); + + // windowManager 관련 추가 + ipcMain.handle('toggle-content-protection', () => { + // windowManager의 toggle-content-protection 로직 + const newStatus = !getContentProtectionStatus(); + setContentProtection(newStatus); + return newStatus; + }); + + + ipcMain.handle('resize-header-window', (event, { width, height }) => { + const header = windowPool.get('header'); + if (header) { + console.log(`[WindowBridge] Resize request: ${width}x${height}`); + + // Prevent resizing during animations or if already at target size + if (movementManager && movementManager.isAnimating) { + console.log('[WindowBridge] Skipping resize during animation'); + return { success: false, error: 'Cannot resize during animation' }; + } + + const currentBounds = header.getBounds(); + console.log(`[WindowBridge] Current bounds: ${currentBounds.width}x${currentBounds.height} at (${currentBounds.x}, ${currentBounds.y})`); + + // Skip if already at target size to prevent unnecessary operations + if (currentBounds.width === width && currentBounds.height === height) { + console.log('[WindowBridge] Already at target size, skipping resize'); + return { success: true }; + } + + const wasResizable = header.isResizable(); + if (!wasResizable) { + header.setResizable(true); + } + + // Calculate the center point of the current window + const centerX = currentBounds.x + currentBounds.width / 2; + // Calculate new X position to keep the window centered + const newX = Math.round(centerX - width / 2); + + // Get the current display to ensure we stay within bounds + const display = getCurrentDisplay(header); + const { x: workAreaX, width: workAreaWidth } = display.workArea; + + // Clamp the new position to stay within display bounds + const clampedX = Math.max(workAreaX, Math.min(workAreaX + workAreaWidth - width, newX)); + + header.setBounds({ x: clampedX, y: currentBounds.y, width, height }); + + if (!wasResizable) { + header.setResizable(false); + } + + // Update layout after resize + if (updateLayout) { + updateLayout(); + } + + return { success: true }; + } + return { success: false, error: 'Header window not found' }; + }); + + ipcMain.handle('get-content-protection-status', () => { + return getContentProtectionStatus(); + }); + + ipcMain.handle('open-shortcut-editor', () => { + // open-shortcut-editor 로직 + const header = windowPool.get('header'); + if (!header) return; + globalShortcut.unregisterAll(); + createFeatureWindows(header, 'shortcut-settings'); + }); + + + // 추가: show-settings-window + ipcMain.on('show-settings-window', (event, bounds) => { + if (!bounds) return; + const win = windowPool.get('settings'); + if (win && !win.isDestroyed()) { + if (settingsHideTimer) { + clearTimeout(settingsHideTimer); + settingsHideTimer = null; + } + // 위치 조정 로직 + const header = windowPool.get('header'); + const headerBounds = header?.getBounds() ?? { x: 0, y: 0 }; + const settingsBounds = win.getBounds(); + const disp = getCurrentDisplay(header); + const { x: waX, y: waY, width: waW, height: waH } = disp.workArea; + let x = Math.round(headerBounds.x + (bounds?.x ?? 0) + (bounds?.width ?? 0) / 2 - settingsBounds.width / 2); + let y = Math.round(headerBounds.y + (bounds?.y ?? 0) + (bounds?.height ?? 0) + 31); + x = Math.max(waX + 10, Math.min(waX + waW - settingsBounds.width - 10, x)); + y = Math.max(waY + 10, Math.min(waY + waH - settingsBounds.height - 10, y)); + win.setBounds({ x, y }); + win.__lockedByButton = true; + win.show(); + win.moveTop(); + win.setAlwaysOnTop(true); + } + }); + + ipcMain.on('hide-settings-window', (event) => { + const window = windowPool.get("settings"); + if (window && !window.isDestroyed()) { + if (settingsHideTimer) { + clearTimeout(settingsHideTimer); + } + settingsHideTimer = setTimeout(() => { + if (window && !window.isDestroyed()) { + window.setAlwaysOnTop(false); + window.hide(); + } + settingsHideTimer = null; + }, 200); + + window.__lockedByButton = false; + } + }); + + ipcMain.on('cancel-hide-settings-window', (event) => { + if (settingsHideTimer) { + clearTimeout(settingsHideTimer); + settingsHideTimer = null; + } + }); + + // 로그인 페이지 열기 + ipcMain.handle('open-login-page', () => { + const webUrl = process.env.pickleglass_WEB_URL || 'http://localhost:3000'; + const personalizeUrl = `${webUrl}/personalize?desktop=true`; + shell.openExternal(personalizeUrl); + console.log('Opening personalization page:', personalizeUrl); + }); + + // 윈도우 이동 + ipcMain.handle('move-window-step', (event, direction) => { + if (movementManager) { + movementManager.moveStep(direction); + } + }); }, // Renderer로 상태를 전송 diff --git a/src/features/common/services/localProgressTracker.js b/src/features/common/services/localProgressTracker.js index 48f5fcb..454b431 100644 --- a/src/features/common/services/localProgressTracker.js +++ b/src/features/common/services/localProgressTracker.js @@ -2,10 +2,10 @@ export class LocalProgressTracker { constructor(serviceName) { this.serviceName = serviceName; this.activeOperations = new Map(); // operationId -> { controller, onProgress } - this.ipcRenderer = window.require?.('electron')?.ipcRenderer; - if (!this.ipcRenderer) { - throw new Error(`${serviceName} requires Electron environment`); + // Check if we're in renderer process with window.api available + if (!window.api) { + throw new Error(`${serviceName} requires Electron environment with contextBridge`); } this.globalProgressHandler = (event, data) => { @@ -15,14 +15,14 @@ export class LocalProgressTracker { } }; - const progressEvents = { - 'ollama': 'ollama:pull-progress', - 'whisper': 'whisper:download-progress' - }; + // Set up progress listeners based on service name + if (serviceName.toLowerCase() === 'ollama') { + window.api.settingsView.onOllamaPullProgress(this.globalProgressHandler); + } else if (serviceName.toLowerCase() === 'whisper') { + window.api.settingsView.onWhisperDownloadProgress(this.globalProgressHandler); + } - const eventName = progressEvents[serviceName.toLowerCase()] || `${serviceName}:progress`; - this.progressEvent = eventName; - this.ipcRenderer.on(eventName, this.globalProgressHandler); + this.progressEvent = serviceName.toLowerCase(); } async trackOperation(operationId, operationType, onProgress) { @@ -35,15 +35,16 @@ export class LocalProgressTracker { this.activeOperations.set(operationId, operation); try { - const ipcChannels = { - 'ollama': { install: 'ollama:pull-model' }, - 'whisper': { download: 'whisper:download-model' } - }; + let result; - const channel = ipcChannels[this.serviceName.toLowerCase()]?.[operationType] || - `${this.serviceName}:${operationType}`; - - const result = await this.ipcRenderer.invoke(channel, operationId); + // Use appropriate API call based on service and operation + if (this.serviceName.toLowerCase() === 'ollama' && operationType === 'install') { + result = await window.api.settingsView.pullOllamaModel(operationId); + } else if (this.serviceName.toLowerCase() === 'whisper' && operationType === 'download') { + result = await window.api.settingsView.downloadWhisperModel(operationId); + } else { + throw new Error(`Unsupported operation: ${this.serviceName}:${operationType}`); + } if (!result.success) { throw new Error(result.error || `${operationType} failed`); @@ -93,8 +94,12 @@ export class LocalProgressTracker { destroy() { this.cancelAllOperations(); - if (this.ipcRenderer) { - this.ipcRenderer.removeListener(this.progressEvent, this.globalProgressHandler); + + // Remove progress listeners based on service name + if (this.progressEvent === 'ollama') { + window.api.settingsView.removeOnOllamaPullProgress(this.globalProgressHandler); + } else if (this.progressEvent === 'whisper') { + window.api.settingsView.removeOnWhisperDownloadProgress(this.globalProgressHandler); } } } diff --git a/src/preload.js b/src/preload.js index 80dd79d..02267b5 100644 --- a/src/preload.js +++ b/src/preload.js @@ -2,72 +2,231 @@ const { contextBridge, ipcRenderer } = require('electron'); contextBridge.exposeInMainWorld('api', { - feature: { - // 기존 ask 관련 유지 - submitAsk: (query) => ipcRenderer.invoke('feature:ask', query), - onAskProgress: (callback) => ipcRenderer.on('feature:ask:progress', (e, p) => callback(p)), - - settings: { - // invoke methods - getCurrentUser: () => ipcRenderer.invoke('get-current-user'), - getProviderConfig: () => ipcRenderer.invoke('model:get-provider-config'), - getAllKeys: () => ipcRenderer.invoke('model:get-all-keys'), - getAvailableModels: (type) => ipcRenderer.invoke('model:get-available-models', type), - getSelectedModels: () => ipcRenderer.invoke('model:get-selected-models'), - getPresets: () => ipcRenderer.invoke('settings:getPresets'), - getContentProtectionStatus: () => ipcRenderer.invoke('get-content-protection-status'), - getCurrentShortcuts: () => ipcRenderer.invoke('get-current-shortcuts'), - getOllamaStatus: () => ipcRenderer.invoke('ollama:get-status'), - getWhisperInstalledModels: () => ipcRenderer.invoke('whisper:get-installed-models'), - ollamaEnsureReady: () => ipcRenderer.invoke('ollama:ensure-ready'), - validateKey: (data) => ipcRenderer.invoke('model:validate-key', data), - getAutoUpdate: () => ipcRenderer.invoke('settings:get-auto-update'), - setAutoUpdate: (isEnabled) => ipcRenderer.invoke('settings:set-auto-update', isEnabled), - removeApiKey: (provider) => ipcRenderer.invoke('model:remove-api-key', provider), - setSelectedModel: (data) => ipcRenderer.invoke('model:set-selected-model', data), - downloadWhisperModel: (modelId) => ipcRenderer.invoke('whisper:download-model', modelId), - openLoginPage: () => ipcRenderer.invoke('open-login-page'), - toggleContentProtection: () => ipcRenderer.invoke('toggle-content-protection'), - openShortcutEditor: () => ipcRenderer.invoke('open-shortcut-editor'), + // Platform information for renderer processes + platform: { + isLinux: process.platform === 'linux', + isMacOS: process.platform === 'darwin', + isWindows: process.platform === 'win32', + platform: process.platform + }, + + // Common utilities used across multiple components + common: { + // User & Auth + getCurrentUser: () => ipcRenderer.invoke('get-current-user'), + startFirebaseAuth: () => ipcRenderer.invoke('start-firebase-auth'), + firebaseLogout: () => ipcRenderer.invoke('firebase-logout'), + + // App Control quitApplication: () => ipcRenderer.invoke('quit-application'), - firebaseLogout: () => ipcRenderer.invoke('firebase-logout'), - ollamaShutdown: (graceful) => ipcRenderer.invoke('ollama:shutdown', graceful), - startFirebaseAuth: () => ipcRenderer.invoke('start-firebase-auth'), - // on methods (listeners) + // User state listener (used by multiple components) onUserStateChanged: (callback) => ipcRenderer.on('user-state-changed', callback), removeOnUserStateChanged: (callback) => ipcRenderer.removeListener('user-state-changed', callback), - onSettingsUpdated: (callback) => ipcRenderer.on('settings-updated', callback), - removeOnSettingsUpdated: (callback) => ipcRenderer.removeListener('settings-updated', callback), - onPresetsUpdated: (callback) => ipcRenderer.on('presets-updated', callback), - removeOnPresetsUpdated: (callback) => ipcRenderer.removeListener('presets-updated', callback), - onShortcutsUpdated: (callback) => ipcRenderer.on('shortcuts-updated', callback), - removeOnShortcutsUpdated: (callback) => ipcRenderer.removeListener('shortcuts-updated', callback), - onWhisperDownloadProgress: (callback) => ipcRenderer.on('whisper:download-progress', callback), - removeOnWhisperDownloadProgress: (callback) => ipcRenderer.removeListener('whisper:download-progress', callback), + }, - // send methods - cancelHideSettingsWindow: () => ipcRenderer.send('cancel-hide-settings-window'), - hideSettingsWindow: () => ipcRenderer.send('hide-settings-window') + // UI Component specific namespaces + // src/ui/app/ApiKeyHeader.js + apiKeyHeader: { + // Model & Provider Management + getProviderConfig: () => ipcRenderer.invoke('model:get-provider-config'), + getOllamaStatus: () => ipcRenderer.invoke('ollama:get-status'), + getModelSuggestions: () => ipcRenderer.invoke('ollama:get-model-suggestions'), + ensureOllamaReady: () => ipcRenderer.invoke('ollama:ensure-ready'), + installOllama: () => ipcRenderer.invoke('ollama:install'), + startOllamaService: () => ipcRenderer.invoke('ollama:start-service'), + pullOllamaModel: (modelName) => ipcRenderer.invoke('ollama:pull-model', modelName), + downloadWhisperModel: (modelId) => ipcRenderer.invoke('whisper:download-model', modelId), + validateKey: (data) => ipcRenderer.invoke('model:validate-key', data), + setSelectedModel: (data) => ipcRenderer.invoke('model:set-selected-model', data), + areProvidersConfigured: () => ipcRenderer.invoke('model:are-providers-configured'), + + // Window Management + getHeaderPosition: () => ipcRenderer.invoke('get-header-position'), + moveHeaderTo: (x, y) => ipcRenderer.invoke('move-header-to', x, y), + + // Listeners + onOllamaInstallProgress: (callback) => ipcRenderer.on('ollama:install-progress', callback), + removeOnOllamaInstallProgress: (callback) => ipcRenderer.removeListener('ollama:install-progress', callback), + onceOllamaInstallComplete: (callback) => ipcRenderer.once('ollama:install-complete', callback), + removeOnceOllamaInstallComplete: (callback) => ipcRenderer.removeListener('ollama:install-complete', callback), + onOllamaPullProgress: (callback) => ipcRenderer.on('ollama:pull-progress', callback), + removeOnOllamaPullProgress: (callback) => ipcRenderer.removeListener('ollama:pull-progress', callback), + onWhisperDownloadProgress: (callback) => ipcRenderer.on('whisper:download-progress', callback), + removeOnWhisperDownloadProgress: (callback) => ipcRenderer.removeListener('whisper:download-progress', callback), + + // Remove all listeners (for cleanup) + removeAllListeners: () => { + ipcRenderer.removeAllListeners('whisper:download-progress'); + ipcRenderer.removeAllListeners('ollama:install-progress'); + ipcRenderer.removeAllListeners('ollama:pull-progress'); + ipcRenderer.removeAllListeners('ollama:install-complete'); } }, - // 기존 window 유지 - window: { - // 기존 - hide: () => ipcRenderer.send('window:hide'), - onFocusChange: (callback) => ipcRenderer.on('window:focus-change', (e, f) => callback(f)), - // 추가 + // src/ui/app/HeaderController.js + headerController: { + // State Management + sendHeaderStateChanged: (state) => ipcRenderer.send('header-state-changed', state), + + // Window Management + resizeHeaderWindow: (dimensions) => ipcRenderer.invoke('resize-header-window', dimensions), + + // Permissions + checkSystemPermissions: () => ipcRenderer.invoke('check-system-permissions'), + checkPermissionsCompleted: () => ipcRenderer.invoke('check-permissions-completed'), + + // Listeners + onUserStateChanged: (callback) => ipcRenderer.on('user-state-changed', callback), + removeOnUserStateChanged: (callback) => ipcRenderer.removeListener('user-state-changed', callback), + onAuthFailed: (callback) => ipcRenderer.on('auth-failed', callback), + removeOnAuthFailed: (callback) => ipcRenderer.removeListener('auth-failed', callback), + onForceShowApiKeyHeader: (callback) => ipcRenderer.on('force-show-apikey-header', callback), + removeOnForceShowApiKeyHeader: (callback) => ipcRenderer.removeListener('force-show-apikey-header', callback) + }, + + // src/ui/app/MainHeader.js + mainHeader: { + // Window Management + getHeaderPosition: () => ipcRenderer.invoke('get-header-position'), + moveHeaderTo: (x, y) => ipcRenderer.invoke('move-header-to', x, y), + sendHeaderAnimationFinished: (state) => ipcRenderer.send('header-animation-finished', state), + + // Settings Window Management + cancelHideSettingsWindow: () => ipcRenderer.send('cancel-hide-settings-window'), showSettingsWindow: (bounds) => ipcRenderer.send('show-settings-window', bounds), hideSettingsWindow: () => ipcRenderer.send('hide-settings-window'), - cancelHideSettingsWindow: () => ipcRenderer.send('cancel-hide-settings-window'), - moveWindowStep: (direction) => ipcRenderer.invoke('move-window-step', direction), + + // Generic invoke (for dynamic channel names) + invoke: (channel, ...args) => ipcRenderer.invoke(channel, ...args), + + // Listeners + onSessionStateText: (callback) => ipcRenderer.on('session-state-text', callback), + removeOnSessionStateText: (callback) => ipcRenderer.removeListener('session-state-text', callback), + onShortcutsUpdated: (callback) => ipcRenderer.on('shortcuts-updated', callback), + removeOnShortcutsUpdated: (callback) => ipcRenderer.removeListener('shortcuts-updated', callback) + }, + + // src/ui/app/PermissionHeader.js + permissionHeader: { + // Permission Management + checkSystemPermissions: () => ipcRenderer.invoke('check-system-permissions'), + requestMicrophonePermission: () => ipcRenderer.invoke('request-microphone-permission'), + openSystemPreferences: (preference) => ipcRenderer.invoke('open-system-preferences', preference), + markPermissionsCompleted: () => ipcRenderer.invoke('mark-permissions-completed') + }, + + // src/ui/app/PickleGlassApp.js + pickleGlassApp: { + // Listeners + onClickThroughToggled: (callback) => ipcRenderer.on('click-through-toggled', callback), + removeOnClickThroughToggled: (callback) => ipcRenderer.removeListener('click-through-toggled', callback), + removeAllClickThroughListeners: () => ipcRenderer.removeAllListeners('click-through-toggled') + }, + + // src/ui/ask/AskView.js + askView: { + // Window Management + closeAskWindow: () => ipcRenderer.invoke('ask:closeAskWindow'), + adjustWindowHeight: (height) => ipcRenderer.invoke('adjust-window-height', height), + + // Message Handling + sendMessage: (text) => ipcRenderer.invoke('ask:sendMessage', text), + + // Listeners + onSendQuestionToRenderer: (callback) => ipcRenderer.on('ask:sendQuestionToRenderer', callback), + removeOnSendQuestionToRenderer: (callback) => ipcRenderer.removeListener('ask:sendQuestionToRenderer', callback), + onHideTextInput: (callback) => ipcRenderer.on('hide-text-input', callback), + removeOnHideTextInput: (callback) => ipcRenderer.removeListener('hide-text-input', callback), + onShowTextInput: (callback) => ipcRenderer.on('ask:showTextInput', callback), + removeOnShowTextInput: (callback) => ipcRenderer.removeListener('ask:showTextInput', callback), + onResponseChunk: (callback) => ipcRenderer.on('ask-response-chunk', callback), + removeOnResponseChunk: (callback) => ipcRenderer.removeListener('ask-response-chunk', callback), + onResponseStreamEnd: (callback) => ipcRenderer.on('ask-response-stream-end', callback), + removeOnResponseStreamEnd: (callback) => ipcRenderer.removeListener('ask-response-stream-end', callback), + onScrollResponseUp: (callback) => ipcRenderer.on('scroll-response-up', callback), + removeOnScrollResponseUp: (callback) => ipcRenderer.removeListener('scroll-response-up', callback), + onScrollResponseDown: (callback) => ipcRenderer.on('scroll-response-down', callback), + removeOnScrollResponseDown: (callback) => ipcRenderer.removeListener('scroll-response-down', callback) + }, + + // src/ui/listen/ListenView.js + listenView: { + // Window Management + adjustWindowHeight: (height) => ipcRenderer.invoke('adjust-window-height', height), + + // Listeners + onSessionStateChanged: (callback) => ipcRenderer.on('session-state-changed', callback), + removeOnSessionStateChanged: (callback) => ipcRenderer.removeListener('session-state-changed', callback) + }, + + // src/ui/listen/stt/SttView.js + sttView: { + // Listeners + onSttUpdate: (callback) => ipcRenderer.on('stt-update', callback), + removeOnSttUpdate: (callback) => ipcRenderer.removeListener('stt-update', callback) + }, + + // src/ui/listen/summary/SummaryView.js + summaryView: { + // Message Handling + sendQuestionToMain: (text) => ipcRenderer.invoke('ask:sendQuestionToMain', text), + + // Listeners + onSummaryUpdate: (callback) => ipcRenderer.on('summary-update', callback), + removeOnSummaryUpdate: (callback) => ipcRenderer.removeListener('summary-update', callback), + removeAllSummaryUpdateListeners: () => ipcRenderer.removeAllListeners('summary-update') + }, + + // src/ui/settings/SettingsView.js + settingsView: { + // User & Auth + getCurrentUser: () => ipcRenderer.invoke('get-current-user'), openLoginPage: () => ipcRenderer.invoke('open-login-page'), firebaseLogout: () => ipcRenderer.invoke('firebase-logout'), - ollamaShutdown: (graceful) => ipcRenderer.invoke('ollama:shutdown', graceful), startFirebaseAuth: () => ipcRenderer.invoke('start-firebase-auth'), - // on methods (listeners) + // Model & Provider Management + getModelSettings: () => ipcRenderer.invoke('settings:get-model-settings'), // Facade call + getProviderConfig: () => ipcRenderer.invoke('model:get-provider-config'), + getAllKeys: () => ipcRenderer.invoke('model:get-all-keys'), + getAvailableModels: (type) => ipcRenderer.invoke('model:get-available-models', type), + getSelectedModels: () => ipcRenderer.invoke('model:get-selected-models'), + validateKey: (data) => ipcRenderer.invoke('model:validate-key', data), + saveApiKey: (key) => ipcRenderer.invoke('model:save-api-key', key), + removeApiKey: (provider) => ipcRenderer.invoke('model:remove-api-key', provider), + setSelectedModel: (data) => ipcRenderer.invoke('model:set-selected-model', data), + + // Ollama Management + getOllamaStatus: () => ipcRenderer.invoke('ollama:get-status'), + ensureOllamaReady: () => ipcRenderer.invoke('ollama:ensure-ready'), + shutdownOllama: (graceful) => ipcRenderer.invoke('ollama:shutdown', graceful), + + // Whisper Management + getWhisperInstalledModels: () => ipcRenderer.invoke('whisper:get-installed-models'), + downloadWhisperModel: (modelId) => ipcRenderer.invoke('whisper:download-model', modelId), + + // Settings Management + getPresets: () => ipcRenderer.invoke('settings:getPresets'), + getAutoUpdate: () => ipcRenderer.invoke('settings:get-auto-update'), + setAutoUpdate: (isEnabled) => ipcRenderer.invoke('settings:set-auto-update', isEnabled), + getContentProtectionStatus: () => ipcRenderer.invoke('get-content-protection-status'), + toggleContentProtection: () => ipcRenderer.invoke('toggle-content-protection'), + getCurrentShortcuts: () => ipcRenderer.invoke('get-current-shortcuts'), + openShortcutEditor: () => ipcRenderer.invoke('open-shortcut-editor'), + + // Window Management + moveWindowStep: (direction) => ipcRenderer.invoke('move-window-step', direction), + cancelHideSettingsWindow: () => ipcRenderer.send('cancel-hide-settings-window'), + hideSettingsWindow: () => ipcRenderer.send('hide-settings-window'), + + // App Control + quitApplication: () => ipcRenderer.invoke('quit-application'), + + // Progress Tracking + pullOllamaModel: (modelName) => ipcRenderer.invoke('ollama:pull-model', modelName), + + // Listeners onUserStateChanged: (callback) => ipcRenderer.on('user-state-changed', callback), removeOnUserStateChanged: (callback) => ipcRenderer.removeListener('user-state-changed', callback), onSettingsUpdated: (callback) => ipcRenderer.on('settings-updated', callback), @@ -78,9 +237,66 @@ contextBridge.exposeInMainWorld('api', { removeOnShortcutsUpdated: (callback) => ipcRenderer.removeListener('shortcuts-updated', callback), onWhisperDownloadProgress: (callback) => ipcRenderer.on('whisper:download-progress', callback), removeOnWhisperDownloadProgress: (callback) => ipcRenderer.removeListener('whisper:download-progress', callback), + onOllamaPullProgress: (callback) => ipcRenderer.on('ollama:pull-progress', callback), + removeOnOllamaPullProgress: (callback) => ipcRenderer.removeListener('ollama:pull-progress', callback) + }, - // send methods - cancelHideSettingsWindow: () => ipcRenderer.send('cancel-hide-settings-window'), - hideSettingsWindow: () => ipcRenderer.send('hide-settings-window') + // src/ui/settings/ShortCutSettingsView.js + shortcutSettingsView: { + // Shortcut Management + saveShortcuts: (shortcuts) => ipcRenderer.invoke('save-shortcuts', shortcuts), + getDefaultShortcuts: () => ipcRenderer.invoke('get-default-shortcuts'), + closeShortcutEditor: () => ipcRenderer.send('close-shortcut-editor'), + + // Listeners + onLoadShortcuts: (callback) => ipcRenderer.on('load-shortcuts', callback), + removeOnLoadShortcuts: (callback) => ipcRenderer.removeListener('load-shortcuts', callback) + }, + + // src/ui/app/content.html inline scripts + content: { + // Animation Management + sendAnimationFinished: () => ipcRenderer.send('animation-finished'), + + // Listeners + onWindowShowAnimation: (callback) => ipcRenderer.on('window-show-animation', callback), + removeOnWindowShowAnimation: (callback) => ipcRenderer.removeListener('window-show-animation', callback), + onWindowHideAnimation: (callback) => ipcRenderer.on('window-hide-animation', callback), + removeOnWindowHideAnimation: (callback) => ipcRenderer.removeListener('window-hide-animation', callback), + onSettingsWindowHideAnimation: (callback) => ipcRenderer.on('settings-window-hide-animation', callback), + removeOnSettingsWindowHideAnimation: (callback) => ipcRenderer.removeListener('settings-window-hide-animation', callback), + onListenWindowMoveToCenter: (callback) => ipcRenderer.on('listen-window-move-to-center', callback), + removeOnListenWindowMoveToCenter: (callback) => ipcRenderer.removeListener('listen-window-move-to-center', callback), + onListenWindowMoveToLeft: (callback) => ipcRenderer.on('listen-window-move-to-left', callback), + removeOnListenWindowMoveToLeft: (callback) => ipcRenderer.removeListener('listen-window-move-to-left', callback) + }, + + // src/ui/listen/audioCore/listenCapture.js + listenCapture: { + // Audio Management + sendAudioContent: (data) => ipcRenderer.invoke('send-audio-content', data), + sendSystemAudioContent: (data) => ipcRenderer.invoke('send-system-audio-content', data), + startMacosAudio: () => ipcRenderer.invoke('start-macos-audio'), + stopMacosAudio: () => ipcRenderer.invoke('stop-macos-audio'), + + // Screen Capture + captureScreenshot: (options) => ipcRenderer.invoke('capture-screenshot', options), + getCurrentScreenshot: () => ipcRenderer.invoke('get-current-screenshot'), + startScreenCapture: () => ipcRenderer.invoke('start-screen-capture'), + stopScreenCapture: () => ipcRenderer.invoke('stop-screen-capture'), + + // Session Management + isSessionActive: () => ipcRenderer.invoke('is-session-active'), + + // Listeners + onSystemAudioData: (callback) => ipcRenderer.on('system-audio-data', callback), + removeOnSystemAudioData: (callback) => ipcRenderer.removeListener('system-audio-data', callback) + }, + + // src/ui/listen/audioCore/renderer.js + renderer: { + // Listeners + onChangeListenCaptureState: (callback) => ipcRenderer.on('change-listen-capture-state', callback), + removeOnChangeListenCaptureState: (callback) => ipcRenderer.removeListener('change-listen-capture-state', callback) } }); \ No newline at end of file diff --git a/src/ui/app/ApiKeyHeader.js b/src/ui/app/ApiKeyHeader.js index 659b2cc..0bdbe03 100644 --- a/src/ui/app/ApiKeyHeader.js +++ b/src/ui/app/ApiKeyHeader.js @@ -370,13 +370,12 @@ export class ApiKeyHeader extends LitElement { } async loadProviderConfig() { - if (!window.require) return; - const { ipcRenderer } = window.require('electron'); + if (!window.api) return; try { const [config, ollamaStatus] = await Promise.all([ - ipcRenderer.invoke('model:get-provider-config'), - ipcRenderer.invoke('ollama:get-status') + window.api.apiKeyHeader.getProviderConfig(), + window.api.apiKeyHeader.getOllamaStatus() ]); const llmProviders = []; @@ -428,8 +427,7 @@ export class ApiKeyHeader extends LitElement { e.preventDefault() - const { ipcRenderer } = window.require("electron") - const initialPosition = await ipcRenderer.invoke("get-header-position") + const initialPosition = await window.api.apiKeyHeader.getHeaderPosition() this.dragState = { initialMouseX: e.screenX, @@ -456,8 +454,7 @@ export class ApiKeyHeader extends LitElement { const newWindowX = this.dragState.initialWindowX + (e.screenX - this.dragState.initialMouseX) const newWindowY = this.dragState.initialWindowY + (e.screenY - this.dragState.initialMouseY) - const { ipcRenderer } = window.require("electron") - ipcRenderer.invoke("move-header-to", newWindowX, newWindowY) + window.api.apiKeyHeader.moveHeaderTo(newWindowX, newWindowY) } handleMouseUp(e) { @@ -652,9 +649,8 @@ export class ApiKeyHeader extends LitElement { try { // Lightweight health check - just ping the service const isHealthy = await this._executeOperation('health_check', async () => { - if (!window.require) return false; - const { ipcRenderer } = window.require('electron'); - const result = await ipcRenderer.invoke('ollama:get-status'); + if (!window.api) return false; + const result = await window.api.apiKeyHeader.getOllamaStatus(); return result?.success && result?.running; }, { timeout: 5000, priority: 'low' }); @@ -928,14 +924,13 @@ export class ApiKeyHeader extends LitElement { } async refreshOllamaStatus() { - if (!window.require) return; + if (!window.api) return; try { this._updateConnectionState('connecting', 'Checking Ollama status'); const result = await this._executeOperation('ollama_status', async () => { - const { ipcRenderer } = window.require('electron'); - return await ipcRenderer.invoke('ollama:get-status'); + return await window.api.apiKeyHeader.getOllamaStatus(); }); if (result?.success) { @@ -960,12 +955,11 @@ export class ApiKeyHeader extends LitElement { } async loadModelSuggestions() { - if (!window.require) return; + if (!window.api) return; try { const result = await this._executeOperation('model_suggestions', async () => { - const { ipcRenderer } = window.require('electron'); - return await ipcRenderer.invoke('ollama:get-model-suggestions'); + return await window.api.apiKeyHeader.getModelSuggestions(); }); if (result?.success) { @@ -988,14 +982,13 @@ export class ApiKeyHeader extends LitElement { } async ensureOllamaReady() { - if (!window.require) return false; + if (!window.api) return false; try { this._updateConnectionState('connecting', 'Ensuring Ollama is ready'); const result = await this._executeOperation('ollama_ensure_ready', async () => { - const { ipcRenderer } = window.require('electron'); - return await ipcRenderer.invoke('ollama:ensure-ready'); + return await window.api.apiKeyHeader.ensureOllamaReady(); }, { timeout: this.operationTimeout }); if (result?.success) { @@ -1015,8 +1008,7 @@ export class ApiKeyHeader extends LitElement { } async ensureOllamaReadyWithUI() { - if (!window.require) return false; - const { ipcRenderer } = window.require("electron"); + if (!window.api) return false; this.installingModel = "Setting up Ollama"; this.installProgress = 0; @@ -1074,21 +1066,21 @@ export class ApiKeyHeader extends LitElement { operationCompleted = true; clearTimeout(completionTimeout); - ipcRenderer.removeListener("ollama:install-progress", progressHandler); + window.api.apiKeyHeader.removeOnOllamaInstallProgress(progressHandler); await this._handleOllamaSetupCompletion(result.success, result.error); }; - ipcRenderer.once("ollama:install-complete", completionHandler); - ipcRenderer.on("ollama:install-progress", progressHandler); + window.api.apiKeyHeader.onceOllamaInstallComplete(completionHandler); + window.api.apiKeyHeader.onOllamaInstallProgress(progressHandler); try { let result; if (!this.ollamaStatus.installed) { console.log("[ApiKeyHeader] Ollama not installed. Starting installation."); - result = await ipcRenderer.invoke("ollama:install"); + result = await window.api.apiKeyHeader.installOllama(); } else { console.log("[ApiKeyHeader] Ollama installed. Starting service."); - result = await ipcRenderer.invoke("ollama:start-service"); + result = await window.api.apiKeyHeader.startOllamaService(); } // If IPC call succeeds but no event received, handle completion manually @@ -1106,8 +1098,8 @@ export class ApiKeyHeader extends LitElement { operationCompleted = true; clearTimeout(completionTimeout); console.error("[ApiKeyHeader] Ollama setup failed:", error); - ipcRenderer.removeListener("ollama:install-progress", progressHandler); - ipcRenderer.removeListener("ollama:install-complete", completionHandler); + window.api.apiKeyHeader.removeOnOllamaInstallProgress(progressHandler); + window.api.apiKeyHeader.removeOnceOllamaInstallComplete(completionHandler); await this._handleOllamaSetupCompletion(false, error.message); } } @@ -1229,7 +1221,6 @@ export class ApiKeyHeader extends LitElement { this.clearMessages(); this.requestUpdate(); - const { ipcRenderer } = window.require('electron'); let progressHandler = null; try { @@ -1249,10 +1240,10 @@ export class ApiKeyHeader extends LitElement { }; // Set up progress tracking - ipcRenderer.on('ollama:pull-progress', progressHandler); + window.api.apiKeyHeader.onOllamaPullProgress(progressHandler); // Execute the model pull with timeout - const installPromise = ipcRenderer.invoke('ollama:pull-model', modelName); + const installPromise = window.api.apiKeyHeader.pullOllamaModel(modelName); const timeoutPromise = new Promise((_, reject) => setTimeout(() => reject(new Error('Installation timeout after 10 minutes')), 600000) ); @@ -1281,7 +1272,7 @@ export class ApiKeyHeader extends LitElement { } finally { // Comprehensive cleanup if (progressHandler) { - ipcRenderer.removeListener('ollama:pull-progress', progressHandler); + window.api.apiKeyHeader.removeOnOllamaPullProgress(progressHandler); } this.installingModel = null; @@ -1307,7 +1298,6 @@ export class ApiKeyHeader extends LitElement { this.clearMessages(); this.requestUpdate(); - const { ipcRenderer } = window.require('electron'); let progressHandler = null; try { @@ -1321,10 +1311,10 @@ export class ApiKeyHeader extends LitElement { } }; - ipcRenderer.on('whisper:download-progress', progressHandler); + window.api.apiKeyHeader.onWhisperDownloadProgress(progressHandler); // Start download with timeout protection - const downloadPromise = ipcRenderer.invoke('whisper:download-model', modelId); + const downloadPromise = window.api.apiKeyHeader.downloadWhisperModel(modelId); const timeoutPromise = new Promise((_, reject) => setTimeout(() => reject(new Error('Download timeout after 10 minutes')), 600000) ); @@ -1351,7 +1341,7 @@ export class ApiKeyHeader extends LitElement { } finally { // Cleanup if (progressHandler) { - ipcRenderer.removeListener('whisper:download-progress', progressHandler); + window.api.apiKeyHeader.removeOnWhisperDownloadProgress(progressHandler); } delete this.whisperInstallingModels[modelId]; this.requestUpdate(); @@ -1411,8 +1401,6 @@ export class ApiKeyHeader extends LitElement { this.isLoading = true; this.clearMessages(); this.requestUpdate(); - - const { ipcRenderer } = window.require('electron'); try { // Handle LLM provider @@ -1436,14 +1424,14 @@ export class ApiKeyHeader extends LitElement { } // Validate Ollama is working - llmResult = await ipcRenderer.invoke('model:validate-key', { + llmResult = await window.api.apiKeyHeader.validateKey({ provider: 'ollama', key: 'local' }); if (llmResult.success) { // Set the selected model - await ipcRenderer.invoke('model:set-selected-model', { + await window.api.apiKeyHeader.setSelectedModel({ type: 'llm', modelId: this.selectedLlmModel }); @@ -1454,7 +1442,7 @@ export class ApiKeyHeader extends LitElement { throw new Error('Please enter LLM API key'); } - llmResult = await ipcRenderer.invoke('model:validate-key', { + llmResult = await window.api.apiKeyHeader.validateKey({ provider: this.llmProvider, key: this.llmApiKey.trim() }); @@ -1467,14 +1455,14 @@ export class ApiKeyHeader extends LitElement { sttResult = { success: true }; } else if (this.sttProvider === 'whisper') { // For Whisper, just validate it's enabled (model download already handled in handleSttModelChange) - sttResult = await ipcRenderer.invoke('model:validate-key', { + sttResult = await window.api.apiKeyHeader.validateKey({ provider: 'whisper', key: 'local' }); if (sttResult.success && this.selectedSttModel) { // Set the selected model - await ipcRenderer.invoke('model:set-selected-model', { + await window.api.apiKeyHeader.setSelectedModel({ type: 'stt', modelId: this.selectedSttModel }); @@ -1485,7 +1473,7 @@ export class ApiKeyHeader extends LitElement { throw new Error('Please enter STT API key'); } - sttResult = await ipcRenderer.invoke('model:validate-key', { + sttResult = await window.api.apiKeyHeader.validateKey({ provider: this.sttProvider, key: this.sttApiKey.trim() }); @@ -1522,15 +1510,15 @@ export class ApiKeyHeader extends LitElement { e.preventDefault() console.log("Requesting Firebase authentication from main process...") - if (window.require) { - window.require("electron").ipcRenderer.invoke("start-firebase-auth") + if (window.api) { + window.api.common.startFirebaseAuth() } } handleClose() { console.log("Close button clicked") - if (window.require) { - window.require("electron").ipcRenderer.invoke("quit-application") + if (window.api) { + window.api.common.quitApplication() } } @@ -1543,8 +1531,8 @@ export class ApiKeyHeader extends LitElement { console.log('[ApiKeyHeader] handleAnimationEnd: Transition completed, transitioning to next state...'); - if (!window.require) { - console.error('[ApiKeyHeader] handleAnimationEnd: window.require not available'); + if (!window.api) { + console.error('[ApiKeyHeader] handleAnimationEnd: window.api not available'); return; } @@ -1553,14 +1541,12 @@ export class ApiKeyHeader extends LitElement { return; } - const { ipcRenderer } = window.require('electron'); - - ipcRenderer.invoke('get-current-user') + window.api.common.getCurrentUser() .then(userState => { console.log('[ApiKeyHeader] handleAnimationEnd: User state retrieved:', userState); // Additional validation for local providers - return ipcRenderer.invoke('model:are-providers-configured').then(isConfigured => { + return window.api.apiKeyHeader.areProvidersConfigured().then(isConfigured => { console.log('[ApiKeyHeader] handleAnimationEnd: Providers configured check:', isConfigured); if (!isConfigured) { @@ -1625,12 +1611,8 @@ export class ApiKeyHeader extends LitElement { } // Cleanup event listeners - if (window.require) { - const { ipcRenderer } = window.require('electron'); - ipcRenderer.removeAllListeners('whisper:download-progress'); - ipcRenderer.removeAllListeners('ollama:install-progress'); - ipcRenderer.removeAllListeners('ollama:pull-progress'); - ipcRenderer.removeAllListeners('ollama:install-complete'); + if (window.api) { + window.api.apiKeyHeader.removeAllListeners(); } // Cancel any ongoing downloads diff --git a/src/ui/app/HeaderController.js b/src/ui/app/HeaderController.js index 8f56dec..37c5aa9 100644 --- a/src/ui/app/HeaderController.js +++ b/src/ui/app/HeaderController.js @@ -32,6 +32,7 @@ class HeaderTransitionManager { this.apiKeyHeader = document.createElement('apikey-header'); this.apiKeyHeader.stateUpdateCallback = (userState) => this.handleStateUpdate(userState); this.headerContainer.appendChild(this.apiKeyHeader); + console.log('[HeaderController] ensureHeader: Header of type:', type, 'created.'); } else if (type === 'permission') { this.permissionHeader = document.createElement('permission-setup'); this.permissionHeader.continueCallback = () => this.transitionToMainHeader(); @@ -50,41 +51,39 @@ class HeaderTransitionManager { this._bootstrap(); - if (window.require) { - const { ipcRenderer } = window.require('electron'); - - ipcRenderer.on('user-state-changed', (event, userState) => { + if (window.api) { + window.api.headerController.onUserStateChanged((event, userState) => { console.log('[HeaderController] Received user state change:', userState); this.handleStateUpdate(userState); }); - ipcRenderer.on('auth-failed', (event, { message }) => { + window.api.headerController.onAuthFailed((event, { message }) => { console.error('[HeaderController] Received auth failure from main process:', message); if (this.apiKeyHeader) { this.apiKeyHeader.errorMessage = 'Authentication failed. Please try again.'; this.apiKeyHeader.isLoading = false; } }); - ipcRenderer.on('force-show-apikey-header', async () => { + window.api.headerController.onForceShowApiKeyHeader(async () => { console.log('[HeaderController] Received broadcast to show apikey header. Switching now.'); await this._resizeForApiKey(); this.ensureHeader('apikey'); - }); + }); } } notifyHeaderState(stateOverride) { const state = stateOverride || this.currentHeaderType || 'apikey'; - if (window.require) { - window.require('electron').ipcRenderer.send('header-state-changed', state); + if (window.api) { + window.api.headerController.sendHeaderStateChanged(state); } } async _bootstrap() { // The initial state will be sent by the main process via 'user-state-changed' // We just need to request it. - if (window.require) { - const userState = await window.require('electron').ipcRenderer.invoke('get-current-user'); + if (window.api) { + const userState = await window.api.common.getCurrentUser(); console.log('[HeaderController] Bootstrapping with initial user state:', userState); this.handleStateUpdate(userState); } else { @@ -96,12 +95,7 @@ class HeaderTransitionManager { //////// after_modelStateService //////// async handleStateUpdate(userState) { - console.log('[HeaderController DEBUG] handleStateUpdate called with userState:', userState); - const { ipcRenderer } = window.require('electron'); - - console.log('[HeaderController DEBUG] Invoking "model:are-providers-configured"...'); - const isConfigured = await ipcRenderer.invoke('model:are-providers-configured'); - console.log('[HeaderController DEBUG] "model:are-providers-configured" returned:', isConfigured); + const isConfigured = await window.api.apiKeyHeader.areProvidersConfigured(); if (isConfigured) { const { isLoggedIn } = userState; @@ -130,10 +124,9 @@ class HeaderTransitionManager { } // Check if permissions were previously completed - if (window.require) { - const { ipcRenderer } = window.require('electron'); + if (window.api) { try { - const permissionsCompleted = await ipcRenderer.invoke('check-permissions-completed'); + const permissionsCompleted = await window.api.headerController.checkPermissionsCompleted(); if (permissionsCompleted) { console.log('[HeaderController] Permissions were previously completed, checking current status...'); @@ -165,39 +158,33 @@ class HeaderTransitionManager { this.ensureHeader('main'); } - _resizeForMain() { - if (!window.require) return; - return window - .require('electron') - .ipcRenderer.invoke('resize-header-window', { width: 353, height: 47 }) + async _resizeForMain() { + if (!window.api) return; + console.log('[HeaderController] _resizeForMain: Resizing window to 353x47'); + return window.api.headerController.resizeHeaderWindow({ width: 353, height: 47 }) .catch(() => {}); } async _resizeForApiKey() { - if (!window.require) return; - return window - .require('electron') - .ipcRenderer.invoke('resize-header-window', { width: 350, height: 300 }) + if (!window.api) return; + console.log('[HeaderController] _resizeForApiKey: Resizing window to 350x300'); + return window.api.headerController.resizeHeaderWindow({ width: 350, height: 300 }) .catch(() => {}); } async _resizeForPermissionHeader() { - if (!window.require) return; - return window - .require('electron') - .ipcRenderer.invoke('resize-header-window', { width: 285, height: 220 }) + if (!window.api) return; + return window.api.headerController.resizeHeaderWindow({ width: 285, height: 220 }) .catch(() => {}); } async checkPermissions() { - if (!window.require) { + if (!window.api) { return { success: true }; } - - const { ipcRenderer } = window.require('electron'); try { - const permissions = await ipcRenderer.invoke('check-system-permissions'); + const permissions = await window.api.headerController.checkSystemPermissions(); console.log('[HeaderController] Current permissions:', permissions); if (!permissions.needsSetup) { diff --git a/src/ui/app/MainHeader.js b/src/ui/app/MainHeader.js index 3f78f67..44f50e5 100644 --- a/src/ui/app/MainHeader.js +++ b/src/ui/app/MainHeader.js @@ -362,8 +362,7 @@ export class MainHeader extends LitElement { async handleMouseDown(e) { e.preventDefault(); - const { ipcRenderer } = window.require('electron'); - const initialPosition = await ipcRenderer.invoke('get-header-position'); + const initialPosition = await window.api.mainHeader.getHeaderPosition(); this.dragState = { initialMouseX: e.screenX, @@ -390,8 +389,7 @@ export class MainHeader extends LitElement { const newWindowX = this.dragState.initialWindowX + (e.screenX - this.dragState.initialMouseX); const newWindowY = this.dragState.initialWindowY + (e.screenY - this.dragState.initialMouseY); - const { ipcRenderer } = window.require('electron'); - ipcRenderer.invoke('move-header-to', newWindowX, newWindowY); + window.api.mainHeader.moveHeaderTo(newWindowX, newWindowY); } handleMouseUp(e) { @@ -447,12 +445,12 @@ export class MainHeader extends LitElement { if (this.classList.contains('hiding')) { this.classList.add('hidden'); - if (window.require) { - window.require('electron').ipcRenderer.send('header-animation-finished', 'hidden'); + if (window.api) { + window.api.mainHeader.sendHeaderAnimationFinished('hidden'); } } else if (this.classList.contains('showing')) { - if (window.require) { - window.require('electron').ipcRenderer.send('header-animation-finished', 'visible'); + if (window.api) { + window.api.mainHeader.sendHeaderAnimationFinished('visible'); } } } @@ -466,26 +464,24 @@ export class MainHeader extends LitElement { super.connectedCallback(); this.addEventListener('animationend', this.handleAnimationEnd); - if (window.require) { - const { ipcRenderer } = window.require('electron'); - + if (window.api) { this._sessionStateTextListener = (event, text) => { this.actionText = text; this.isTogglingSession = false; }; - ipcRenderer.on('session-state-text', this._sessionStateTextListener); + window.api.mainHeader.onSessionStateText(this._sessionStateTextListener); // this._sessionStateListener = (event, { isActive }) => { // this.isSessionActive = isActive; // this.isTogglingSession = false; // }; - // ipcRenderer.on('session-state-changed', this._sessionStateListener); + // window.api.mainHeader.onSessionStateChanged(this._sessionStateListener); this._shortcutListener = (event, keybinds) => { console.log('[MainHeader] Received updated shortcuts:', keybinds); this.shortcuts = keybinds; }; - ipcRenderer.on('shortcuts-updated', this._shortcutListener); + window.api.mainHeader.onShortcutsUpdated(this._shortcutListener); } } @@ -498,39 +494,37 @@ export class MainHeader extends LitElement { this.animationEndTimer = null; } - if (window.require) { - const { ipcRenderer } = window.require('electron'); + if (window.api) { if (this._sessionStateTextListener) { - ipcRenderer.removeListener('session-state-text', this._sessionStateTextListener); + window.api.mainHeader.removeOnSessionStateText(this._sessionStateTextListener); } // if (this._sessionStateListener) { - // ipcRenderer.removeListener('session-state-changed', this._sessionStateListener); + // window.api.mainHeader.removeOnSessionStateChanged(this._sessionStateListener); // } if (this._shortcutListener) { - ipcRenderer.removeListener('shortcuts-updated', this._shortcutListener); + window.api.mainHeader.removeOnShortcutsUpdated(this._shortcutListener); } } } invoke(channel, ...args) { if (this.wasJustDragged) return; - if (window.require) { - window.require('electron').ipcRenderer.invoke(channel, ...args); + if (window.api) { + window.api.mainHeader.invoke(channel, ...args); } // return Promise.resolve(); } showSettingsWindow(element) { if (this.wasJustDragged) return; - if (window.require) { - const { ipcRenderer } = window.require('electron'); + if (window.api) { console.log(`[MainHeader] showSettingsWindow called at ${Date.now()}`); - ipcRenderer.send('cancel-hide-settings-window'); + window.api.mainHeader.cancelHideSettingsWindow(); if (element) { const { left, top, width, height } = element.getBoundingClientRect(); - ipcRenderer.send('show-settings-window', { + window.api.mainHeader.showSettingsWindow({ x: left, y: top, width, @@ -542,9 +536,9 @@ export class MainHeader extends LitElement { hideSettingsWindow() { if (this.wasJustDragged) return; - if (window.require) { + if (window.api) { console.log(`[MainHeader] hideSettingsWindow called at ${Date.now()}`); - window.require('electron').ipcRenderer.send('hide-settings-window'); + window.api.mainHeader.hideSettingsWindow(); } } @@ -561,7 +555,7 @@ export class MainHeader extends LitElement { const args = ['listen']; await this.invoke(channel, ...args); } catch (error) { - console.error('IPC invoke for session toggle failed:', error); + console.error('session toggle failed:', error); this.isTogglingSession = false; } } diff --git a/src/ui/app/PermissionHeader.js b/src/ui/app/PermissionHeader.js index 96a01c1..d5761b1 100644 --- a/src/ui/app/PermissionHeader.js +++ b/src/ui/app/PermissionHeader.js @@ -288,13 +288,12 @@ export class PermissionHeader extends LitElement { } async checkPermissions() { - if (!window.require || this.isChecking) return; + if (!window.api || this.isChecking) return; this.isChecking = true; - const { ipcRenderer } = window.require('electron'); try { - const permissions = await ipcRenderer.invoke('check-system-permissions'); + const permissions = await window.api.permissionHeader.checkSystemPermissions(); console.log('[PermissionHeader] Permission check result:', permissions); const prevMic = this.microphoneGranted; @@ -324,13 +323,12 @@ export class PermissionHeader extends LitElement { } async handleMicrophoneClick() { - if (!window.require || this.microphoneGranted === 'granted') return; + if (!window.api || this.microphoneGranted === 'granted') return; console.log('[PermissionHeader] Requesting microphone permission...'); - const { ipcRenderer } = window.require('electron'); try { - const result = await ipcRenderer.invoke('check-system-permissions'); + const result = await window.api.permissionHeader.checkSystemPermissions(); console.log('[PermissionHeader] Microphone permission result:', result); if (result.microphone === 'granted') { @@ -340,7 +338,7 @@ export class PermissionHeader extends LitElement { } if (result.microphone === 'not-determined' || result.microphone === 'denied' || result.microphone === 'unknown' || result.microphone === 'restricted') { - const res = await ipcRenderer.invoke('request-microphone-permission'); + const res = await window.api.permissionHeader.requestMicrophonePermission(); if (res.status === 'granted' || res.success === true) { this.microphoneGranted = 'granted'; this.requestUpdate(); @@ -357,13 +355,12 @@ export class PermissionHeader extends LitElement { } async handleScreenClick() { - if (!window.require || this.screenGranted === 'granted') return; + if (!window.api || this.screenGranted === 'granted') return; console.log('[PermissionHeader] Checking screen recording permission...'); - const { ipcRenderer } = window.require('electron'); try { - const permissions = await ipcRenderer.invoke('check-system-permissions'); + const permissions = await window.api.permissionHeader.checkSystemPermissions(); console.log('[PermissionHeader] Screen permission check result:', permissions); if (permissions.screen === 'granted') { @@ -373,7 +370,7 @@ export class PermissionHeader extends LitElement { } if (permissions.screen === 'not-determined' || permissions.screen === 'denied' || permissions.screen === 'unknown' || permissions.screen === 'restricted') { console.log('[PermissionHeader] Opening screen recording preferences...'); - await ipcRenderer.invoke('open-system-preferences', 'screen-recording'); + await window.api.permissionHeader.openSystemPreferences('screen-recording'); } // Check permissions again after a delay @@ -389,10 +386,9 @@ export class PermissionHeader extends LitElement { this.microphoneGranted === 'granted' && this.screenGranted === 'granted') { // Mark permissions as completed - if (window.require) { - const { ipcRenderer } = window.require('electron'); + if (window.api) { try { - await ipcRenderer.invoke('mark-permissions-completed'); + await window.api.permissionHeader.markPermissionsCompleted(); console.log('[PermissionHeader] Marked permissions as completed'); } catch (error) { console.error('[PermissionHeader] Error marking permissions as completed:', error); @@ -405,8 +401,8 @@ export class PermissionHeader extends LitElement { handleClose() { console.log('Close button clicked'); - if (window.require) { - window.require('electron').ipcRenderer.invoke('quit-application'); + if (window.api) { + window.api.common.quitApplication(); } } diff --git a/src/ui/app/PickleGlassApp.js b/src/ui/app/PickleGlassApp.js index fc4939f..df920c3 100644 --- a/src/ui/app/PickleGlassApp.js +++ b/src/ui/app/PickleGlassApp.js @@ -74,10 +74,8 @@ export class PickleGlassApp extends LitElement { connectedCallback() { super.connectedCallback(); - if (window.require) { - const { ipcRenderer } = window.require('electron'); - - ipcRenderer.on('click-through-toggled', (_, isEnabled) => { + if (window.api) { + window.api.pickleGlassApp.onClickThroughToggled((_, isEnabled) => { this._isClickThrough = isEnabled; }); } @@ -85,9 +83,8 @@ export class PickleGlassApp extends LitElement { disconnectedCallback() { super.disconnectedCallback(); - if (window.require) { - const { ipcRenderer } = window.require('electron'); - ipcRenderer.removeAllListeners('click-through-toggled'); + if (window.api) { + window.api.pickleGlassApp.removeAllClickThroughListeners(); } } @@ -121,9 +118,8 @@ export class PickleGlassApp extends LitElement { } async handleClose() { - if (window.require) { - const { ipcRenderer } = window.require('electron'); - await ipcRenderer.invoke('quit-application'); + if (window.api) { + await window.api.common.quitApplication(); } } diff --git a/src/ui/app/content.html b/src/ui/app/content.html index 868e0db..8757011 100644 --- a/src/ui/app/content.html +++ b/src/ui/app/content.html @@ -1,7 +1,7 @@ - + Pickle Glass Content