prettier fix
This commit is contained in:
+4
-6
@@ -52,9 +52,7 @@ function buildContextMessage() {
|
||||
|
||||
if (validTurns.length === 0) return null;
|
||||
|
||||
const contextLines = validTurns.map(turn =>
|
||||
`[Interviewer]: ${turn.transcription.trim()}\n[Your answer]: ${turn.ai_response.trim()}`
|
||||
);
|
||||
const contextLines = validTurns.map(turn => `[Interviewer]: ${turn.transcription.trim()}\n[Your answer]: ${turn.ai_response.trim()}`);
|
||||
|
||||
return `Session reconnected. Here's the conversation so far:\n\n${contextLines.join('\n\n')}\n\nContinue from here.`;
|
||||
}
|
||||
@@ -74,7 +72,7 @@ function initializeNewSession(profile = null, customPrompt = null) {
|
||||
sendToRenderer('save-session-context', {
|
||||
sessionId: currentSessionId,
|
||||
profile: profile,
|
||||
customPrompt: customPrompt || ''
|
||||
customPrompt: customPrompt || '',
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -110,7 +108,7 @@ function saveScreenAnalysis(prompt, response, model) {
|
||||
timestamp: Date.now(),
|
||||
prompt: prompt,
|
||||
response: response.trim(),
|
||||
model: model
|
||||
model: model,
|
||||
};
|
||||
|
||||
screenAnalysisHistory.push(analysisEntry);
|
||||
@@ -122,7 +120,7 @@ function saveScreenAnalysis(prompt, response, model) {
|
||||
analysis: analysisEntry,
|
||||
fullHistory: screenAnalysisHistory,
|
||||
profile: currentProfile,
|
||||
customPrompt: currentCustomPrompt
|
||||
customPrompt: currentCustomPrompt,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+24
-22
@@ -7,19 +7,19 @@ let logPath = null;
|
||||
|
||||
function getLogPath() {
|
||||
if (logPath) return logPath;
|
||||
|
||||
|
||||
const userDataPath = app.getPath('userData');
|
||||
const logsDir = path.join(userDataPath, 'logs');
|
||||
|
||||
|
||||
// Create logs directory if it doesn't exist
|
||||
if (!fs.existsSync(logsDir)) {
|
||||
fs.mkdirSync(logsDir, { recursive: true });
|
||||
}
|
||||
|
||||
|
||||
// Create log file with timestamp
|
||||
const timestamp = new Date().toISOString().split('T')[0];
|
||||
logPath = path.join(logsDir, `app-${timestamp}.log`);
|
||||
|
||||
|
||||
return logPath;
|
||||
}
|
||||
|
||||
@@ -27,32 +27,32 @@ function initLogger() {
|
||||
try {
|
||||
const filePath = getLogPath();
|
||||
logFile = fs.createWriteStream(filePath, { flags: 'a' });
|
||||
|
||||
|
||||
const startMsg = `\n${'='.repeat(60)}\nApp started at ${new Date().toISOString()}\nPlatform: ${process.platform}, Arch: ${process.arch}\nElectron: ${process.versions.electron}, Node: ${process.versions.node}\nPackaged: ${app.isPackaged}\n${'='.repeat(60)}\n`;
|
||||
logFile.write(startMsg);
|
||||
|
||||
|
||||
// Override console methods to also write to file
|
||||
const originalLog = console.log;
|
||||
const originalError = console.error;
|
||||
const originalWarn = console.warn;
|
||||
|
||||
|
||||
console.log = (...args) => {
|
||||
originalLog.apply(console, args);
|
||||
writeLog('INFO', args);
|
||||
};
|
||||
|
||||
|
||||
console.error = (...args) => {
|
||||
originalError.apply(console, args);
|
||||
writeLog('ERROR', args);
|
||||
};
|
||||
|
||||
|
||||
console.warn = (...args) => {
|
||||
originalWarn.apply(console, args);
|
||||
writeLog('WARN', args);
|
||||
};
|
||||
|
||||
|
||||
console.log('Logger initialized, writing to:', filePath);
|
||||
|
||||
|
||||
return filePath;
|
||||
} catch (err) {
|
||||
console.error('Failed to initialize logger:', err);
|
||||
@@ -62,20 +62,22 @@ function initLogger() {
|
||||
|
||||
function writeLog(level, args) {
|
||||
if (!logFile) return;
|
||||
|
||||
|
||||
try {
|
||||
const timestamp = new Date().toISOString();
|
||||
const message = args.map(arg => {
|
||||
if (typeof arg === 'object') {
|
||||
try {
|
||||
return JSON.stringify(arg, null, 2);
|
||||
} catch {
|
||||
return String(arg);
|
||||
const message = args
|
||||
.map(arg => {
|
||||
if (typeof arg === 'object') {
|
||||
try {
|
||||
return JSON.stringify(arg, null, 2);
|
||||
} catch {
|
||||
return String(arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
return String(arg);
|
||||
}).join(' ');
|
||||
|
||||
return String(arg);
|
||||
})
|
||||
.join(' ');
|
||||
|
||||
logFile.write(`[${timestamp}] [${level}] ${message}\n`);
|
||||
} catch (err) {
|
||||
// Silently fail - don't want logging errors to crash the app
|
||||
|
||||
@@ -311,7 +311,9 @@ async function sendImageToOpenAI(base64Data, prompt, config) {
|
||||
const { apiKey, baseUrl, model } = config;
|
||||
|
||||
// OpenAI doesn't support images in Realtime API yet, use standard Chat Completions
|
||||
const apiEndpoint = baseUrl ? `${baseUrl.replace('wss://', 'https://').replace('/v1/realtime', '')}/v1/chat/completions` : 'https://api.openai.com/v1/chat/completions';
|
||||
const apiEndpoint = baseUrl
|
||||
? `${baseUrl.replace('wss://', 'https://').replace('/v1/realtime', '')}/v1/chat/completions`
|
||||
: 'https://api.openai.com/v1/chat/completions';
|
||||
|
||||
try {
|
||||
const response = await fetch(apiEndpoint, {
|
||||
|
||||
@@ -297,7 +297,7 @@ async function processAudioChunk(base64Audio, mimeType) {
|
||||
// Track first chunk time for duration-based flushing
|
||||
if (audioChunks.length === 0) {
|
||||
firstChunkTime = now;
|
||||
|
||||
|
||||
// Start periodic transcription timer (Windows needs this)
|
||||
if (!windowsTranscriptionTimer && process.platform === 'win32') {
|
||||
console.log('Starting Windows periodic transcription timer...');
|
||||
@@ -355,7 +355,7 @@ async function flushAudioAndTranscribe() {
|
||||
// Calculate audio duration
|
||||
const bytesPerSample = 2;
|
||||
const audioDurationMs = (combinedBuffer.length / bytesPerSample / SAMPLE_RATE) * 1000;
|
||||
|
||||
|
||||
console.log(`Transcribing ${chunkCount} chunks (${audioDurationMs.toFixed(0)}ms of audio)...`);
|
||||
|
||||
// Transcribe
|
||||
@@ -384,7 +384,7 @@ function clearConversation() {
|
||||
const systemMessage = conversationMessages.find(m => m.role === 'system');
|
||||
conversationMessages = systemMessage ? [systemMessage] : [];
|
||||
audioChunks = [];
|
||||
|
||||
|
||||
// Clear timers
|
||||
if (silenceCheckTimer) {
|
||||
clearTimeout(silenceCheckTimer);
|
||||
@@ -403,7 +403,7 @@ function closeOpenAISDK() {
|
||||
conversationMessages = [];
|
||||
audioChunks = [];
|
||||
isProcessing = false;
|
||||
|
||||
|
||||
// Clear timers
|
||||
if (silenceCheckTimer) {
|
||||
clearTimeout(silenceCheckTimer);
|
||||
@@ -413,7 +413,7 @@ function closeOpenAISDK() {
|
||||
clearInterval(windowsTranscriptionTimer);
|
||||
windowsTranscriptionTimer = null;
|
||||
}
|
||||
|
||||
|
||||
sendToRenderer('update-status', 'Disconnected');
|
||||
}
|
||||
|
||||
@@ -600,7 +600,7 @@ async function startMacOSAudioCapture() {
|
||||
|
||||
// Add to audio buffer for transcription
|
||||
audioBuffer = Buffer.concat([audioBuffer, monoChunk]);
|
||||
|
||||
|
||||
chunkCount++;
|
||||
if (chunkCount % 100 === 0) {
|
||||
console.log(`Audio: ${chunkCount} chunks processed, buffer size: ${audioBuffer.length}`);
|
||||
|
||||
+134
-92
@@ -22,14 +22,20 @@ const isWindows = process.platform === 'win32';
|
||||
|
||||
// Send logs to main process for file logging
|
||||
function logToMain(level, ...args) {
|
||||
const message = args.map(arg => {
|
||||
if (typeof arg === 'object') {
|
||||
try { return JSON.stringify(arg); } catch { return String(arg); }
|
||||
}
|
||||
return String(arg);
|
||||
}).join(' ');
|
||||
const message = args
|
||||
.map(arg => {
|
||||
if (typeof arg === 'object') {
|
||||
try {
|
||||
return JSON.stringify(arg);
|
||||
} catch {
|
||||
return String(arg);
|
||||
}
|
||||
}
|
||||
return String(arg);
|
||||
})
|
||||
.join(' ');
|
||||
ipcRenderer.send('renderer-log', { level, message });
|
||||
|
||||
|
||||
// Also log to console
|
||||
if (level === 'error') console.error(...args);
|
||||
else if (level === 'warn') console.warn(...args);
|
||||
@@ -130,7 +136,7 @@ const storage = {
|
||||
async getTodayLimits() {
|
||||
const result = await ipcRenderer.invoke('storage:get-today-limits');
|
||||
return result.success ? result.data : { flash: { count: 0 }, flashLite: { count: 0 } };
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// Cache for preferences to avoid async calls in hot paths
|
||||
@@ -297,18 +303,18 @@ async function startCapture(screenshotIntervalSeconds = 5, imageQuality = 'mediu
|
||||
// Windows - show custom screen picker first
|
||||
logToMain('info', '=== Starting Windows audio capture ===');
|
||||
cheatingDaddy.setStatus('Choose screen to share...');
|
||||
|
||||
|
||||
// Show screen picker dialog
|
||||
const appElement = document.querySelector('cheating-daddy-app');
|
||||
const pickerResult = await appElement.showScreenPickerDialog();
|
||||
|
||||
|
||||
if (pickerResult.cancelled) {
|
||||
cheatingDaddy.setStatus('Cancelled');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
cheatingDaddy.setStatus('Starting capture...');
|
||||
|
||||
|
||||
mediaStream = await navigator.mediaDevices.getDisplayMedia({
|
||||
video: {
|
||||
frameRate: 1,
|
||||
@@ -326,16 +332,16 @@ async function startCapture(screenshotIntervalSeconds = 5, imageQuality = 'mediu
|
||||
|
||||
const audioTracks = mediaStream.getAudioTracks();
|
||||
const videoTracks = mediaStream.getVideoTracks();
|
||||
|
||||
|
||||
logToMain('info', 'Windows capture result:', {
|
||||
hasVideo: videoTracks.length > 0,
|
||||
hasAudio: audioTracks.length > 0,
|
||||
audioTrackInfo: audioTracks.map(t => ({
|
||||
label: t.label,
|
||||
enabled: t.enabled,
|
||||
audioTrackInfo: audioTracks.map(t => ({
|
||||
label: t.label,
|
||||
enabled: t.enabled,
|
||||
muted: t.muted,
|
||||
readyState: t.readyState,
|
||||
settings: t.getSettings()
|
||||
settings: t.getSettings(),
|
||||
})),
|
||||
});
|
||||
|
||||
@@ -379,10 +385,10 @@ async function startCapture(screenshotIntervalSeconds = 5, imageQuality = 'mediu
|
||||
console.log('Manual mode enabled - screenshots will be captured on demand only');
|
||||
} catch (err) {
|
||||
console.error('Error starting capture:', err);
|
||||
|
||||
|
||||
// Provide more helpful error messages based on error type
|
||||
let errorMessage = err.message || 'Failed to start capture';
|
||||
|
||||
|
||||
if (errorMessage.toLowerCase().includes('timeout')) {
|
||||
errorMessage = 'Screen capture timed out. Please try again and select a screen quickly.';
|
||||
} else if (errorMessage.toLowerCase().includes('permission') || errorMessage.toLowerCase().includes('denied')) {
|
||||
@@ -392,7 +398,7 @@ async function startCapture(screenshotIntervalSeconds = 5, imageQuality = 'mediu
|
||||
} else if (errorMessage.toLowerCase().includes('aborted') || errorMessage.toLowerCase().includes('cancel')) {
|
||||
errorMessage = 'Screen selection was cancelled. Please try again.';
|
||||
}
|
||||
|
||||
|
||||
cheatingDaddy.setStatus('Error: ' + errorMessage);
|
||||
}
|
||||
}
|
||||
@@ -463,25 +469,28 @@ function setupLinuxSystemAudioProcessing() {
|
||||
function setupWindowsLoopbackProcessing() {
|
||||
// Setup audio processing for Windows loopback audio only
|
||||
logToMain('info', 'Setting up Windows loopback audio processing...');
|
||||
|
||||
|
||||
try {
|
||||
audioContext = new AudioContext({ sampleRate: SAMPLE_RATE });
|
||||
|
||||
|
||||
logToMain('info', 'AudioContext created:', {
|
||||
state: audioContext.state,
|
||||
sampleRate: audioContext.sampleRate,
|
||||
});
|
||||
|
||||
|
||||
// Resume AudioContext if suspended (Chrome policy)
|
||||
if (audioContext.state === 'suspended') {
|
||||
logToMain('warn', 'AudioContext suspended, attempting resume...');
|
||||
audioContext.resume().then(() => {
|
||||
logToMain('info', 'AudioContext resumed successfully');
|
||||
}).catch(err => {
|
||||
logToMain('error', 'Failed to resume AudioContext:', err.message);
|
||||
});
|
||||
audioContext
|
||||
.resume()
|
||||
.then(() => {
|
||||
logToMain('info', 'AudioContext resumed successfully');
|
||||
})
|
||||
.catch(err => {
|
||||
logToMain('error', 'Failed to resume AudioContext:', err.message);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
const source = audioContext.createMediaStreamSource(mediaStream);
|
||||
audioProcessor = audioContext.createScriptProcessor(BUFFER_SIZE, 1, 1);
|
||||
|
||||
@@ -505,9 +514,9 @@ function setupWindowsLoopbackProcessing() {
|
||||
data: base64Data,
|
||||
mimeType: 'audio/pcm;rate=24000',
|
||||
});
|
||||
|
||||
|
||||
chunkCount++;
|
||||
|
||||
|
||||
// Log progress every 100 chunks (~10 seconds)
|
||||
if (chunkCount === 1) {
|
||||
logToMain('info', 'First audio chunk sent to AI');
|
||||
@@ -522,9 +531,8 @@ function setupWindowsLoopbackProcessing() {
|
||||
|
||||
source.connect(audioProcessor);
|
||||
audioProcessor.connect(audioContext.destination);
|
||||
|
||||
|
||||
logToMain('info', 'Windows audio processing pipeline connected');
|
||||
|
||||
} catch (err) {
|
||||
logToMain('error', 'Error setting up Windows audio:', err.message, err.stack);
|
||||
cheatingDaddy.setStatus('Audio error: ' + err.message);
|
||||
@@ -760,17 +768,7 @@ async function captureRegionFromScreenshot(rect, screenshotDataUrl) {
|
||||
const cropContext = cropCanvas.getContext('2d');
|
||||
|
||||
// Draw only the selected region
|
||||
cropContext.drawImage(
|
||||
img,
|
||||
scaledRect.left,
|
||||
scaledRect.top,
|
||||
scaledRect.width,
|
||||
scaledRect.height,
|
||||
0,
|
||||
0,
|
||||
scaledRect.width,
|
||||
scaledRect.height
|
||||
);
|
||||
cropContext.drawImage(img, scaledRect.left, scaledRect.top, scaledRect.width, scaledRect.height, 0, 0, scaledRect.width, scaledRect.height);
|
||||
|
||||
// Convert to blob and send
|
||||
cropCanvas.toBlob(
|
||||
@@ -983,7 +981,7 @@ ipcRenderer.on('save-session-context', async (event, data) => {
|
||||
try {
|
||||
await storage.saveSession(data.sessionId, {
|
||||
profile: data.profile,
|
||||
customPrompt: data.customPrompt
|
||||
customPrompt: data.customPrompt,
|
||||
});
|
||||
console.log('Session context saved:', data.sessionId, 'profile:', data.profile);
|
||||
} catch (error) {
|
||||
@@ -997,7 +995,7 @@ ipcRenderer.on('save-screen-analysis', async (event, data) => {
|
||||
await storage.saveSession(data.sessionId, {
|
||||
screenAnalysisHistory: data.fullHistory,
|
||||
profile: data.profile,
|
||||
customPrompt: data.customPrompt
|
||||
customPrompt: data.customPrompt,
|
||||
});
|
||||
console.log('Screen analysis saved:', data.sessionId);
|
||||
} catch (error) {
|
||||
@@ -1032,60 +1030,102 @@ const theme = {
|
||||
themes: {
|
||||
dark: {
|
||||
background: '#1e1e1e',
|
||||
text: '#e0e0e0', textSecondary: '#a0a0a0', textMuted: '#6b6b6b',
|
||||
border: '#333333', accent: '#ffffff',
|
||||
btnPrimaryBg: '#ffffff', btnPrimaryText: '#000000', btnPrimaryHover: '#e0e0e0',
|
||||
tooltipBg: '#1a1a1a', tooltipText: '#ffffff',
|
||||
keyBg: 'rgba(255,255,255,0.1)'
|
||||
text: '#e0e0e0',
|
||||
textSecondary: '#a0a0a0',
|
||||
textMuted: '#6b6b6b',
|
||||
border: '#333333',
|
||||
accent: '#ffffff',
|
||||
btnPrimaryBg: '#ffffff',
|
||||
btnPrimaryText: '#000000',
|
||||
btnPrimaryHover: '#e0e0e0',
|
||||
tooltipBg: '#1a1a1a',
|
||||
tooltipText: '#ffffff',
|
||||
keyBg: 'rgba(255,255,255,0.1)',
|
||||
},
|
||||
light: {
|
||||
background: '#ffffff',
|
||||
text: '#1a1a1a', textSecondary: '#555555', textMuted: '#888888',
|
||||
border: '#e0e0e0', accent: '#000000',
|
||||
btnPrimaryBg: '#1a1a1a', btnPrimaryText: '#ffffff', btnPrimaryHover: '#333333',
|
||||
tooltipBg: '#1a1a1a', tooltipText: '#ffffff',
|
||||
keyBg: 'rgba(0,0,0,0.1)'
|
||||
text: '#1a1a1a',
|
||||
textSecondary: '#555555',
|
||||
textMuted: '#888888',
|
||||
border: '#e0e0e0',
|
||||
accent: '#000000',
|
||||
btnPrimaryBg: '#1a1a1a',
|
||||
btnPrimaryText: '#ffffff',
|
||||
btnPrimaryHover: '#333333',
|
||||
tooltipBg: '#1a1a1a',
|
||||
tooltipText: '#ffffff',
|
||||
keyBg: 'rgba(0,0,0,0.1)',
|
||||
},
|
||||
midnight: {
|
||||
background: '#0d1117',
|
||||
text: '#c9d1d9', textSecondary: '#8b949e', textMuted: '#6e7681',
|
||||
border: '#30363d', accent: '#58a6ff',
|
||||
btnPrimaryBg: '#58a6ff', btnPrimaryText: '#0d1117', btnPrimaryHover: '#79b8ff',
|
||||
tooltipBg: '#161b22', tooltipText: '#c9d1d9',
|
||||
keyBg: 'rgba(88,166,255,0.15)'
|
||||
text: '#c9d1d9',
|
||||
textSecondary: '#8b949e',
|
||||
textMuted: '#6e7681',
|
||||
border: '#30363d',
|
||||
accent: '#58a6ff',
|
||||
btnPrimaryBg: '#58a6ff',
|
||||
btnPrimaryText: '#0d1117',
|
||||
btnPrimaryHover: '#79b8ff',
|
||||
tooltipBg: '#161b22',
|
||||
tooltipText: '#c9d1d9',
|
||||
keyBg: 'rgba(88,166,255,0.15)',
|
||||
},
|
||||
sepia: {
|
||||
background: '#f4ecd8',
|
||||
text: '#5c4b37', textSecondary: '#7a6a56', textMuted: '#998875',
|
||||
border: '#d4c8b0', accent: '#8b4513',
|
||||
btnPrimaryBg: '#5c4b37', btnPrimaryText: '#f4ecd8', btnPrimaryHover: '#7a6a56',
|
||||
tooltipBg: '#5c4b37', tooltipText: '#f4ecd8',
|
||||
keyBg: 'rgba(92,75,55,0.15)'
|
||||
text: '#5c4b37',
|
||||
textSecondary: '#7a6a56',
|
||||
textMuted: '#998875',
|
||||
border: '#d4c8b0',
|
||||
accent: '#8b4513',
|
||||
btnPrimaryBg: '#5c4b37',
|
||||
btnPrimaryText: '#f4ecd8',
|
||||
btnPrimaryHover: '#7a6a56',
|
||||
tooltipBg: '#5c4b37',
|
||||
tooltipText: '#f4ecd8',
|
||||
keyBg: 'rgba(92,75,55,0.15)',
|
||||
},
|
||||
nord: {
|
||||
background: '#2e3440',
|
||||
text: '#eceff4', textSecondary: '#d8dee9', textMuted: '#4c566a',
|
||||
border: '#3b4252', accent: '#88c0d0',
|
||||
btnPrimaryBg: '#88c0d0', btnPrimaryText: '#2e3440', btnPrimaryHover: '#8fbcbb',
|
||||
tooltipBg: '#3b4252', tooltipText: '#eceff4',
|
||||
keyBg: 'rgba(136,192,208,0.15)'
|
||||
text: '#eceff4',
|
||||
textSecondary: '#d8dee9',
|
||||
textMuted: '#4c566a',
|
||||
border: '#3b4252',
|
||||
accent: '#88c0d0',
|
||||
btnPrimaryBg: '#88c0d0',
|
||||
btnPrimaryText: '#2e3440',
|
||||
btnPrimaryHover: '#8fbcbb',
|
||||
tooltipBg: '#3b4252',
|
||||
tooltipText: '#eceff4',
|
||||
keyBg: 'rgba(136,192,208,0.15)',
|
||||
},
|
||||
dracula: {
|
||||
background: '#282a36',
|
||||
text: '#f8f8f2', textSecondary: '#bd93f9', textMuted: '#6272a4',
|
||||
border: '#44475a', accent: '#ff79c6',
|
||||
btnPrimaryBg: '#ff79c6', btnPrimaryText: '#282a36', btnPrimaryHover: '#ff92d0',
|
||||
tooltipBg: '#44475a', tooltipText: '#f8f8f2',
|
||||
keyBg: 'rgba(255,121,198,0.15)'
|
||||
text: '#f8f8f2',
|
||||
textSecondary: '#bd93f9',
|
||||
textMuted: '#6272a4',
|
||||
border: '#44475a',
|
||||
accent: '#ff79c6',
|
||||
btnPrimaryBg: '#ff79c6',
|
||||
btnPrimaryText: '#282a36',
|
||||
btnPrimaryHover: '#ff92d0',
|
||||
tooltipBg: '#44475a',
|
||||
tooltipText: '#f8f8f2',
|
||||
keyBg: 'rgba(255,121,198,0.15)',
|
||||
},
|
||||
abyss: {
|
||||
background: '#0a0a0a',
|
||||
text: '#d4d4d4', textSecondary: '#808080', textMuted: '#505050',
|
||||
border: '#1a1a1a', accent: '#ffffff',
|
||||
btnPrimaryBg: '#ffffff', btnPrimaryText: '#0a0a0a', btnPrimaryHover: '#d4d4d4',
|
||||
tooltipBg: '#141414', tooltipText: '#d4d4d4',
|
||||
keyBg: 'rgba(255,255,255,0.08)'
|
||||
}
|
||||
text: '#d4d4d4',
|
||||
textSecondary: '#808080',
|
||||
textMuted: '#505050',
|
||||
border: '#1a1a1a',
|
||||
accent: '#ffffff',
|
||||
btnPrimaryBg: '#ffffff',
|
||||
btnPrimaryText: '#0a0a0a',
|
||||
btnPrimaryHover: '#d4d4d4',
|
||||
tooltipBg: '#141414',
|
||||
tooltipText: '#d4d4d4',
|
||||
keyBg: 'rgba(255,255,255,0.08)',
|
||||
},
|
||||
},
|
||||
|
||||
current: 'dark',
|
||||
@@ -1102,29 +1142,31 @@ const theme = {
|
||||
sepia: 'Sepia',
|
||||
nord: 'Nord',
|
||||
dracula: 'Dracula',
|
||||
abyss: 'Abyss'
|
||||
abyss: 'Abyss',
|
||||
};
|
||||
return Object.keys(this.themes).map(key => ({
|
||||
value: key,
|
||||
name: names[key] || key,
|
||||
colors: this.themes[key]
|
||||
colors: this.themes[key],
|
||||
}));
|
||||
},
|
||||
|
||||
hexToRgb(hex) {
|
||||
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
||||
return result ? {
|
||||
r: parseInt(result[1], 16),
|
||||
g: parseInt(result[2], 16),
|
||||
b: parseInt(result[3], 16)
|
||||
} : { r: 30, g: 30, b: 30 };
|
||||
return result
|
||||
? {
|
||||
r: parseInt(result[1], 16),
|
||||
g: parseInt(result[2], 16),
|
||||
b: parseInt(result[3], 16),
|
||||
}
|
||||
: { r: 30, g: 30, b: 30 };
|
||||
},
|
||||
|
||||
lightenColor(rgb, amount) {
|
||||
return {
|
||||
r: Math.min(255, rgb.r + amount),
|
||||
g: Math.min(255, rgb.g + amount),
|
||||
b: Math.min(255, rgb.b + amount)
|
||||
b: Math.min(255, rgb.b + amount),
|
||||
};
|
||||
},
|
||||
|
||||
@@ -1132,7 +1174,7 @@ const theme = {
|
||||
return {
|
||||
r: Math.max(0, rgb.r - amount),
|
||||
g: Math.max(0, rgb.g - amount),
|
||||
b: Math.max(0, rgb.b - amount)
|
||||
b: Math.max(0, rgb.b - amount),
|
||||
};
|
||||
},
|
||||
|
||||
@@ -1212,7 +1254,7 @@ const theme = {
|
||||
async save(themeName) {
|
||||
await storage.updatePreference('theme', themeName);
|
||||
this.apply(themeName);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// Consolidated cheatingDaddy object - all functions in one place
|
||||
|
||||
+7
-4
@@ -33,10 +33,10 @@ function createWindow(sendToRenderer, geminiSessionRef) {
|
||||
});
|
||||
|
||||
const { session, desktopCapturer } = require('electron');
|
||||
|
||||
|
||||
// Store selected source for Windows custom picker
|
||||
let selectedSourceId = null;
|
||||
|
||||
|
||||
// Setup display media handler based on platform
|
||||
if (process.platform === 'darwin') {
|
||||
// macOS: Use native system picker
|
||||
@@ -553,7 +553,10 @@ function setupWindowIpcHandlers(mainWindow, sendToRenderer, geminiSessionRef) {
|
||||
const primaryDisplay = screen.getPrimaryDisplay();
|
||||
|
||||
// Calculate bounds that cover all displays
|
||||
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
||||
let minX = Infinity,
|
||||
minY = Infinity,
|
||||
maxX = -Infinity,
|
||||
maxY = -Infinity;
|
||||
displays.forEach(display => {
|
||||
minX = Math.min(minX, display.bounds.x);
|
||||
minY = Math.min(minY, display.bounds.y);
|
||||
@@ -712,7 +715,7 @@ function setupWindowIpcHandlers(mainWindow, sendToRenderer, geminiSessionRef) {
|
||||
|
||||
regionSelectionWindow.loadURL(`data:text/html;charset=utf-8,${encodeURIComponent(htmlContent)}`);
|
||||
|
||||
return new Promise((resolve) => {
|
||||
return new Promise(resolve => {
|
||||
ipcMain.once('region-selected', (event, rect) => {
|
||||
if (regionSelectionWindow && !regionSelectionWindow.isDestroyed()) {
|
||||
regionSelectionWindow.close();
|
||||
|
||||
@@ -12,4 +12,4 @@ export async function resizeLayout() {
|
||||
} catch (error) {
|
||||
console.error('Error resizing window:', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user