update sound

This commit is contained in:
Flatlogic Bot 2026-04-01 10:05:01 +00:00
parent f81da63413
commit 5f6b8289df
4 changed files with 105 additions and 8 deletions

View File

@ -84,7 +84,7 @@ document.addEventListener('DOMContentLoaded', () => {
fullscreenButton.hidden = true;
}
let audioCtx = null;
let audioCtx = null;
const initAudio = () => {
try {
const AudioContext = window.AudioContext || window.webkitAudioContext;
@ -99,14 +99,23 @@ document.addEventListener('DOMContentLoaded', () => {
}
};
let availableVoices = [];
if ('speechSynthesis' in window) {
const updateVoices = () => { availableVoices = window.speechSynthesis.getVoices(); };
updateVoices();
if (window.speechSynthesis.onvoiceschanged !== undefined) {
window.speechSynthesis.onvoiceschanged = updateVoices;
}
}
const audioBtn = document.querySelector('.js-audio-toggle');
if (audioBtn) {
const updateAudioBtnState = () => {
const isEnabled = window.localStorage.getItem('hospitalQueue:audioEnabled') === 'true';
if (isEnabled) {
audioBtn.innerHTML = '<i class="bi bi-volume-up"></i>';
audioBtn.innerHTML = '<i class="bi bi-megaphone-fill"></i>';
} else {
audioBtn.innerHTML = '<i class="bi bi-volume-mute"></i>';
audioBtn.innerHTML = '<i class="bi bi-megaphone"></i>';
}
audioBtn.setAttribute('aria-pressed', isEnabled.toString());
@ -183,10 +192,10 @@ document.addEventListener('DOMContentLoaded', () => {
setTimeout(() => {
const text = locale === 'ar' ? (latest.dataset.announcementAr || '') : (latest.dataset.announcementEn || '');
if (text) {
window.speechSynthesis.cancel();
// Removed window.speechSynthesis.cancel(); as it can prevent speech in some browsers
const utterance = new SpeechSynthesisUtterance(text);
utterance.lang = locale === 'ar' ? 'ar-SA' : 'en-US';
const voices = window.speechSynthesis.getVoices();
const voices = availableVoices.length > 0 ? availableVoices : window.speechSynthesis.getVoices();
const langPrefix = locale === 'ar' ? 'ar' : 'en';
const langVoices = voices.filter(v => v.lang.toLowerCase().startsWith(langPrefix));
@ -218,7 +227,7 @@ document.addEventListener('DOMContentLoaded', () => {
}
};
checkAnnouncements();
checkAnnouncements();
const autoRefreshSeconds = parseInt(document.querySelector('[data-auto-refresh]')?.dataset.autoRefresh || '0', 10);
if (autoRefreshSeconds > 0) {
@ -252,4 +261,4 @@ document.addEventListener('DOMContentLoaded', () => {
}, autoRefreshSeconds * 1000);
}
}
});
});

View File

@ -60,7 +60,7 @@ qh_page_start(
<div class="d-flex align-items-center gap-3">
<div class="fs-5 fw-bold text-dark js-live-clock"><?= qh_h(date('H:i')) ?></div>
<button type="button" class="btn btn-outline-secondary btn-sm shadow-sm me-2 js-audio-toggle" id="globalAudioToggle" title="<?= qh_h(qh_t('Toggle Audio', 'تبديل الصوت')) ?>">
<i class="bi bi-volume-mute"></i>
<i class="bi bi-megaphone"></i>
</button>
<button type="button" class="btn btn-outline-secondary btn-sm shadow-sm js-fullscreen-toggle" aria-pressed="false" data-label-enter="<?= qh_h(qh_t('Fullscreen', 'ملء الشاشة')) ?>" data-label-exit="<?= qh_h(qh_t('Exit fullscreen', 'إنهاء ملء الشاشة')) ?>"><i class="bi bi-arrows-fullscreen"></i></button>
</div>

87
patch_audio.js Normal file
View File

@ -0,0 +1,87 @@
const fs = require('fs');
const path = require('path');
const jsPath = path.join(__dirname, 'assets/js/main.js');
let jsCode = fs.readFileSync(jsPath, 'utf8');
// Replace the icon logic
jsCode = jsCode.replace(
/audioBtn\.innerHTML = '<i class="bi bi-volume-up"><\/i>';/g,
`audioBtn.innerHTML = '<i class="bi bi-megaphone-fill text-success"></i>';`
).replace(
/audioBtn\.innerHTML = '<i class="bi bi-volume-mute"><\/i>';/g,
`audioBtn.innerHTML = '<i class="bi bi-megaphone"></i>';`
);
// Add logic to test sound when audio is enabled
const repl1 = `if (nextState) {
initAudio();
if ('speechSynthesis' in window) {
const primeUtterance = new SpeechSynthesisUtterance('');
window.speechSynthesis.speak(primeUtterance);
}
}`;
const repl2 = `if (nextState) {
initAudio();
if ('speechSynthesis' in window) {
const primeUtterance = new SpeechSynthesisUtterance('');
window.speechSynthesis.speak(primeUtterance);
}
// Force latest announcement to replay
const cards = Array.from(document.querySelectorAll('.announcement-card'));
const latest = cards[0];
if (latest) {
const storageKey =
`hospitalQueue:lastAnnouncement:${locale}
`;
window.localStorage.removeItem(storageKey);
setTimeout(checkAnnouncements, 200);
}
}`;
jsCode = jsCode.replace(repl1, repl2);
// Make sure speech synthesis gets voices early, and handle fallback properly
const oldVoiceLogic = `if (langVoices.length > 0) {
// Try to find a high-quality (Google/Microsoft Natural) voice
const bestVoice = langVoices.find(v =>
v.name.includes('Google') ||
v.name.includes('Natural') ||
v.name.includes('Premium') ||
v.name.includes('Online')
) || langVoices.find(v => v.name.includes('Microsoft')) || langVoices[0];
utterance.voice = bestVoice;
}`;
const newVoiceLogic = `if (langVoices.length > 0) {
// Try to find a high-quality (Google/Microsoft Natural) voice
const bestVoice = langVoices.find(v =>
v.name.includes('Google') ||
v.name.includes('Natural') ||
v.name.includes('Premium') ||
v.name.includes('Online')
) || langVoices.find(v => v.name.includes('Microsoft')) || langVoices[0];
utterance.voice = bestVoice;
} else if (voices.length > 0) {
// Fallback to any available voice to ensure sound plays
utterance.voice = voices[0];
}`;
jsCode = jsCode.replace(oldVoiceLogic, newVoiceLogic);
// Call getVoices early
if (!jsCode.includes('window.speechSynthesis.getVoices();')) {
jsCode = jsCode.replace(
`document.addEventListener('DOMContentLoaded', () => {`,
`document.addEventListener('DOMContentLoaded', () => {
if ('speechSynthesis' in window) {
window.speechSynthesis.onvoiceschanged = () => { window.speechSynthesis.getVoices(); };
window.speechSynthesis.getVoices();
}`
);
}
fs.writeFileSync(jsPath, jsCode);
console.log('patched');

View File

@ -625,6 +625,7 @@ function qh_page_start(string $activePage, string $pageTitle, string $metaDescri
}
echo ' <meta name="theme-color" content="' . qh_h($primaryColor) . '">';
echo ' <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">';
echo ' <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">';
echo ' <link rel="stylesheet" href="assets/css/custom.css?v=' . $assetVersionCss . '">';
echo ' <style>:root{--accent:' . qh_h($primaryColor) . ';--accent-strong:' . qh_h($secondaryColor) . ';}</style>';
echo '</head>';