diff --git a/popup.js b/popup.js index 923b1a7..3ee8906 100644 --- a/popup.js +++ b/popup.js @@ -264,8 +264,6 @@ document.getElementById('autofill-btn').addEventListener('click', async () => { // ─── Voice Dictation ─────────────────────────────────────────────────────────── -// ─── Voice Dictation ─────────────────────────────────────────────────────────── - function initDictation() { const statusEl = document.getElementById('dictation-status'); const micBtn = document.getElementById('dictation-mic-btn'); @@ -276,6 +274,16 @@ function initDictation() { let finalTranscript = ''; let interimTranscript = ''; + function updateCopyBtnVisibility() { + if (resultArea.value.trim()) { + copyBtn.style.display = 'inline-flex'; + } else { + copyBtn.style.display = 'none'; + } + } + + resultArea.addEventListener('input', updateCopyBtnVisibility); + function stopRecording(process = true) { if (!isRecording) return; isRecording = false; @@ -283,6 +291,8 @@ function initDictation() { micBtn.style.background = 'linear-gradient(135deg, var(--accent), #9b5de5)'; micBtn.innerHTML = '🎤'; + updateCopyBtnVisibility(); + const textToProcess = resultArea.value.trim(); if (textToProcess && process) { statusEl.textContent = '✨ جارٍ التحسين بواسطة الذكاء الاصطناعي...'; @@ -305,6 +315,7 @@ function initDictation() { interimTranscript = message.payload.interimText || ''; finalTranscript = message.payload.finalText || ''; resultArea.value = (finalTranscript + interimTranscript).trim(); + updateCopyBtnVisibility(); } else if (message.type === 'SPEECH_ERROR') { console.error('Speech recognition error', message.payload.error); if (message.payload.error === 'not-allowed') { @@ -352,6 +363,9 @@ function initDictation() { return; } window.__ljaDictationActive = true; + window.__ljaSpeechUserStopped = false; + window.__ljaSpeechAccumulatedText = ''; + window.__ljaSpeechCurrentSessionFinalText = ''; const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition; if (!SpeechRecognition) { @@ -360,49 +374,87 @@ function initDictation() { return; } - const recognition = new SpeechRecognition(); - recognition.lang = lang; - recognition.continuous = true; - recognition.interimResults = true; - recognition.maxAlternatives = 1; + let recognition; - recognition.onstart = () => { - chrome.runtime.sendMessage({ type: 'SPEECH_START_SUCCESS' }); - }; + function startRecognition() { + if (window.__ljaSpeechUserStopped) return; - recognition.onresult = (event) => { - let interimText = ''; - let finalText = ''; + recognition = new SpeechRecognition(); + recognition.lang = lang; + recognition.continuous = true; + recognition.interimResults = true; + recognition.maxAlternatives = 1; - for (let i = 0; i < event.results.length; i++) { - const result = event.results[i]; - if (result.isFinal) { - finalText += result[0].transcript + ' '; - } else { - interimText += result[0].transcript; + recognition.onstart = () => { + chrome.runtime.sendMessage({ type: 'SPEECH_START_SUCCESS' }); + }; + + recognition.onresult = (event) => { + let interimText = ''; + let sessionFinalText = ''; + + for (let i = 0; i < event.results.length; i++) { + const result = event.results[i]; + if (result.isFinal) { + sessionFinalText += result[0].transcript + ' '; + } else { + interimText += result[0].transcript; + } } + + window.__ljaSpeechCurrentSessionFinalText = sessionFinalText; + + const fullFinalText = window.__ljaSpeechAccumulatedText + sessionFinalText; + + chrome.runtime.sendMessage({ + type: 'SPEECH_RESULT', + payload: { + interimText: interimText, + finalText: fullFinalText + } + }); + }; + + recognition.onerror = (event) => { + console.error('[LJA Dictation] Error:', event.error); + if (event.error === 'not-allowed') { + chrome.runtime.sendMessage({ type: 'SPEECH_ERROR', payload: { error: event.error } }); + window.__ljaDictationActive = false; + } else { + console.warn('[LJA Dictation] Recoverable error:', event.error); + } + }; + + recognition.onend = () => { + if (window.__ljaSpeechUserStopped) { + // User explicitly stopped + chrome.runtime.sendMessage({ type: 'SPEECH_END' }); + window.__ljaDictationActive = false; + } else { + // Ended due to browser timeout / silence, restart it + window.__ljaSpeechAccumulatedText += window.__ljaSpeechCurrentSessionFinalText; + window.__ljaSpeechCurrentSessionFinalText = ''; + console.log('[LJA Dictation] Silence/timeout. Restarting recognition...'); + setTimeout(() => { + if (!window.__ljaSpeechUserStopped) { + startRecognition(); + } + }, 150); + } + }; + + try { + recognition.start(); + } catch (e) { + chrome.runtime.sendMessage({ type: 'SPEECH_ERROR', payload: { error: e.message } }); + window.__ljaDictationActive = false; } - - chrome.runtime.sendMessage({ - type: 'SPEECH_RESULT', - payload: { interimText, finalText } - }); - }; - - recognition.onerror = (event) => { - console.error('[LJA Dictation] Error:', event.error); - chrome.runtime.sendMessage({ type: 'SPEECH_ERROR', payload: { error: event.error } }); - window.__ljaDictationActive = false; - }; - - recognition.onend = () => { - chrome.runtime.sendMessage({ type: 'SPEECH_END' }); - window.__ljaDictationActive = false; - }; + } // Listen for STOP message from popup const stopListener = (msg, sender, sendResponse) => { if (msg.type === 'STOP_RECORDING_FROM_POPUP') { + window.__ljaSpeechUserStopped = true; try { recognition.stop(); } catch(e) {} window.__ljaDictationActive = false; chrome.runtime.onMessage.removeListener(stopListener); @@ -411,12 +463,7 @@ function initDictation() { }; chrome.runtime.onMessage.addListener(stopListener); - try { - recognition.start(); - } catch (e) { - chrome.runtime.sendMessage({ type: 'SPEECH_ERROR', payload: { error: e.message } }); - window.__ljaDictationActive = false; - } + startRecognition(); }, args: ['ar-SA'] }).catch(err => { @@ -440,7 +487,7 @@ function initDictation() { const apiKey = document.getElementById('api-key-input').value.trim(); if (!apiKey) { statusEl.textContent = '⚠️ الرجاء إدخال مفتاح Gemini لتحسين النص'; - copyBtn.style.display = 'inline-flex'; + updateCopyBtnVisibility(); return; } @@ -481,13 +528,13 @@ CORRECTED TEXT:`; resultArea.value = processedText.trim(); statusEl.textContent = '✅ تم التحسين بنجاح! يمكنك النسخ الآن.'; - copyBtn.style.display = 'inline-flex'; + updateCopyBtnVisibility(); } else { throw new Error('Server error'); } } catch (e) { statusEl.textContent = '⚠️ فشل التحسين الذكي، نعرض النص الأصلي.'; - copyBtn.style.display = 'inline-flex'; + updateCopyBtnVisibility(); } } }