refactoring the bridge
This commit is contained in:
parent
9f29fa5873
commit
1bdc5fd1bd
2
aec
2
aec
@ -1 +1 @@
|
||||
Subproject commit 3be088c6cff8021c74eca714150e68e2cc74bee0
|
||||
Subproject commit f00bb1fb948053c752b916adfee19f90644a0b2f
|
71
src/bridge/featureBridge.js
Normal file
71
src/bridge/featureBridge.js
Normal file
@ -0,0 +1,71 @@
|
||||
// src/bridge/featureBridge.js
|
||||
const { ipcMain } = require('electron');
|
||||
const settingsService = require('../features/settings/settingsService');
|
||||
|
||||
module.exports = {
|
||||
// Renderer로부터의 요청을 수신
|
||||
initialize() {
|
||||
// 기존 ask 핸들러 유지
|
||||
ipcMain.handle('feature:ask', (e, query) => {
|
||||
// 실제로는 여기서 Controller -> Service 로직 수행
|
||||
return `"${query}"에 대한 답변입니다.`;
|
||||
});
|
||||
|
||||
// settings 관련 핸들러 추가
|
||||
ipcMain.handle('settings:getSettings', async () => {
|
||||
return await settingsService.getSettings();
|
||||
});
|
||||
|
||||
ipcMain.handle('settings:saveSettings', async (event, settings) => {
|
||||
return await settingsService.saveSettings(settings);
|
||||
});
|
||||
|
||||
ipcMain.handle('settings:getPresets', async () => {
|
||||
return await settingsService.getPresets();
|
||||
});
|
||||
|
||||
ipcMain.handle('settings:getPresetTemplates', async () => {
|
||||
return await settingsService.getPresetTemplates();
|
||||
});
|
||||
|
||||
ipcMain.handle('settings:createPreset', async (event, title, prompt) => {
|
||||
return await settingsService.createPreset(title, prompt);
|
||||
});
|
||||
|
||||
ipcMain.handle('settings:updatePreset', async (event, id, title, prompt) => {
|
||||
return await settingsService.updatePreset(id, title, prompt);
|
||||
});
|
||||
|
||||
ipcMain.handle('settings:deletePreset', async (event, id) => {
|
||||
return await settingsService.deletePreset(id);
|
||||
});
|
||||
|
||||
ipcMain.handle('settings:saveApiKey', async (event, apiKey, provider) => {
|
||||
return await settingsService.saveApiKey(apiKey, provider);
|
||||
});
|
||||
|
||||
ipcMain.handle('settings:removeApiKey', async () => {
|
||||
return await settingsService.removeApiKey();
|
||||
});
|
||||
|
||||
ipcMain.handle('settings:updateContentProtection', async (event, enabled) => {
|
||||
return await settingsService.updateContentProtection(enabled);
|
||||
});
|
||||
|
||||
ipcMain.handle('settings:get-auto-update', async () => {
|
||||
return await settingsService.getAutoUpdateSetting();
|
||||
});
|
||||
|
||||
ipcMain.handle('settings:set-auto-update', async (event, isEnabled) => {
|
||||
console.log('[SettingsService] Setting auto update setting:', isEnabled);
|
||||
return await settingsService.setAutoUpdateSetting(isEnabled);
|
||||
});
|
||||
|
||||
console.log('[FeatureBridge] Initialized with settings handlers.');
|
||||
},
|
||||
|
||||
// Renderer로 상태를 전송
|
||||
sendAskProgress(win, progress) {
|
||||
win.webContents.send('feature:ask:progress', progress);
|
||||
},
|
||||
};
|
10
src/bridge/internalBridge.js
Normal file
10
src/bridge/internalBridge.js
Normal file
@ -0,0 +1,10 @@
|
||||
// src/bridge/internalBridge.js
|
||||
const { EventEmitter } = require('events');
|
||||
|
||||
// FeatureCore와 WindowCore를 잇는 내부 이벤트 버스
|
||||
module.exports = new EventEmitter();
|
||||
|
||||
// 예시 이벤트
|
||||
internalBridge.on('content-protection-changed', (enabled) => {
|
||||
// windowManager에서 처리
|
||||
});
|
74
src/bridge/windowBridge.js
Normal file
74
src/bridge/windowBridge.js
Normal file
@ -0,0 +1,74 @@
|
||||
// src/bridge/windowBridge.js
|
||||
const { ipcMain, BrowserWindow } = require('electron');
|
||||
const { windowPool, settingsHideTimer, app, shell } = require('../electron/windowManager'); // 필요 변수 require
|
||||
|
||||
module.exports = {
|
||||
// Renderer로부터의 요청을 수신
|
||||
initialize() {
|
||||
// 기존
|
||||
ipcMain.on('window:hide', (e) => BrowserWindow.fromWebContents(e.sender)?.hide());
|
||||
|
||||
// windowManager 관련 추가
|
||||
ipcMain.handle('toggle-content-protection', () => {
|
||||
// windowManager의 toggle-content-protection 로직
|
||||
isContentProtectionOn = !isContentProtectionOn;
|
||||
windowPool.forEach(win => {
|
||||
if (win && !win.isDestroyed()) {
|
||||
win.setContentProtection(isContentProtectionOn);
|
||||
}
|
||||
});
|
||||
return isContentProtectionOn;
|
||||
});
|
||||
|
||||
ipcMain.handle('get-content-protection-status', () => {
|
||||
return isContentProtectionOn;
|
||||
});
|
||||
|
||||
ipcMain.handle('open-shortcut-editor', () => {
|
||||
// open-shortcut-editor 로직 (windowPool 등 필요시 require)
|
||||
const header = windowPool.get('header');
|
||||
if (!header) return;
|
||||
globalShortcut.unregisterAll();
|
||||
createFeatureWindows(header, 'shortcut-settings');
|
||||
});
|
||||
|
||||
// 다른 관련 핸들러 추가 (quit-application, etc.)
|
||||
ipcMain.handle('quit-application', () => {
|
||||
app.quit();
|
||||
});
|
||||
|
||||
// 추가: 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);
|
||||
// 위치 조정 로직 (기존 복사)
|
||||
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);
|
||||
}
|
||||
});
|
||||
|
||||
// 추가: hide-settings-window 등 다른 핸들러 복사
|
||||
// ... (hide-settings-window, cancel-hide-settings-window, quit-application, open-login-page, firebase-logout, move-window-step 등)
|
||||
|
||||
// 예: ipcMain.handle('open-login-page', () => { shell.openExternal(...); });
|
||||
},
|
||||
|
||||
// Renderer로 상태를 전송
|
||||
notifyFocusChange(win, isFocused) {
|
||||
win.webContents.send('window:focus-change', isFocused);
|
||||
},
|
||||
};
|
@ -76,6 +76,7 @@ function updateLayout() {
|
||||
}
|
||||
|
||||
let movementManager = null;
|
||||
const windowBridge = require('../bridge/windowBridge');
|
||||
|
||||
|
||||
async function toggleFeature(featureName) {
|
||||
|
@ -543,11 +543,9 @@ export class SettingsView extends LitElement {
|
||||
}
|
||||
|
||||
async loadAutoUpdateSetting() {
|
||||
if (!window.require) return;
|
||||
const { ipcRenderer } = window.require('electron');
|
||||
this.autoUpdateLoading = true;
|
||||
try {
|
||||
const enabled = await ipcRenderer.invoke('settings:get-auto-update');
|
||||
const enabled = await window.api.feature.settings.getAutoUpdate();
|
||||
this.autoUpdateEnabled = enabled;
|
||||
console.log('Auto-update setting loaded:', enabled);
|
||||
} catch (e) {
|
||||
@ -559,13 +557,12 @@ export class SettingsView extends LitElement {
|
||||
}
|
||||
|
||||
async handleToggleAutoUpdate() {
|
||||
if (!window.require || this.autoUpdateLoading) return;
|
||||
const { ipcRenderer } = window.require('electron');
|
||||
if (this.autoUpdateLoading) return;
|
||||
this.autoUpdateLoading = true;
|
||||
this.requestUpdate();
|
||||
try {
|
||||
const newValue = !this.autoUpdateEnabled;
|
||||
const result = await ipcRenderer.invoke('settings:set-auto-update', newValue);
|
||||
const result = await window.api.feature.settings.setAutoUpdate(newValue);
|
||||
if (result && result.success) {
|
||||
this.autoUpdateEnabled = newValue;
|
||||
} else {
|
||||
@ -580,22 +577,20 @@ export class SettingsView extends LitElement {
|
||||
|
||||
//////// after_modelStateService ////////
|
||||
async loadInitialData() {
|
||||
if (!window.require) return;
|
||||
this.isLoading = true;
|
||||
const { ipcRenderer } = window.require('electron');
|
||||
try {
|
||||
const [userState, config, storedKeys, availableLlm, availableStt, selectedModels, presets, contentProtection, shortcuts, ollamaStatus, whisperModelsResult] = await Promise.all([
|
||||
ipcRenderer.invoke('get-current-user'),
|
||||
ipcRenderer.invoke('model:get-provider-config'), // Provider 설정 로드
|
||||
ipcRenderer.invoke('model:get-all-keys'),
|
||||
ipcRenderer.invoke('model:get-available-models', { type: 'llm' }),
|
||||
ipcRenderer.invoke('model:get-available-models', { type: 'stt' }),
|
||||
ipcRenderer.invoke('model:get-selected-models'),
|
||||
ipcRenderer.invoke('settings:getPresets'),
|
||||
ipcRenderer.invoke('get-content-protection-status'),
|
||||
ipcRenderer.invoke('get-current-shortcuts'),
|
||||
ipcRenderer.invoke('ollama:get-status'),
|
||||
ipcRenderer.invoke('whisper:get-installed-models')
|
||||
window.api.feature.settings.getCurrentUser(),
|
||||
window.api.feature.settings.getProviderConfig(), // Provider 설정 로드
|
||||
window.api.feature.settings.getAllKeys(),
|
||||
window.api.feature.settings.getAvailableModels({ type: 'llm' }),
|
||||
window.api.feature.settings.getAvailableModels({ type: 'stt' }),
|
||||
window.api.feature.settings.getSelectedModels(),
|
||||
window.api.feature.settings.getPresets(),
|
||||
window.api.feature.settings.getContentProtectionStatus(),
|
||||
window.api.feature.settings.getCurrentShortcuts(),
|
||||
window.api.feature.settings.getOllamaStatus(),
|
||||
window.api.feature.settings.getWhisperInstalledModels()
|
||||
]);
|
||||
|
||||
if (userState && userState.isLoggedIn) this.firebaseUser = userState;
|
||||
@ -644,10 +639,9 @@ export class SettingsView extends LitElement {
|
||||
// For Ollama, we need to ensure it's ready first
|
||||
if (provider === 'ollama') {
|
||||
this.saving = true;
|
||||
const { ipcRenderer } = window.require('electron');
|
||||
|
||||
// First ensure Ollama is installed and running
|
||||
const ensureResult = await ipcRenderer.invoke('ollama:ensure-ready');
|
||||
const ensureResult = await window.api.feature.settings.ensureOllamaReady();
|
||||
if (!ensureResult.success) {
|
||||
alert(`Failed to setup Ollama: ${ensureResult.error}`);
|
||||
this.saving = false;
|
||||
@ -655,7 +649,7 @@ export class SettingsView extends LitElement {
|
||||
}
|
||||
|
||||
// Now validate (which will check if service is running)
|
||||
const result = await ipcRenderer.invoke('model:validate-key', { provider, key: 'local' });
|
||||
const result = await window.api.feature.settings.validateKey({ provider, key: 'local' });
|
||||
|
||||
if (result.success) {
|
||||
this.apiKeys = { ...this.apiKeys, [provider]: 'local' };
|
||||
@ -671,8 +665,7 @@ export class SettingsView extends LitElement {
|
||||
// For Whisper, just enable it
|
||||
if (provider === 'whisper') {
|
||||
this.saving = true;
|
||||
const { ipcRenderer } = window.require('electron');
|
||||
const result = await ipcRenderer.invoke('model:validate-key', { provider, key: 'local' });
|
||||
const result = await window.api.feature.settings.validateKey({ provider, key: 'local' });
|
||||
|
||||
if (result.success) {
|
||||
this.apiKeys = { ...this.apiKeys, [provider]: 'local' };
|
||||
@ -686,8 +679,7 @@ export class SettingsView extends LitElement {
|
||||
|
||||
// For other providers, use the normal flow
|
||||
this.saving = true;
|
||||
const { ipcRenderer } = window.require('electron');
|
||||
const result = await ipcRenderer.invoke('model:validate-key', { provider, key });
|
||||
const result = await window.api.feature.settings.validateKey({ provider, key });
|
||||
|
||||
if (result.success) {
|
||||
this.apiKeys = { ...this.apiKeys, [provider]: key };
|
||||
@ -701,20 +693,18 @@ export class SettingsView extends LitElement {
|
||||
|
||||
async handleClearKey(provider) {
|
||||
this.saving = true;
|
||||
const { ipcRenderer } = window.require('electron');
|
||||
await ipcRenderer.invoke('model:remove-api-key', { provider });
|
||||
await window.api.feature.settings.removeApiKey({ provider });
|
||||
this.apiKeys = { ...this.apiKeys, [provider]: '' };
|
||||
await this.refreshModelData();
|
||||
this.saving = false;
|
||||
}
|
||||
|
||||
async refreshModelData() {
|
||||
const { ipcRenderer } = window.require('electron');
|
||||
const [availableLlm, availableStt, selected, storedKeys] = await Promise.all([
|
||||
ipcRenderer.invoke('model:get-available-models', { type: 'llm' }),
|
||||
ipcRenderer.invoke('model:get-available-models', { type: 'stt' }),
|
||||
ipcRenderer.invoke('model:get-selected-models'),
|
||||
ipcRenderer.invoke('model:get-all-keys')
|
||||
window.api.feature.settings.getAvailableModels({ type: 'llm' }),
|
||||
window.api.feature.settings.getAvailableModels({ type: 'stt' }),
|
||||
window.api.feature.settings.getSelectedModels(),
|
||||
window.api.feature.settings.getAllKeys()
|
||||
]);
|
||||
this.availableLlmModels = availableLlm;
|
||||
this.availableSttModels = availableStt;
|
||||
@ -765,8 +755,7 @@ export class SettingsView extends LitElement {
|
||||
}
|
||||
|
||||
this.saving = true;
|
||||
const { ipcRenderer } = window.require('electron');
|
||||
await ipcRenderer.invoke('model:set-selected-model', { type, modelId });
|
||||
await window.api.feature.settings.setSelectedModel({ type, modelId });
|
||||
if (type === 'llm') this.selectedLlm = modelId;
|
||||
if (type === 'stt') this.selectedStt = modelId;
|
||||
this.isLlmListVisible = false;
|
||||
@ -776,8 +765,7 @@ export class SettingsView extends LitElement {
|
||||
}
|
||||
|
||||
async refreshOllamaStatus() {
|
||||
const { ipcRenderer } = window.require('electron');
|
||||
const ollamaStatus = await ipcRenderer.invoke('ollama:get-status');
|
||||
const ollamaStatus = await window.api.feature.settings.getOllamaStatus();
|
||||
if (ollamaStatus?.success) {
|
||||
this.ollamaStatus = { installed: ollamaStatus.installed, running: ollamaStatus.running };
|
||||
this.ollamaModels = ollamaStatus.models || [];
|
||||
@ -821,8 +809,6 @@ export class SettingsView extends LitElement {
|
||||
this.requestUpdate();
|
||||
|
||||
try {
|
||||
const { ipcRenderer } = window.require('electron');
|
||||
|
||||
// Set up progress listener
|
||||
const progressHandler = (event, { modelId: id, progress }) => {
|
||||
if (id === modelId) {
|
||||
@ -831,10 +817,10 @@ export class SettingsView extends LitElement {
|
||||
}
|
||||
};
|
||||
|
||||
ipcRenderer.on('whisper:download-progress', progressHandler);
|
||||
window.api.feature.settings.onWhisperDownloadProgress(progressHandler);
|
||||
|
||||
// Start download
|
||||
const result = await ipcRenderer.invoke('whisper:download-model', modelId);
|
||||
const result = await window.api.feature.settings.downloadWhisperModel(modelId);
|
||||
|
||||
if (result.success) {
|
||||
// Auto-select the model after download
|
||||
@ -844,7 +830,7 @@ export class SettingsView extends LitElement {
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
ipcRenderer.removeListener('whisper:download-progress', progressHandler);
|
||||
window.api.feature.settings.removeOnWhisperDownloadProgress(progressHandler);
|
||||
} catch (error) {
|
||||
console.error(`[SettingsView] Error downloading Whisper model ${modelId}:`, error);
|
||||
alert(`Error downloading ${modelId}: ${error.message}`);
|
||||
@ -876,17 +862,12 @@ export class SettingsView extends LitElement {
|
||||
if (this.wasJustDragged) return
|
||||
|
||||
console.log("Requesting Firebase authentication from main process...")
|
||||
if (window.require) {
|
||||
window.require("electron").ipcRenderer.invoke("start-firebase-auth")
|
||||
}
|
||||
}
|
||||
window.api.feature.settings.startFirebaseAuth();
|
||||
}
|
||||
//////// after_modelStateService ////////
|
||||
|
||||
openShortcutEditor() {
|
||||
if (window.require) {
|
||||
const { ipcRenderer } = window.require('electron');
|
||||
ipcRenderer.invoke('open-shortcut-editor');
|
||||
}
|
||||
window.api.feature.settings.openShortcutEditor();
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
@ -924,10 +905,6 @@ export class SettingsView extends LitElement {
|
||||
}
|
||||
|
||||
setupIpcListeners() {
|
||||
if (!window.require) return;
|
||||
|
||||
const { ipcRenderer } = window.require('electron');
|
||||
|
||||
this._userStateListener = (event, userState) => {
|
||||
console.log('[SettingsView] Received user-state-changed:', userState);
|
||||
if (userState && userState.isLoggedIn) {
|
||||
@ -949,7 +926,7 @@ export class SettingsView extends LitElement {
|
||||
this._presetsUpdatedListener = async (event) => {
|
||||
console.log('[SettingsView] Received presets-updated, refreshing presets');
|
||||
try {
|
||||
const presets = await ipcRenderer.invoke('settings:getPresets');
|
||||
const presets = await window.api.feature.settings.getPresets();
|
||||
this.presets = presets || [];
|
||||
|
||||
// 현재 선택된 프리셋이 삭제되었는지 확인 (사용자 프리셋만 고려)
|
||||
@ -968,28 +945,24 @@ export class SettingsView extends LitElement {
|
||||
this.shortcuts = keybinds;
|
||||
};
|
||||
|
||||
ipcRenderer.on('user-state-changed', this._userStateListener);
|
||||
ipcRenderer.on('settings-updated', this._settingsUpdatedListener);
|
||||
ipcRenderer.on('presets-updated', this._presetsUpdatedListener);
|
||||
ipcRenderer.on('shortcuts-updated', this._shortcutListener);
|
||||
window.api.feature.settings.onUserStateChanged(this._userStateListener);
|
||||
window.api.feature.settings.onSettingsUpdated(this._settingsUpdatedListener);
|
||||
window.api.feature.settings.onPresetsUpdated(this._presetsUpdatedListener);
|
||||
window.api.feature.settings.onShortcutsUpdated(this._shortcutListener);
|
||||
}
|
||||
|
||||
cleanupIpcListeners() {
|
||||
if (!window.require) return;
|
||||
|
||||
const { ipcRenderer } = window.require('electron');
|
||||
|
||||
if (this._userStateListener) {
|
||||
ipcRenderer.removeListener('user-state-changed', this._userStateListener);
|
||||
window.api.feature.settings.removeOnUserStateChanged(this._userStateListener);
|
||||
}
|
||||
if (this._settingsUpdatedListener) {
|
||||
ipcRenderer.removeListener('settings-updated', this._settingsUpdatedListener);
|
||||
window.api.feature.settings.removeOnSettingsUpdated(this._settingsUpdatedListener);
|
||||
}
|
||||
if (this._presetsUpdatedListener) {
|
||||
ipcRenderer.removeListener('presets-updated', this._presetsUpdatedListener);
|
||||
window.api.feature.settings.removeOnPresetsUpdated(this._presetsUpdatedListener);
|
||||
}
|
||||
if (this._shortcutListener) {
|
||||
ipcRenderer.removeListener('shortcuts-updated', this._shortcutListener);
|
||||
window.api.feature.settings.removeOnShortcutsUpdated(this._shortcutListener);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1023,17 +996,11 @@ export class SettingsView extends LitElement {
|
||||
}
|
||||
|
||||
handleMouseEnter = () => {
|
||||
if (window.require) {
|
||||
const { ipcRenderer } = window.require('electron');
|
||||
ipcRenderer.send('cancel-hide-settings-window');
|
||||
}
|
||||
window.api.window.cancelHideSettingsWindow();
|
||||
}
|
||||
|
||||
handleMouseLeave = () => {
|
||||
if (window.require) {
|
||||
const { ipcRenderer } = window.require('electron');
|
||||
ipcRenderer.send('hide-settings-window');
|
||||
}
|
||||
window.api.window.hideSettingsWindow();
|
||||
}
|
||||
|
||||
// getMainShortcuts() {
|
||||
@ -1083,39 +1050,27 @@ export class SettingsView extends LitElement {
|
||||
|
||||
handleMoveLeft() {
|
||||
console.log('Move Left clicked');
|
||||
if (window.require) {
|
||||
const { ipcRenderer } = window.require('electron');
|
||||
ipcRenderer.invoke('move-window-step', 'left');
|
||||
}
|
||||
window.api.feature.settings.moveWindowStep('left');
|
||||
}
|
||||
|
||||
handleMoveRight() {
|
||||
console.log('Move Right clicked');
|
||||
if (window.require) {
|
||||
const { ipcRenderer } = window.require('electron');
|
||||
ipcRenderer.invoke('move-window-step', 'right');
|
||||
}
|
||||
window.api.feature.settings.moveWindowStep('right');
|
||||
}
|
||||
|
||||
async handlePersonalize() {
|
||||
console.log('Personalize clicked');
|
||||
if (window.require) {
|
||||
const { ipcRenderer } = window.require('electron');
|
||||
try {
|
||||
await ipcRenderer.invoke('open-login-page');
|
||||
} catch (error) {
|
||||
console.error('Failed to open personalize page:', error);
|
||||
}
|
||||
try {
|
||||
await window.api.window.openLoginPage();
|
||||
} catch (error) {
|
||||
console.error('Failed to open personalize page:', error);
|
||||
}
|
||||
}
|
||||
|
||||
async handleToggleInvisibility() {
|
||||
console.log('Toggle Invisibility clicked');
|
||||
if (window.require) {
|
||||
const { ipcRenderer } = window.require('electron');
|
||||
this.isContentProtectionOn = await ipcRenderer.invoke('toggle-content-protection');
|
||||
this.requestUpdate();
|
||||
}
|
||||
this.isContentProtectionOn = await window.api.window.toggleContentProtection();
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
async handleSaveApiKey() {
|
||||
@ -1123,62 +1078,46 @@ export class SettingsView extends LitElement {
|
||||
if (!input || !input.value) return;
|
||||
|
||||
const newApiKey = input.value;
|
||||
if (window.require) {
|
||||
const { ipcRenderer } = window.require('electron');
|
||||
try {
|
||||
const result = await ipcRenderer.invoke('settings:saveApiKey', newApiKey);
|
||||
if (result.success) {
|
||||
console.log('API Key saved successfully via IPC.');
|
||||
this.apiKey = newApiKey;
|
||||
this.requestUpdate();
|
||||
} else {
|
||||
console.error('Failed to save API Key via IPC:', result.error);
|
||||
}
|
||||
} catch(e) {
|
||||
console.error('Error invoking save-api-key IPC:', e);
|
||||
try {
|
||||
const result = await window.api.feature.settings.saveApiKey(newApiKey);
|
||||
if (result.success) {
|
||||
console.log('API Key saved successfully via IPC.');
|
||||
this.apiKey = newApiKey;
|
||||
this.requestUpdate();
|
||||
} else {
|
||||
console.error('Failed to save API Key via IPC:', result.error);
|
||||
}
|
||||
} catch(e) {
|
||||
console.error('Error invoking save-api-key IPC:', e);
|
||||
}
|
||||
}
|
||||
|
||||
async handleClearApiKey() {
|
||||
console.log('Clear API Key clicked');
|
||||
if (window.require) {
|
||||
const { ipcRenderer } = window.require('electron');
|
||||
await ipcRenderer.invoke('settings:removeApiKey');
|
||||
this.apiKey = null;
|
||||
this.requestUpdate();
|
||||
}
|
||||
await window.api.feature.settings.removeApiKey();
|
||||
this.apiKey = null;
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
handleQuit() {
|
||||
console.log('Quit clicked');
|
||||
if (window.require) {
|
||||
const { ipcRenderer } = window.require('electron');
|
||||
ipcRenderer.invoke('quit-application');
|
||||
}
|
||||
window.api.window.quitApplication();
|
||||
}
|
||||
|
||||
handleFirebaseLogout() {
|
||||
console.log('Firebase Logout clicked');
|
||||
if (window.require) {
|
||||
const { ipcRenderer } = window.require('electron');
|
||||
ipcRenderer.invoke('firebase-logout');
|
||||
}
|
||||
window.api.window.firebaseLogout();
|
||||
}
|
||||
|
||||
async handleOllamaShutdown() {
|
||||
console.log('[SettingsView] Shutting down Ollama service...');
|
||||
|
||||
if (!window.require) return;
|
||||
|
||||
const { ipcRenderer } = window.require('electron');
|
||||
|
||||
try {
|
||||
// Show loading state
|
||||
this.ollamaStatus = { ...this.ollamaStatus, running: false };
|
||||
this.requestUpdate();
|
||||
|
||||
const result = await ipcRenderer.invoke('ollama:shutdown', false); // Graceful shutdown
|
||||
const result = await window.api.feature.settings.shutdownOllama(false); // Graceful shutdown
|
||||
|
||||
if (result.success) {
|
||||
console.log('[SettingsView] Ollama shut down successfully');
|
||||
@ -1330,329 +1269,6 @@ export class SettingsView extends LitElement {
|
||||
//////// before_modelStateService ////////
|
||||
|
||||
//////// after_modelStateService ////////
|
||||
render() {
|
||||
if (this.isLoading) {
|
||||
return html`
|
||||
<div class="settings-container">
|
||||
<div class="loading-state">
|
||||
<div class="loading-spinner"></div>
|
||||
<span>Loading...</span>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
const loggedIn = !!this.firebaseUser;
|
||||
|
||||
const apiKeyManagementHTML = html`
|
||||
<div class="api-key-section">
|
||||
${Object.entries(this.providerConfig)
|
||||
.filter(([id, config]) => !id.includes('-glass'))
|
||||
.map(([id, config]) => {
|
||||
if (id === 'ollama') {
|
||||
// Special UI for Ollama
|
||||
return html`
|
||||
<div class="provider-key-group">
|
||||
<label>${config.name} (Local)</label>
|
||||
${this.ollamaStatus.installed && this.ollamaStatus.running ? html`
|
||||
<div style="padding: 8px; background: rgba(0,255,0,0.1); border-radius: 4px; font-size: 11px; color: rgba(0,255,0,0.8);">
|
||||
✓ Ollama is running
|
||||
</div>
|
||||
<button class="settings-button full-width danger" @click=${this.handleOllamaShutdown}>
|
||||
Stop Ollama Service
|
||||
</button>
|
||||
` : this.ollamaStatus.installed ? html`
|
||||
<div style="padding: 8px; background: rgba(255,200,0,0.1); border-radius: 4px; font-size: 11px; color: rgba(255,200,0,0.8);">
|
||||
⚠ Ollama installed but not running
|
||||
</div>
|
||||
<button class="settings-button full-width" @click=${() => this.handleSaveKey(id)}>
|
||||
Start Ollama
|
||||
</button>
|
||||
` : html`
|
||||
<div style="padding: 8px; background: rgba(255,100,100,0.1); border-radius: 4px; font-size: 11px; color: rgba(255,100,100,0.8);">
|
||||
✗ Ollama not installed
|
||||
</div>
|
||||
<button class="settings-button full-width" @click=${() => this.handleSaveKey(id)}>
|
||||
Install & Setup Ollama
|
||||
</button>
|
||||
`}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
if (id === 'whisper') {
|
||||
// Special UI for Whisper with model selection
|
||||
const whisperModels = config.sttModels || [];
|
||||
const selectedWhisperModel = this.selectedStt && this.getProviderForModel('stt', this.selectedStt) === 'whisper'
|
||||
? this.selectedStt
|
||||
: null;
|
||||
|
||||
return html`
|
||||
<div class="provider-key-group">
|
||||
<label>${config.name} (Local STT)</label>
|
||||
${this.apiKeys[id] === 'local' ? html`
|
||||
<div style="padding: 8px; background: rgba(0,255,0,0.1); border-radius: 4px; font-size: 11px; color: rgba(0,255,0,0.8); margin-bottom: 8px;">
|
||||
✓ Whisper is enabled
|
||||
</div>
|
||||
|
||||
<!-- Whisper Model Selection Dropdown -->
|
||||
<label style="font-size: 10px; margin-top: 8px;">Select Model:</label>
|
||||
<select
|
||||
class="model-dropdown"
|
||||
style="width: 100%; padding: 6px; background: rgba(0,0,0,0.2); border: 1px solid rgba(255,255,255,0.2); color: white; border-radius: 4px; font-size: 11px; margin-bottom: 8px;"
|
||||
@change=${(e) => this.handleWhisperModelSelect(e.target.value)}
|
||||
.value=${selectedWhisperModel || ''}
|
||||
>
|
||||
<option value="">Choose a model...</option>
|
||||
${whisperModels.map(model => {
|
||||
const isInstalling = this.installingModels[model.id] !== undefined;
|
||||
const progress = this.installingModels[model.id] || 0;
|
||||
|
||||
let statusText = '';
|
||||
if (isInstalling) {
|
||||
statusText = ` (Downloading ${progress}%)`;
|
||||
} else if (model.installed) {
|
||||
statusText = ' (Installed)';
|
||||
}
|
||||
|
||||
return html`
|
||||
<option value="${model.id}" ?disabled=${isInstalling}>
|
||||
${model.name}${statusText}
|
||||
</option>
|
||||
`;
|
||||
})}
|
||||
</select>
|
||||
|
||||
${Object.entries(this.installingModels).map(([modelId, progress]) => {
|
||||
if (modelId.startsWith('whisper-') && progress !== undefined) {
|
||||
return html`
|
||||
<div style="margin: 8px 0;">
|
||||
<div style="font-size: 10px; color: rgba(255,255,255,0.7); margin-bottom: 4px;">
|
||||
Downloading ${modelId}...
|
||||
</div>
|
||||
<div class="install-progress" style="height: 4px; background: rgba(255,255,255,0.1); border-radius: 2px; overflow: hidden;">
|
||||
<div class="install-progress-bar" style="height: 100%; background: rgba(0, 122, 255, 0.8); width: ${progress}%; transition: width 0.3s ease;"></div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
return null;
|
||||
})}
|
||||
|
||||
<button class="settings-button full-width danger" @click=${() => this.handleClearKey(id)}>
|
||||
Disable Whisper
|
||||
</button>
|
||||
` : html`
|
||||
<button class="settings-button full-width" @click=${() => this.handleSaveKey(id)}>
|
||||
Enable Whisper STT
|
||||
</button>
|
||||
`}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
// Regular providers
|
||||
return html`
|
||||
<div class="provider-key-group">
|
||||
<label for="key-input-${id}">${config.name} API Key</label>
|
||||
<input type="password" id="key-input-${id}"
|
||||
placeholder=${loggedIn ? "Using Pickle's Key" : `Enter ${config.name} API Key`}
|
||||
.value=${this.apiKeys[id] || ''}
|
||||
>
|
||||
<div class="key-buttons">
|
||||
<button class="settings-button" @click=${() => this.handleSaveKey(id)} >Save</button>
|
||||
<button class="settings-button danger" @click=${() => this.handleClearKey(id)} }>Clear</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
})}
|
||||
</div>
|
||||
`;
|
||||
|
||||
const getModelName = (type, id) => {
|
||||
const models = type === 'llm' ? this.availableLlmModels : this.availableSttModels;
|
||||
const model = models.find(m => m.id === id);
|
||||
return model ? model.name : id;
|
||||
}
|
||||
|
||||
const modelSelectionHTML = html`
|
||||
<div class="model-selection-section">
|
||||
<div class="model-select-group">
|
||||
<label>LLM Model: <strong>${getModelName('llm', this.selectedLlm) || 'Not Set'}</strong></label>
|
||||
<button class="settings-button full-width" @click=${() => this.toggleModelList('llm')} ?disabled=${this.saving || this.availableLlmModels.length === 0}>
|
||||
Change LLM Model
|
||||
</button>
|
||||
${this.isLlmListVisible ? html`
|
||||
<div class="model-list">
|
||||
${this.availableLlmModels.map(model => {
|
||||
const isOllama = this.getProviderForModel('llm', model.id) === 'ollama';
|
||||
const ollamaModel = isOllama ? this.ollamaModels.find(m => m.name === model.id) : null;
|
||||
const isInstalling = this.installingModels[model.id] !== undefined;
|
||||
const installProgress = this.installingModels[model.id] || 0;
|
||||
|
||||
return html`
|
||||
<div class="model-item ${this.selectedLlm === model.id ? 'selected' : ''}"
|
||||
@click=${() => this.selectModel('llm', model.id)}>
|
||||
<span>${model.name}</span>
|
||||
${isOllama ? html`
|
||||
${isInstalling ? html`
|
||||
<div class="install-progress">
|
||||
<div class="install-progress-bar" style="width: ${installProgress}%"></div>
|
||||
</div>
|
||||
` : ollamaModel?.installed ? html`
|
||||
<span class="model-status installed">✓ Installed</span>
|
||||
` : html`
|
||||
<span class="model-status not-installed">Click to install</span>
|
||||
`}
|
||||
` : ''}
|
||||
</div>
|
||||
`;
|
||||
})}
|
||||
</div>
|
||||
` : ''}
|
||||
</div>
|
||||
<div class="model-select-group">
|
||||
<label>STT Model: <strong>${getModelName('stt', this.selectedStt) || 'Not Set'}</strong></label>
|
||||
<button class="settings-button full-width" @click=${() => this.toggleModelList('stt')} ?disabled=${this.saving || this.availableSttModels.length === 0}>
|
||||
Change STT Model
|
||||
</button>
|
||||
${this.isSttListVisible ? html`
|
||||
<div class="model-list">
|
||||
${this.availableSttModels.map(model => {
|
||||
const isWhisper = this.getProviderForModel('stt', model.id) === 'whisper';
|
||||
const isInstalling = this.installingModels[model.id] !== undefined;
|
||||
const installProgress = this.installingModels[model.id] || 0;
|
||||
|
||||
return html`
|
||||
<div class="model-item ${this.selectedStt === model.id ? 'selected' : ''}"
|
||||
@click=${() => this.selectModel('stt', model.id)}>
|
||||
<span>${model.name}</span>
|
||||
${isWhisper && isInstalling ? html`
|
||||
<div class="install-progress">
|
||||
<div class="install-progress-bar" style="width: ${installProgress}%"></div>
|
||||
</div>
|
||||
` : ''}
|
||||
</div>
|
||||
`;
|
||||
})}
|
||||
</div>
|
||||
` : ''}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
return html`
|
||||
<div class="settings-container">
|
||||
<div class="header-section">
|
||||
<div>
|
||||
<h1 class="app-title">Pickle Glass</h1>
|
||||
<div class="account-info">
|
||||
${this.firebaseUser
|
||||
? html`Account: ${this.firebaseUser.email || 'Logged In'}`
|
||||
: `Account: Not Logged In`
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div class="invisibility-icon ${this.isContentProtectionOn ? 'visible' : ''}" title="Invisibility is On">
|
||||
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M9.785 7.41787C8.7 7.41787 7.79 8.19371 7.55667 9.22621C7.0025 8.98704 6.495 9.05121 6.11 9.22037C5.87083 8.18204 4.96083 7.41787 3.88167 7.41787C2.61583 7.41787 1.58333 8.46204 1.58333 9.75121C1.58333 11.0404 2.61583 12.0845 3.88167 12.0845C5.08333 12.0845 6.06333 11.1395 6.15667 9.93787C6.355 9.79787 6.87417 9.53537 7.51 9.94954C7.615 11.1454 8.58333 12.0845 9.785 12.0845C11.0508 12.0845 12.0833 11.0404 12.0833 9.75121C12.0833 8.46204 11.0508 7.41787 9.785 7.41787ZM3.88167 11.4195C2.97167 11.4195 2.2425 10.6729 2.2425 9.75121C2.2425 8.82954 2.9775 8.08287 3.88167 8.08287C4.79167 8.08287 5.52083 8.82954 5.52083 9.75121C5.52083 10.6729 4.79167 11.4195 3.88167 11.4195ZM9.785 11.4195C8.875 11.4195 8.14583 10.6729 8.14583 9.75121C8.14583 8.82954 8.875 8.08287 9.785 8.08287C10.695 8.08287 11.43 8.82954 11.43 9.75121C11.43 10.6729 10.6892 11.4195 9.785 11.4195ZM12.6667 5.95954H1V6.83454H12.6667V5.95954ZM8.8925 1.36871C8.76417 1.08287 8.4375 0.931207 8.12833 1.03037L6.83333 1.46204L5.5325 1.03037L5.50333 1.02454C5.19417 0.93704 4.8675 1.10037 4.75083 1.39787L3.33333 5.08454H10.3333L8.91 1.39787L8.8925 1.36871Z" fill="white"/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
${apiKeyManagementHTML}
|
||||
${modelSelectionHTML}
|
||||
|
||||
<div class="buttons-section" style="border-top: 1px solid rgba(255, 255, 255, 0.1); padding-top: 6px; margin-top: 6px;">
|
||||
<button class="settings-button full-width" @click=${this.openShortcutEditor}>
|
||||
Edit Shortcuts
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="shortcuts-section">
|
||||
${this.getMainShortcuts().map(shortcut => html`
|
||||
<div class="shortcut-item">
|
||||
<span class="shortcut-name">${shortcut.name}</span>
|
||||
<div class="shortcut-keys">
|
||||
${this.renderShortcutKeys(shortcut.accelerator)}
|
||||
</div>
|
||||
</div>
|
||||
`)}
|
||||
</div>
|
||||
|
||||
<div class="preset-section">
|
||||
<div class="preset-header">
|
||||
<span class="preset-title">
|
||||
My Presets
|
||||
<span class="preset-count">(${this.presets.filter(p => p.is_default === 0).length})</span>
|
||||
</span>
|
||||
<span class="preset-toggle" @click=${this.togglePresets}>
|
||||
${this.showPresets ? '▼' : '▶'}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="preset-list ${this.showPresets ? '' : 'hidden'}">
|
||||
${this.presets.filter(p => p.is_default === 0).length === 0 ? html`
|
||||
<div class="no-presets-message">
|
||||
No custom presets yet.<br>
|
||||
<span class="web-link" @click=${this.handlePersonalize}>
|
||||
Create your first preset
|
||||
</span>
|
||||
</div>
|
||||
` : this.presets.filter(p => p.is_default === 0).map(preset => html`
|
||||
<div class="preset-item ${this.selectedPreset?.id === preset.id ? 'selected' : ''}"
|
||||
@click=${() => this.handlePresetSelect(preset)}>
|
||||
<span class="preset-name">${preset.title}</span>
|
||||
${this.selectedPreset?.id === preset.id ? html`<span class="preset-status">Selected</span>` : ''}
|
||||
</div>
|
||||
`)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="buttons-section">
|
||||
<button class="settings-button full-width" @click=${this.handlePersonalize}>
|
||||
<span>Personalize / Meeting Notes</span>
|
||||
</button>
|
||||
<button class="settings-button full-width" @click=${this.handleToggleAutoUpdate} ?disabled=${this.autoUpdateLoading}>
|
||||
<span>Automatic Updates: ${this.autoUpdateEnabled ? 'On' : 'Off'}</span>
|
||||
</button>
|
||||
|
||||
<div class="move-buttons">
|
||||
<button class="settings-button half-width" @click=${this.handleMoveLeft}>
|
||||
<span>← Move</span>
|
||||
</button>
|
||||
<button class="settings-button half-width" @click=${this.handleMoveRight}>
|
||||
<span>Move →</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<button class="settings-button full-width" @click=${this.handleToggleInvisibility}>
|
||||
<span>${this.isContentProtectionOn ? 'Disable Invisibility' : 'Enable Invisibility'}</span>
|
||||
</button>
|
||||
|
||||
<div class="bottom-buttons">
|
||||
${this.firebaseUser
|
||||
? html`
|
||||
<button class="settings-button half-width danger" @click=${this.handleFirebaseLogout}>
|
||||
<span>Logout</span>
|
||||
</button>
|
||||
`
|
||||
: html`
|
||||
<button class="settings-button half-width" @click=${this.handleUsePicklesKey}>
|
||||
<span>Login</span>
|
||||
</button>
|
||||
`
|
||||
}
|
||||
<button class="settings-button half-width danger" @click=${this.handleQuit}>
|
||||
<span>Quit</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
//////// after_modelStateService ////////
|
||||
}
|
||||
|
||||
customElements.define('settings-view', SettingsView);
|
@ -373,56 +373,7 @@ function initialize() {
|
||||
// cleanup
|
||||
windowNotificationManager.cleanup();
|
||||
|
||||
// IPC handlers for settings
|
||||
ipcMain.handle('settings:getSettings', async () => {
|
||||
return await getSettings();
|
||||
});
|
||||
|
||||
ipcMain.handle('settings:saveSettings', async (event, settings) => {
|
||||
return await saveSettings(settings);
|
||||
});
|
||||
|
||||
// IPC handlers for presets
|
||||
ipcMain.handle('settings:getPresets', async () => {
|
||||
return await getPresets();
|
||||
});
|
||||
|
||||
ipcMain.handle('settings:getPresetTemplates', async () => {
|
||||
return await getPresetTemplates();
|
||||
});
|
||||
|
||||
ipcMain.handle('settings:createPreset', async (event, title, prompt) => {
|
||||
return await createPreset(title, prompt);
|
||||
});
|
||||
|
||||
ipcMain.handle('settings:updatePreset', async (event, id, title, prompt) => {
|
||||
return await updatePreset(id, title, prompt);
|
||||
});
|
||||
|
||||
ipcMain.handle('settings:deletePreset', async (event, id) => {
|
||||
return await deletePreset(id);
|
||||
});
|
||||
|
||||
ipcMain.handle('settings:saveApiKey', async (event, apiKey, provider) => {
|
||||
return await saveApiKey(apiKey, provider);
|
||||
});
|
||||
|
||||
ipcMain.handle('settings:removeApiKey', async () => {
|
||||
return await removeApiKey();
|
||||
});
|
||||
|
||||
ipcMain.handle('settings:updateContentProtection', async (event, enabled) => {
|
||||
return await updateContentProtection(enabled);
|
||||
});
|
||||
|
||||
ipcMain.handle('settings:get-auto-update', async () => {
|
||||
return await getAutoUpdateSetting();
|
||||
});
|
||||
|
||||
ipcMain.handle('settings:set-auto-update', async (event, isEnabled) => {
|
||||
console.log('[SettingsService] Setting auto update setting:', isEnabled);
|
||||
return await setAutoUpdateSetting(isEnabled);
|
||||
});
|
||||
// IPC handlers 제거 (featureBridge로 이동)
|
||||
|
||||
console.log('[SettingsService] Initialized and ready.');
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ const settingsService = require('./features/settings/settingsService');
|
||||
const sessionRepository = require('./common/repositories/session');
|
||||
const ModelStateService = require('./common/services/modelStateService');
|
||||
const sqliteClient = require('./common/services/sqliteClient');
|
||||
const featureBridge = require('./bridge/featureBridge');
|
||||
|
||||
// Global variables
|
||||
const eventBridge = new EventEmitter();
|
||||
@ -205,6 +206,7 @@ app.whenReady().then(async () => {
|
||||
listenService.setupIpcHandlers();
|
||||
askService.initialize();
|
||||
settingsService.initialize();
|
||||
featureBridge.initialize(); // 추가: featureBridge 초기화
|
||||
setupGeneralIpcHandlers();
|
||||
setupOllamaIpcHandlers();
|
||||
setupWhisperIpcHandlers();
|
||||
|
@ -1,2 +1,86 @@
|
||||
// See the Electron documentation for details on how to use preload scripts:
|
||||
// https://www.electronjs.org/docs/latest/tutorial/process-model#preload-scripts
|
||||
// src/preload.js
|
||||
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'),
|
||||
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)
|
||||
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')
|
||||
}
|
||||
},
|
||||
// 기존 window 유지
|
||||
window: {
|
||||
// 기존
|
||||
hide: () => ipcRenderer.send('window:hide'),
|
||||
onFocusChange: (callback) => ipcRenderer.on('window:focus-change', (e, f) => callback(f)),
|
||||
|
||||
// 추가
|
||||
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),
|
||||
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)
|
||||
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')
|
||||
}
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user