Add admin sound preferences

This commit is contained in:
rajchales-monito
2026-07-24 14:52:20 +02:00
parent 1d6d478993
commit 3f709f3a4e
3 changed files with 183 additions and 65 deletions
+88 -26
View File
@@ -11,6 +11,7 @@ const state = {
hideBots: localStorage.getItem("mf_admin_hide_bots") !== "0",
soundMuted: localStorage.getItem("mf_admin_sound_muted") === "1",
soundVolume: Number(localStorage.getItem("mf_admin_sound_volume") || 70),
soundStyle: localStorage.getItem("mf_admin_sound_style") || "bright",
replyFiles: [],
attentionTimer: null,
attentionOn: false,
@@ -48,22 +49,35 @@ $("#logoutButton").addEventListener("click", async () => {
location.reload();
});
$("#settingsButton").addEventListener("click", () => $("#settingsPanel").classList.remove("hidden"));
$("#settingsButton").addEventListener("click", () => $("#settingsPanel").classList.toggle("hidden"));
$("#closeSettingsButton").addEventListener("click", () => $("#settingsPanel").classList.add("hidden"));
$("#adminSoundToggle").addEventListener("click", () => {
state.soundMuted = !state.soundMuted;
if (!state.soundMuted && state.soundVolume <= 0) state.soundVolume = 70;
localStorage.setItem("mf_admin_sound_muted", state.soundMuted ? "1" : "0");
localStorage.setItem("mf_admin_sound_volume", String(state.soundVolume));
renderAdminSoundControls();
setAdminSoundMuted(!state.soundMuted);
});
$("#adminSoundVolume").addEventListener("input", (event) => {
state.soundVolume = clamp(Number(event.target.value), 0, 100);
state.soundMuted = state.soundVolume <= 0;
localStorage.setItem("mf_admin_sound_volume", String(state.soundVolume));
localStorage.setItem("mf_admin_sound_muted", state.soundMuted ? "1" : "0");
setAdminSoundVolume(Number(event.target.value));
});
$("#adminSoundToggleSettings").addEventListener("change", (event) => {
setAdminSoundMuted(!event.target.checked);
});
$("#adminSoundVolumeSettings").addEventListener("input", (event) => {
setAdminSoundVolume(Number(event.target.value));
});
$("#adminSoundStyle").addEventListener("change", (event) => {
state.soundStyle = event.target.value;
localStorage.setItem("mf_admin_sound_style", state.soundStyle);
renderAdminSoundControls();
});
$("#adminSoundTest").addEventListener("click", () => {
playNotifySound({ ignoreMuted: true });
});
document.querySelectorAll("[data-settings-tab]").forEach((button) => {
button.addEventListener("click", () => {
const tab = button.dataset.settingsTab;
document.querySelectorAll("[data-settings-tab]").forEach((item) => item.classList.toggle("active", item === button));
document.querySelectorAll("[data-settings-panel]").forEach((panel) => panel.classList.toggle("active", panel.dataset.settingsPanel === tab));
});
});
$("#settingsForm").brand.addEventListener("input", (event) => {
$("#settingsForm").brandHex.value = normalizeHexColor(event.target.value) || event.target.value;
});
@@ -795,33 +809,81 @@ function notify() {
function renderAdminSoundControls() {
const toggle = $("#adminSoundToggle");
const volume = $("#adminSoundVolume");
if (!toggle || !volume) return;
const settingsToggle = $("#adminSoundToggleSettings");
const settingsVolume = $("#adminSoundVolumeSettings");
const settingsStyle = $("#adminSoundStyle");
const safeVolume = clamp(state.soundVolume, 0, 100);
toggle.classList.toggle("muted", state.soundMuted || safeVolume <= 0);
toggle.setAttribute("aria-label", state.soundMuted ? "Zapnout zvuk notifikaci" : "Vypnout zvuk notifikaci");
toggle.title = state.soundMuted ? "Zapnout zvuk notifikaci" : "Vypnout zvuk notifikaci";
volume.value = String(safeVolume);
volume.title = `Hlasitost ${safeVolume}%`;
if (toggle) {
toggle.classList.toggle("muted", state.soundMuted || safeVolume <= 0);
toggle.setAttribute("aria-label", state.soundMuted ? "Zapnout zvuk notifikaci" : "Vypnout zvuk notifikaci");
toggle.title = state.soundMuted ? "Zapnout zvuk notifikaci" : "Vypnout zvuk notifikaci";
}
if (volume) {
volume.value = String(safeVolume);
volume.title = `Hlasitost ${safeVolume}%`;
}
if (settingsToggle) settingsToggle.checked = !state.soundMuted;
if (settingsVolume) settingsVolume.value = String(safeVolume);
if (settingsStyle) settingsStyle.value = state.soundStyle;
}
function playNotifySound() {
function setAdminSoundMuted(isMuted) {
state.soundMuted = Boolean(isMuted);
if (!state.soundMuted && state.soundVolume <= 0) state.soundVolume = 70;
localStorage.setItem("mf_admin_sound_muted", state.soundMuted ? "1" : "0");
localStorage.setItem("mf_admin_sound_volume", String(state.soundVolume));
renderAdminSoundControls();
}
function setAdminSoundVolume(value) {
state.soundVolume = clamp(value, 0, 100);
state.soundMuted = state.soundVolume <= 0;
localStorage.setItem("mf_admin_sound_volume", String(state.soundVolume));
localStorage.setItem("mf_admin_sound_muted", state.soundMuted ? "1" : "0");
renderAdminSoundControls();
}
function playNotifySound(options = {}) {
const volume = clamp(state.soundVolume, 0, 100);
if (state.soundMuted || volume <= 0) return;
if (!options.ignoreMuted && (state.soundMuted || volume <= 0)) return;
const AudioCtor = window.AudioContext || window.webkitAudioContext;
if (!AudioCtor) return;
const audio = new AudioCtor();
const gain = audio.createGain();
gain.gain.value = 0.12 * (volume / 100);
gain.gain.value = 0.12 * ((volume || 70) / 100);
gain.connect(audio.destination);
[0, 0.14].forEach((offset, index) => {
for (const tone of soundPattern(state.soundStyle)) {
const osc = audio.createOscillator();
osc.type = "sine";
osc.frequency.value = index ? 1040 : 820;
osc.type = tone.type;
osc.frequency.value = tone.frequency;
osc.connect(gain);
osc.start(audio.currentTime + offset);
osc.stop(audio.currentTime + offset + 0.11);
});
setTimeout(() => audio.close().catch(() => {}), 520);
osc.start(audio.currentTime + tone.offset);
osc.stop(audio.currentTime + tone.offset + tone.duration);
}
setTimeout(() => audio.close().catch(() => {}), 720);
}
function soundPattern(style) {
const patterns = {
soft: [
{ offset: 0, duration: 0.13, frequency: 520, type: "sine" },
{ offset: 0.16, duration: 0.12, frequency: 680, type: "sine" }
],
chime: [
{ offset: 0, duration: 0.16, frequency: 880, type: "triangle" },
{ offset: 0.18, duration: 0.18, frequency: 1320, type: "triangle" }
],
urgent: [
{ offset: 0, duration: 0.1, frequency: 760, type: "square" },
{ offset: 0.13, duration: 0.1, frequency: 760, type: "square" },
{ offset: 0.26, duration: 0.12, frequency: 980, type: "square" }
],
bright: [
{ offset: 0, duration: 0.11, frequency: 820, type: "sine" },
{ offset: 0.14, duration: 0.11, frequency: 1040, type: "sine" }
]
};
return patterns[style] || patterns.bright;
}
function clamp(value, min, max) {