@namastexlabs/speak
Version:
Open source voice dictation for everyone
148 lines (126 loc) • 4.6 kB
JavaScript
const { ipcRenderer } = require('electron');
// Welcome screen functionality
document.addEventListener('DOMContentLoaded', () => {
console.log('Welcome screen loaded');
// Check if we already have an API key
checkExistingSetup();
});
// Check if API key is already configured
async function checkExistingSetup() {
try {
const settings = await ipcRenderer.invoke('get-settings');
if (settings.apiKey && settings.apiKey !== '***configured***') {
// API key exists, pre-fill it
document.getElementById('api-key').value = settings.apiKey;
}
} catch (error) {
console.warn('Failed to check existing setup:', error);
}
}
// Test API key functionality
async function testApiKey() {
const apiKey = document.getElementById('api-key').value.trim();
if (!apiKey) {
showStatus('api-status', 'Please enter an API key first', 'error');
return;
}
showStatus('api-status', 'Testing API key...', 'info');
try {
const result = await ipcRenderer.invoke('test-api-key', apiKey);
if (result.valid) {
showStatus('api-status', '✅ API key is valid!', 'success');
} else {
showStatus('api-status', '❌ API key is invalid: ' + result.error, 'error');
}
} catch (error) {
showStatus('api-status', '❌ Failed to test API key: ' + error.message, 'error');
}
}
// Save API key and continue
async function saveApiKey() {
const apiKey = document.getElementById('api-key').value.trim();
if (!apiKey) {
showStatus('api-status', 'Please enter an API key', 'error');
return;
}
try {
await ipcRenderer.invoke('update-settings', { apiKey });
showStatus('api-status', '✅ API key saved successfully!', 'success');
// Clear any previous error status after a delay
setTimeout(() => {
document.getElementById('api-status').style.display = 'none';
}, 2000);
} catch (error) {
showStatus('api-status', '❌ Failed to save API key: ' + error.message, 'error');
}
}
// Complete setup and start the app
async function completeSetup() {
try {
// Mark first run as complete
await ipcRenderer.invoke('update-settings', { firstRun: false });
// Request microphone permission
await requestMicrophonePermission();
// Close welcome screen and show main app
ipcRenderer.invoke('complete-welcome');
} catch (error) {
console.error('Failed to complete setup:', error);
showStatus('api-status', '❌ Setup failed: ' + error.message, 'error');
}
}
// Request microphone permission
async function requestMicrophonePermission() {
try {
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
// Stop the stream immediately - we just wanted permission
stream.getTracks().forEach(track => track.stop());
console.log('Microphone permission granted');
} catch (error) {
console.warn('Microphone permission denied or failed:', error);
// Don't block setup for this - user can grant later
}
}
// Skip welcome screen
function skipWelcome() {
ipcRenderer.invoke('skip-welcome');
}
// Utility function to show status messages
function showStatus(elementId, message, type) {
const statusElement = document.getElementById(elementId);
statusElement.className = 'status ' + type;
statusElement.textContent = message;
statusElement.style.display = 'block';
// Auto-hide success messages after 3 seconds
if (type === 'success') {
setTimeout(() => {
statusElement.style.display = 'none';
}, 3000);
}
}
// Handle keyboard shortcuts
document.addEventListener('keydown', (event) => {
// Ctrl+Enter or Cmd+Enter to complete setup
if ((event.ctrlKey || event.metaKey) && event.key === 'Enter') {
event.preventDefault();
completeSetup();
}
// Escape to skip
if (event.key === 'Escape') {
event.preventDefault();
skipWelcome();
}
});
// Auto-focus API key input
document.addEventListener('DOMContentLoaded', () => {
const apiKeyInput = document.getElementById('api-key');
if (apiKeyInput) {
apiKeyInput.focus();
}
});
// Handle external links
document.addEventListener('click', (event) => {
if (event.target.tagName === 'A' && event.target.href.startsWith('http')) {
event.preventDefault();
ipcRenderer.invoke('open-external', event.target.href);
}
});