// مدیریت رابط کاربری (مدال‌ها، شیت‌ها، تغییر صفحات) async function loadHome() { document.getElementById('homeScreen').style.display = 'flex'; document.getElementById('editorScreen').style.display = 'none'; if (!db) { try { await initDB(); } catch(e) { console.error("DB Init Failed inside loadHome"); return; } } const tx = db.transaction("projects", "readonly"); const store = tx.objectStore("projects"); const req = store.getAll(); req.onsuccess = (e) => { let projects = e.target.result; projects.sort((a, b) => b.id - a.id); const grid = document.getElementById('projectsGrid'); const placeholder = document.getElementById('noProjectsPlaceholder'); if (projects.length === 0) { grid.innerHTML = ''; placeholder.style.display = 'flex'; } else { placeholder.style.display = 'none'; grid.innerHTML = ''; projects.forEach((p, index) => { const card = document.createElement('div'); card.className = 'project-card'; card.onclick = () => openProject(p.id); const thumbUrl = p.thumbnail ? `url(${p.thumbnail})` : 'none'; card.innerHTML = `
${p.duration || '00:00'}
${p.name}
${p.dateStr}
`; grid.appendChild(card); }); } }; } function openActionSheet(id, name, event) { event.stopPropagation(); currentActionProjectId = id; currentActionProjectName = name; const sheet = document.getElementById('projectActionOverlay'); sheet.style.display = 'flex'; } function closeActionSheet() { const sheet = document.getElementById('projectActionOverlay'); sheet.style.display = 'none'; } function openDeleteConfirmation() { closeActionSheet(); showConfirmationModal({ iconClass: 'fa-solid fa-trash-can', title: 'حذف پروژه', description: `آیا از حذف کامل «${currentActionProjectName}» مطمئن هستید؟`, confirmText: 'بله، حذف کن', confirmClass: 'delete', onConfirm: () => { const tx = db.transaction("projects", "readwrite"); const store = tx.objectStore("projects"); // ابتدا دریافت پروژه از دیتابیس مرورگر برای پیدا کردن شناسه سرور (file_id) store.get(currentActionProjectId).onsuccess = (e) => { const project = e.target.result; if (project && project.state && project.state.id) { const fileId = project.state.id; // ارسال درخواست حذف به سرور در پس‌زمینه (بدون معطل کردن کاربر) fetch(`/api/delete-project/${fileId}`, { method: 'DELETE' }) .catch(err => console.error("Failed to delete project files on server:", err)); } // حذف پروژه از دیتابیس محلی مرورگر store.delete(currentActionProjectId); }; tx.oncomplete = () => loadHome(); } }); } function openRenameModal() { closeActionSheet(); const modal = document.getElementById('renameModal'); const input = document.getElementById('renameInput'); input.value = currentActionProjectName; modal.style.display = 'flex'; setTimeout(() => modal.classList.add('show'), 10); } function closeRenameModal() { const modal = document.getElementById('renameModal'); modal.classList.remove('show'); setTimeout(() => modal.style.display = 'none', 300); } function saveRename() { const newName = document.getElementById('renameInput').value.trim(); if (newName && currentActionProjectId) { const tx = db.transaction("projects", "readwrite"); const store = tx.objectStore("projects"); store.get(currentActionProjectId).onsuccess = (e) => { const project = e.target.result; if (project) { project.name = newName; store.put(project); } }; tx.oncomplete = () => { closeRenameModal(); loadHome(); }; } else { closeRenameModal(); } } function toggleTool(toolName) { document.querySelectorAll('.tool-btn').forEach(b => b.classList.remove('active-tool')); const btnId = 'btn-' + toolName; const btn = document.getElementById(btnId); const sectionId = 'section-' + toolName; const section = document.getElementById(sectionId); const isAlreadyOpen = toolsContainer.classList.contains('open') && section.style.display === 'block'; if (isAlreadyOpen) { toolsContainer.classList.remove('open'); setTimeout(() => { section.style.display = 'none'; }, 200); } else { document.querySelectorAll('.tool-section').forEach(s => s.style.display = 'none'); if(btn) btn.classList.add('active-tool'); section.style.display = 'block'; section.classList.add('active-section'); toolsContainer.classList.add('open'); if(toolName === 'text') { toolsContainer.style.maxHeight = 'none'; renderSegList(); if (state.segs && state.segs.length > 0) { let sIdxToSelect = 0; const curTime = v.currentTime; const currentSegIdx = state.segs.findIndex(s => curTime >= s.start && curTime <= s.end); if (currentSegIdx !== -1) sIdxToSelect = currentSegIdx; else { const nextSegIdx = state.segs.findIndex(s => s.start > curTime); if (nextSegIdx !== -1) sIdxToSelect = nextSegIdx; } setTimeout(() => { if (state.segs[sIdxToSelect] && state.segs[sIdxToSelect].words.length > 0) { highlightWord(sIdxToSelect, 0, true); } }, 50); } } else { toolsContainer.style.maxHeight = ''; } } } function toggleCustomAccordion() { document.getElementById('customAccordion').classList.toggle('open'); } function closeAllSheets() { const overlay = document.getElementById('sheetOverlay'); overlay.classList.remove('show'); document.querySelectorAll('.bottom-sheet').forEach(s => { s.classList.remove('active'); }); document.getElementById('textInput').blur(); if(previewInterval) clearInterval(previewInterval); v.pause(); const icon1 = document.getElementById('btnPreviewPlay')?.querySelector('i'); if(icon1) icon1.className = "fa-solid fa-play"; const icon2 = document.getElementById('btnTimeSheetPlayIcon'); if(icon2) icon2.className = "fa-solid fa-play"; } function openSheet(type) { if (!activeWordId && type !== 'regenerate' && type !== 'wordcount') return; closeAllSheets(); const targetSheet = document.getElementById(`sheet-${type}`); const overlay = document.getElementById('sheetOverlay'); if(type === 'text') { const [sIdx, wIdx] = activeWordId.split('-').map(Number); const seg = state.segs[sIdx]; const word = seg.words[wIdx]; document.getElementById('textInput').value = word.word; document.getElementById('textTimeDisplay').innerText = `${fmt(word.start)} -> ${fmt(word.end)}`; } else if(type === 'time') { const [sIdx, wIdx] = activeWordId.split('-').map(Number); const seg = state.segs[sIdx]; const word = seg.words[wIdx]; tempStartTime = word.start; tempEndTime = word.end; document.getElementById('timeSheetWord').innerText = word.word; const prevBox = document.getElementById('prevWordPreview'); const nextBox = document.getElementById('nextWordPreview'); // محاسبه محدوده مجاز (Boundary) let minAllowed = 0; let maxAllowed = v.duration || 1000; // محاسبه کلمه قبل و حد پایین if (wIdx > 0) { prevBox.innerText = seg.words[wIdx - 1].word; minAllowed = seg.words[wIdx - 1].end; } else if (sIdx > 0 && state.segs[sIdx-1].words.length > 0) { const prevSeg = state.segs[sIdx-1]; prevBox.innerText = prevSeg.words[prevSeg.words.length - 1].word; minAllowed = prevSeg.words[prevSeg.words.length - 1].end; } else { prevBox.innerText = "-"; minAllowed = 0; } // محاسبه کلمه بعد و حد بالا if (wIdx < seg.words.length - 1) { nextBox.innerText = seg.words[wIdx + 1].word; maxAllowed = seg.words[wIdx + 1].start; } else if (sIdx < state.segs.length - 1 && state.segs[sIdx+1].words.length > 0) { nextBox.innerText = state.segs[sIdx+1].words[0].word; maxAllowed = state.segs[sIdx+1].words[0].start; } else { nextBox.innerText = "-"; maxAllowed = v.duration || tempEndTime + 5; } // راه‌اندازی Trimmer با محدوده‌های دقیق if(typeof initTrimmerUI === 'function') { initTrimmerUI(tempStartTime, tempEndTime, minAllowed, maxAllowed); } } else if(type === 'delete') { const [sIdx, wIdx] = activeWordId.split('-').map(Number); const seg = state.segs[sIdx]; const word = seg.words[wIdx]; document.getElementById('deleteMsgText').innerHTML = `آیا کلمه «${word.word}» حذف شود؟`; } else if (type === 'regenerate') { if (typeof isRegenerating !== 'undefined' && isRegenerating) { document.getElementById('regen-step-start').style.display = 'none'; document.getElementById('regen-step-loading').style.display = 'flex'; document.getElementById('regen-step-success').style.display = 'none'; } else { document.getElementById('regen-step-start').style.display = 'flex'; document.getElementById('regen-step-loading').style.display = 'none'; document.getElementById('regen-step-success').style.display = 'none'; } } setTimeout(() => { overlay.classList.add('show'); targetSheet.classList.add('active'); }, 50); } function preConfirmRegenerate() { showConfirmationModal({ iconClass: 'fa-solid fa-rotate', title: 'بازنویسی هوشمند', description: 'آیا می‌خواهید هوش مصنوعی دوباره ویدیو را بررسی کرده و زیرنویس‌ها را از نو بنویسد؟ (زیرنویس‌های فعلی حذف می‌شوند)', confirmText: 'بله، بازنویسی کن', confirmClass: 'split', onConfirm: () => { regenerateProjectSubtitles(); } }); } function showConfirmationModal(config) { const modal = document.getElementById('confirmationModal'); document.getElementById('confirmIcon').querySelector('i').className = config.iconClass; document.getElementById('confirmTitle').innerText = config.title; document.getElementById('confirmDesc').innerText = config.description; const btn = document.getElementById('confirmBtn'); btn.innerText = config.confirmText; btn.className = 'modal-btn btn-confirm-action ' + config.confirmClass; btn.onclick = () => { config.onConfirm(); closeConfirmationModal(); }; modal.style.display = 'flex'; setTimeout(() => modal.classList.add('show'), 10); } function closeConfirmationModal() { const m = document.getElementById('confirmationModal'); m.classList.remove('show'); setTimeout(() => m.style.display = 'none', 300); }