حذف الكل
'exportBtn');
const filter = $('filter');
const clearAll = $('clearAll');
const browserInfo = $('browserInfo');
browserInfo.textContent = navigator.userAgent;
// Storage
const STORAGE_KEY = 'voice_notes_v1';
function loadNotes(){
try{const raw = localStorage.getItem(STORAGE_KEY); return raw?JSON.parse(raw):[];}catch(e){return []}
}
function saveNotes(notes){localStorage.setItem(STORAGE_KEY, JSON.stringify(notes))}
let notes = loadNotes();
// Speech recognition (Web Speech API)
let recognition = null;
let recognizing = false;
let finalTranscript = '';
function setupRecognition(){
const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition || null;
if(!SpeechRecognition) return null;
const r = new SpeechRecognition();
r.lang = 'ar-EG';
r.interimResults = true;
r.continuous = true;
r.maxAlternatives = 1;
r.onstart = ()=>{recognizing=true;statusEl.textContent='يسجل (تحويل نصي)';micDot.classList.add('active');}
r.onend = ()=>{recognizing=false;statusEl.textContent='متوقف';micDot.classList.remove('active');}
r.onerror = (e)=>{console.error('speech error',e);statusEl.textContent='خطأ: '+(e.error||e.message)}
r.onresult = (event)=>{
let interim='';
for(let i=event.resultIndex;i{
finalTranscript='';
interimEl.textContent='استمع...';
const ok = await ensureMic();
if(!ok){alert('يرجى السماح بصلاحية الميكروفون من المتصفح');return}
if(recognition){
try{recognition.start();}catch(e){console.warn(e);}
}
// start recording audio too (for fallback / download)
if(mediaRecorder){
chunks = [];
mediaRecorder.ondataavailable = e=>{ if(e.data && e.data.size) chunks.push(e.data) };
mediaRecorder.onstop = ()=>{
// create blob URL and attach to the last saved note when user saves
const blob = new Blob(chunks,{type:'audio/webm'});
// store temporarily in memory
window._lastRecordedAudio = blob;
}
try{mediaRecorder.start();}catch(e){console.warn('media start err',e)}
}
statusEl.textContent='يعمل...';
});
stopBtn.addEventListener('click', ()=>{
if(recognition && recognizing){ try{recognition.stop();}catch(e){} }
if(mediaRecorder && mediaRecorder.state!=='inactive'){ try{mediaRecorder.stop();}catch(e){} }
statusEl.textContent='متوقف';
});
saveBtn.addEventListener('click', ()=>{
const text = noteEdit.value.trim() || interimEl.textContent.trim();
if(!text){alert('النص فارغ — تحدث أولاً ثم احفظ.');return}
const ts = formatDate(new Date());
const note = {id:Date.now(), text, created_at:ts};
// attach audio blob if available
if(window._lastRecordedAudio){
// store in IndexedDB is better, but for simplicity we store as Object URL and keep in memory
// convert blob to base64 (careful: could be large). We'll store as object URL and not persist across reloads.
note.audioURL = URL.createObjectURL(window._lastRecordedAudio);
// clear temp
delete window._lastRecordedAudio;
}
notes.unshift(note);
saveNotes(notes);
renderNotes();
interimEl.textContent = 'تم الحفظ.';
noteEdit.value='';
finalTranscript='';
});
clearBtn.addEventListener('click', ()=>{noteEdit.value=''; interimEl.textContent='اضغط "ابدأ التسجيل" ثم تحدث — ستظهر الملاحظات هنا.'});
// rendering
function renderNotes(filterTerm=''){
notesList.innerHTML='';
const filtered = notes.filter(n=>n.text.includes(filterTerm));
if(filtered.length===0){ notesList.innerHTML='لا توجد ملاحظات.
'; return }
for(const n of filtered){
const card = document.createElement('div'); card.className='note';
const meta = document.createElement('div'); meta.className='meta';
meta.innerHTML = `${n.created_at}
#${n.id}
`;
const p = document.createElement('p'); p.textContent = n.text;
const actions = document.createElement('div'); actions.className='actions';
const play = document.createElement('button'); play.className='small btn-ghost'; play.textContent='استماع';
play.onclick = ()=>{
if(n.audioURL){ const a = new Audio(n.audioURL); a.play(); }
else alert('لا يوجد تسجيل صوتي لهذه الملاحظة.');
}
document.createElement('a'); a.href = url; a.download = 'voice-notes.json'; a.click(); URL.revokeObjectURL(url);
});
// Accessibility / hint
document.addEventListener('keydown', (e)=>{ if((e.ctrlKey||e.metaKey) && e.key==='k'){ e.preventDefault(); noteEdit.focus(); } });
// Helpful notice if SpeechRecognition not supported
if(!window.SpeechRecognition && !window.webkitSpeechRecognition){
// switch label
const notice = document.createElement('div'); notice.style.color='var(--muted)'; notice.style.marginTop='8px';
notice.textContent = 'تنبيه: ميزة التحويل الصوتي الفوري غير مدعومة في متصفحك. نوصي باستخدام Chrome أو Edge للتعرّف على الكلام.';
document.querySelector('.card').appendChild(notice);
}