initial commit

This commit is contained in:
Илья Глазунов
2026-01-14 22:57:19 +03:00
commit beb9034cd4
50 changed files with 17257 additions and 0 deletions
+503
View File
@@ -0,0 +1,503 @@
const { BrowserWindow, globalShortcut, ipcMain, screen } = require('electron');
const path = require('node:path');
const fs = require('node:fs');
const os = require('os');
const storage = require('../storage');
let mouseEventsIgnored = false;
let windowResizing = false;
let resizeAnimation = null;
const RESIZE_ANIMATION_DURATION = 500; // milliseconds
function createWindow(sendToRenderer, geminiSessionRef) {
// Get layout preference (default to 'normal')
let windowWidth = 1100;
let windowHeight = 800;
const mainWindow = new BrowserWindow({
width: windowWidth,
height: windowHeight,
frame: false,
transparent: true,
hasShadow: false,
alwaysOnTop: true,
webPreferences: {
nodeIntegration: true,
contextIsolation: false, // TODO: change to true
backgroundThrottling: false,
enableBlinkFeatures: 'GetDisplayMedia',
webSecurity: true,
allowRunningInsecureContent: false,
},
backgroundColor: '#00000000',
});
const { session, desktopCapturer } = require('electron');
session.defaultSession.setDisplayMediaRequestHandler(
(request, callback) => {
desktopCapturer.getSources({ types: ['screen'] }).then(sources => {
callback({ video: sources[0], audio: 'loopback' });
});
},
{ useSystemPicker: true }
);
mainWindow.setResizable(false);
mainWindow.setContentProtection(true);
mainWindow.setVisibleOnAllWorkspaces(true, { visibleOnFullScreen: true });
// Hide from Windows taskbar
if (process.platform === 'win32') {
try {
mainWindow.setSkipTaskbar(true);
console.log('Hidden from Windows taskbar');
} catch (error) {
console.warn('Could not hide from taskbar:', error.message);
}
}
// Hide from Mission Control on macOS
if (process.platform === 'darwin') {
try {
mainWindow.setHiddenInMissionControl(true);
console.log('Hidden from macOS Mission Control');
} catch (error) {
console.warn('Could not hide from Mission Control:', error.message);
}
}
// Center window at the top of the screen
const primaryDisplay = screen.getPrimaryDisplay();
const { width: screenWidth } = primaryDisplay.workAreaSize;
const x = Math.floor((screenWidth - windowWidth) / 2);
const y = 0;
mainWindow.setPosition(x, y);
if (process.platform === 'win32') {
mainWindow.setAlwaysOnTop(true, 'screen-saver', 1);
}
mainWindow.loadFile(path.join(__dirname, '../index.html'));
// After window is created, initialize keybinds
mainWindow.webContents.once('dom-ready', () => {
setTimeout(() => {
const defaultKeybinds = getDefaultKeybinds();
let keybinds = defaultKeybinds;
// Load keybinds from storage
const savedKeybinds = storage.getKeybinds();
if (savedKeybinds) {
keybinds = { ...defaultKeybinds, ...savedKeybinds };
}
updateGlobalShortcuts(keybinds, mainWindow, sendToRenderer, geminiSessionRef);
}, 150);
});
setupWindowIpcHandlers(mainWindow, sendToRenderer, geminiSessionRef);
return mainWindow;
}
function getDefaultKeybinds() {
const isMac = process.platform === 'darwin';
return {
moveUp: isMac ? 'Alt+Up' : 'Ctrl+Up',
moveDown: isMac ? 'Alt+Down' : 'Ctrl+Down',
moveLeft: isMac ? 'Alt+Left' : 'Ctrl+Left',
moveRight: isMac ? 'Alt+Right' : 'Ctrl+Right',
toggleVisibility: isMac ? 'Cmd+\\' : 'Ctrl+\\',
toggleClickThrough: isMac ? 'Cmd+M' : 'Ctrl+M',
nextStep: isMac ? 'Cmd+Enter' : 'Ctrl+Enter',
previousResponse: isMac ? 'Cmd+[' : 'Ctrl+[',
nextResponse: isMac ? 'Cmd+]' : 'Ctrl+]',
scrollUp: isMac ? 'Cmd+Shift+Up' : 'Ctrl+Shift+Up',
scrollDown: isMac ? 'Cmd+Shift+Down' : 'Ctrl+Shift+Down',
emergencyErase: isMac ? 'Cmd+Shift+E' : 'Ctrl+Shift+E',
};
}
function updateGlobalShortcuts(keybinds, mainWindow, sendToRenderer, geminiSessionRef) {
console.log('Updating global shortcuts with:', keybinds);
// Unregister all existing shortcuts
globalShortcut.unregisterAll();
const primaryDisplay = screen.getPrimaryDisplay();
const { width, height } = primaryDisplay.workAreaSize;
const moveIncrement = Math.floor(Math.min(width, height) * 0.1);
// Register window movement shortcuts
const movementActions = {
moveUp: () => {
if (!mainWindow.isVisible()) return;
const [currentX, currentY] = mainWindow.getPosition();
mainWindow.setPosition(currentX, currentY - moveIncrement);
},
moveDown: () => {
if (!mainWindow.isVisible()) return;
const [currentX, currentY] = mainWindow.getPosition();
mainWindow.setPosition(currentX, currentY + moveIncrement);
},
moveLeft: () => {
if (!mainWindow.isVisible()) return;
const [currentX, currentY] = mainWindow.getPosition();
mainWindow.setPosition(currentX - moveIncrement, currentY);
},
moveRight: () => {
if (!mainWindow.isVisible()) return;
const [currentX, currentY] = mainWindow.getPosition();
mainWindow.setPosition(currentX + moveIncrement, currentY);
},
};
// Register each movement shortcut
Object.keys(movementActions).forEach(action => {
const keybind = keybinds[action];
if (keybind) {
try {
globalShortcut.register(keybind, movementActions[action]);
console.log(`Registered ${action}: ${keybind}`);
} catch (error) {
console.error(`Failed to register ${action} (${keybind}):`, error);
}
}
});
// Register toggle visibility shortcut
if (keybinds.toggleVisibility) {
try {
globalShortcut.register(keybinds.toggleVisibility, () => {
if (mainWindow.isVisible()) {
mainWindow.hide();
} else {
mainWindow.showInactive();
}
});
console.log(`Registered toggleVisibility: ${keybinds.toggleVisibility}`);
} catch (error) {
console.error(`Failed to register toggleVisibility (${keybinds.toggleVisibility}):`, error);
}
}
// Register toggle click-through shortcut
if (keybinds.toggleClickThrough) {
try {
globalShortcut.register(keybinds.toggleClickThrough, () => {
mouseEventsIgnored = !mouseEventsIgnored;
if (mouseEventsIgnored) {
mainWindow.setIgnoreMouseEvents(true, { forward: true });
console.log('Mouse events ignored');
} else {
mainWindow.setIgnoreMouseEvents(false);
console.log('Mouse events enabled');
}
mainWindow.webContents.send('click-through-toggled', mouseEventsIgnored);
});
console.log(`Registered toggleClickThrough: ${keybinds.toggleClickThrough}`);
} catch (error) {
console.error(`Failed to register toggleClickThrough (${keybinds.toggleClickThrough}):`, error);
}
}
// Register next step shortcut (either starts session or takes screenshot based on view)
if (keybinds.nextStep) {
try {
globalShortcut.register(keybinds.nextStep, async () => {
console.log('Next step shortcut triggered');
try {
// Determine the shortcut key format
const isMac = process.platform === 'darwin';
const shortcutKey = isMac ? 'cmd+enter' : 'ctrl+enter';
// Use the new handleShortcut function
mainWindow.webContents.executeJavaScript(`
cheatingDaddy.handleShortcut('${shortcutKey}');
`);
} catch (error) {
console.error('Error handling next step shortcut:', error);
}
});
console.log(`Registered nextStep: ${keybinds.nextStep}`);
} catch (error) {
console.error(`Failed to register nextStep (${keybinds.nextStep}):`, error);
}
}
// Register previous response shortcut
if (keybinds.previousResponse) {
try {
globalShortcut.register(keybinds.previousResponse, () => {
console.log('Previous response shortcut triggered');
sendToRenderer('navigate-previous-response');
});
console.log(`Registered previousResponse: ${keybinds.previousResponse}`);
} catch (error) {
console.error(`Failed to register previousResponse (${keybinds.previousResponse}):`, error);
}
}
// Register next response shortcut
if (keybinds.nextResponse) {
try {
globalShortcut.register(keybinds.nextResponse, () => {
console.log('Next response shortcut triggered');
sendToRenderer('navigate-next-response');
});
console.log(`Registered nextResponse: ${keybinds.nextResponse}`);
} catch (error) {
console.error(`Failed to register nextResponse (${keybinds.nextResponse}):`, error);
}
}
// Register scroll up shortcut
if (keybinds.scrollUp) {
try {
globalShortcut.register(keybinds.scrollUp, () => {
console.log('Scroll up shortcut triggered');
sendToRenderer('scroll-response-up');
});
console.log(`Registered scrollUp: ${keybinds.scrollUp}`);
} catch (error) {
console.error(`Failed to register scrollUp (${keybinds.scrollUp}):`, error);
}
}
// Register scroll down shortcut
if (keybinds.scrollDown) {
try {
globalShortcut.register(keybinds.scrollDown, () => {
console.log('Scroll down shortcut triggered');
sendToRenderer('scroll-response-down');
});
console.log(`Registered scrollDown: ${keybinds.scrollDown}`);
} catch (error) {
console.error(`Failed to register scrollDown (${keybinds.scrollDown}):`, error);
}
}
// Register emergency erase shortcut
if (keybinds.emergencyErase) {
try {
globalShortcut.register(keybinds.emergencyErase, () => {
console.log('Emergency Erase triggered!');
if (mainWindow && !mainWindow.isDestroyed()) {
mainWindow.hide();
if (geminiSessionRef.current) {
geminiSessionRef.current.close();
geminiSessionRef.current = null;
}
sendToRenderer('clear-sensitive-data');
setTimeout(() => {
const { app } = require('electron');
app.quit();
}, 300);
}
});
console.log(`Registered emergencyErase: ${keybinds.emergencyErase}`);
} catch (error) {
console.error(`Failed to register emergencyErase (${keybinds.emergencyErase}):`, error);
}
}
}
function setupWindowIpcHandlers(mainWindow, sendToRenderer, geminiSessionRef) {
ipcMain.on('view-changed', (event, view) => {
if (view !== 'assistant' && !mainWindow.isDestroyed()) {
mainWindow.setIgnoreMouseEvents(false);
}
});
ipcMain.handle('window-minimize', () => {
if (!mainWindow.isDestroyed()) {
mainWindow.minimize();
}
});
ipcMain.on('update-keybinds', (event, newKeybinds) => {
if (!mainWindow.isDestroyed()) {
updateGlobalShortcuts(newKeybinds, mainWindow, sendToRenderer, geminiSessionRef);
}
});
ipcMain.handle('toggle-window-visibility', async event => {
try {
if (mainWindow.isDestroyed()) {
return { success: false, error: 'Window has been destroyed' };
}
if (mainWindow.isVisible()) {
mainWindow.hide();
} else {
mainWindow.showInactive();
}
return { success: true };
} catch (error) {
console.error('Error toggling window visibility:', error);
return { success: false, error: error.message };
}
});
function animateWindowResize(mainWindow, targetWidth, targetHeight, layoutMode) {
return new Promise(resolve => {
// Check if window is destroyed before starting animation
if (mainWindow.isDestroyed()) {
console.log('Cannot animate resize: window has been destroyed');
resolve();
return;
}
// Clear any existing animation
if (resizeAnimation) {
clearInterval(resizeAnimation);
resizeAnimation = null;
}
const [startWidth, startHeight] = mainWindow.getSize();
// If already at target size, no need to animate
if (startWidth === targetWidth && startHeight === targetHeight) {
console.log(`Window already at target size for ${layoutMode} mode`);
resolve();
return;
}
console.log(`Starting animated resize from ${startWidth}x${startHeight} to ${targetWidth}x${targetHeight}`);
windowResizing = true;
mainWindow.setResizable(true);
const frameRate = 60; // 60 FPS
const totalFrames = Math.floor(RESIZE_ANIMATION_DURATION / (1000 / frameRate));
let currentFrame = 0;
const widthDiff = targetWidth - startWidth;
const heightDiff = targetHeight - startHeight;
resizeAnimation = setInterval(() => {
currentFrame++;
const progress = currentFrame / totalFrames;
// Use easing function (ease-out)
const easedProgress = 1 - Math.pow(1 - progress, 3);
const currentWidth = Math.round(startWidth + widthDiff * easedProgress);
const currentHeight = Math.round(startHeight + heightDiff * easedProgress);
if (!mainWindow || mainWindow.isDestroyed()) {
clearInterval(resizeAnimation);
resizeAnimation = null;
windowResizing = false;
return;
}
mainWindow.setSize(currentWidth, currentHeight);
// Re-center the window during animation
const primaryDisplay = screen.getPrimaryDisplay();
const { width: screenWidth } = primaryDisplay.workAreaSize;
const x = Math.floor((screenWidth - currentWidth) / 2);
const y = 0;
mainWindow.setPosition(x, y);
if (currentFrame >= totalFrames) {
clearInterval(resizeAnimation);
resizeAnimation = null;
windowResizing = false;
// Check if window is still valid before final operations
if (!mainWindow.isDestroyed()) {
mainWindow.setResizable(false);
// Ensure final size is exact
mainWindow.setSize(targetWidth, targetHeight);
const finalX = Math.floor((screenWidth - targetWidth) / 2);
mainWindow.setPosition(finalX, 0);
}
console.log(`Animation complete: ${targetWidth}x${targetHeight}`);
resolve();
}
}, 1000 / frameRate);
});
}
ipcMain.handle('update-sizes', async event => {
try {
if (mainWindow.isDestroyed()) {
return { success: false, error: 'Window has been destroyed' };
}
// Get current view and layout mode from renderer
let viewName, layoutMode;
try {
viewName = await event.sender.executeJavaScript('cheatingDaddy.getCurrentView()');
layoutMode = await event.sender.executeJavaScript('cheatingDaddy.getLayoutMode()');
} catch (error) {
console.warn('Failed to get view/layout from renderer, using defaults:', error);
viewName = 'main';
layoutMode = 'normal';
}
console.log('Size update requested for view:', viewName, 'layout:', layoutMode);
let targetWidth, targetHeight;
// Determine base size from layout mode
const baseWidth = layoutMode === 'compact' ? 700 : 900;
const baseHeight = layoutMode === 'compact' ? 500 : 600;
// Adjust height based on view
switch (viewName) {
case 'main':
targetWidth = baseWidth;
targetHeight = layoutMode === 'compact' ? 320 : 400;
break;
case 'customize':
case 'settings':
targetWidth = baseWidth;
targetHeight = layoutMode === 'compact' ? 700 : 800;
break;
case 'help':
targetWidth = baseWidth;
targetHeight = layoutMode === 'compact' ? 650 : 750;
break;
case 'history':
targetWidth = baseWidth;
targetHeight = layoutMode === 'compact' ? 650 : 750;
break;
case 'assistant':
case 'onboarding':
default:
targetWidth = baseWidth;
targetHeight = baseHeight;
break;
}
const [currentWidth, currentHeight] = mainWindow.getSize();
console.log('Current window size:', currentWidth, 'x', currentHeight);
// If currently resizing, the animation will start from current position
if (windowResizing) {
console.log('Interrupting current resize animation');
}
await animateWindowResize(mainWindow, targetWidth, targetHeight, `${viewName} view (${layoutMode})`);
return { success: true };
} catch (error) {
console.error('Error updating sizes:', error);
return { success: false, error: error.message };
}
});
}
module.exports = {
createWindow,
getDefaultKeybinds,
updateGlobalShortcuts,
setupWindowIpcHandlers,
};