let isEditMode = false; let editingIndex = null; let tempFileData = null; let deferredPrompt; const installBtn = document.getElementById('installBtn'); const isFirefox = navigator.userAgent.toLowerCase().includes('firefox'); window.addEventListener('beforeinstallprompt', (e) => { // Empêche Chrome d'afficher sa propre mini-barre e.preventDefault(); // Stocke l'événement pour l'utiliser plus tard deferredPrompt = e; // Affiche votre bouton personnalisé installBtn.style.display = 'block'; installBtn.addEventListener('click', async () => { if (deferredPrompt) { // Montre la fenêtre d'installation native deferredPrompt.prompt(); // Attend la réponse de l'utilisateur const { outcome } = await deferredPrompt.userChoice; console.log(`L'utilisateur a répondu : ${outcome}`); // On nettoie deferredPrompt = null; installBtn.style.display = 'none'; } }); }); if (isFirefox && !window.matchMedia('(display-mode: standalone)').matches) { const infoZone = document.getElementById('app-version'); if (infoZone) { // Message plus pro-actif pour l'utilisateur infoZone.innerHTML += "
(Utilisez 'Installer' dans le menu Firefox)"; infoZone.style.color = "#ff8800"; } } // Cache le bouton si l'app est déjà installée window.addEventListener('appinstalled', () => { installBtn.style.display = 'none'; deferredPrompt = null; console.log('PWA installée avec succès !'); }); // Données pour 64 boutons (Grille 8x8) let btnData = JSON.parse(localStorage.getItem('sb_studio_data')) || Array(64).fill(null).map((_, i) => ({ id: i, name: "", file: null, loop: false, volume: 1 })); const players = {}; let draggedIndex = null; function handleDragStart(e, index) { draggedIndex = index; e.target.classList.add('dragging'); // On définit un transfert de données pour Firefox e.dataTransfer.setData('text/plain', index); } function handleDragOver(e) { e.preventDefault(); // Nécessaire pour permettre le drop return false; } function handleDrop(e, targetIndex) { e.preventDefault(); const targetElement = document.getElementById(`btn-${targetIndex}`); targetElement.classList.remove('drag-over'); if (draggedIndex === targetIndex) return; // --- LOGIQUE D'INVERSION --- // On inverse les données dans le tableau btnData const temp = btnData[draggedIndex]; btnData[draggedIndex] = btnData[targetIndex]; btnData[targetIndex] = temp; // On s'assure que les IDs restent corrects (optionnel selon ton usage) btnData[draggedIndex].id = draggedIndex; btnData[targetIndex].id = targetIndex; // Si des sons étaient en cours, on les arrête pour éviter les bugs stopAll(); // On réinitialise les lecteurs audio pour ces deux boutons delete players[draggedIndex]; delete players[targetIndex]; // Sauvegarde et mise à jour de l'affichage localStorage.setItem('sb_studio_data', JSON.stringify(btnData)); init(); } function init() { const board = document.getElementById('board'); board.innerHTML = ""; btnData.forEach((data, i) => { const div = document.createElement('div'); div.className = `btn ${data.file ? 'active' : ''} ${data.loop ? 'has-loop' : ''}`; div.id = `btn-${i}`; div.setAttribute('draggable', 'true'); // Rend le bouton draggable div.innerHTML = `${i+1} ${data.name || "-"} `; // Clic pour lecture ou édition div.onclick = () => handleBtnClick(i); // Événements de Drag & Drop div.ondragstart = (e) => handleDragStart(e, i); div.ondragover = (e) => handleDragOver(e); div.ondragenter = (e) => div.classList.add('drag-over'); div.ondragleave = (e) => div.classList.remove('drag-over'); div.ondrop = (e) => handleDrop(e, i); div.ondragend = (e) => div.classList.remove('dragging'); board.appendChild(div); }); } function toggleEditMode() { isEditMode = !isEditMode; document.body.classList.toggle('edit-mode', isEditMode); document.getElementById('toggleBtn').innerText = isEditMode ? "QUITTER L'ÉDITION" : "MODE ÉDITION"; document.getElementById('toggleBtn').style.background = isEditMode ? "var(--accent)" : "#444"; document.getElementById('toggleBtn').style.color = isEditMode ? "black" : "white"; } function handleBtnClick(i) { if (isEditMode) openEdit(i); else playSound(i); } function playSound(i) { const data = btnData[i]; if (!data.file) return; if (players[i] && !players[i].paused) { players[i].pause(); players[i].currentTime = 0; document.getElementById(`btn-${i}`).classList.remove('playing'); } else { if (!players[i]) players[i] = new Audio(data.file); players[i].loop = data.loop; players[i].volume = data.volume || 1; players[i].play(); document.getElementById(`btn-${i}`).classList.add('playing'); players[i].onended = () => { if(!data.loop) document.getElementById(`btn-${i}`).classList.remove('playing'); }; } } function stopAll() { Object.keys(players).forEach(key => { players[key].pause(); players[key].currentTime = 0; document.getElementById(`btn-${key}`).classList.remove('playing'); }); } function openEdit(i) { editingIndex = i; const data = btnData[i]; document.getElementById('editTitle').innerText = "Bouton " + (i + 1); document.getElementById('inputName').value = data.name; document.getElementById('inputLoop').checked = data.loop; document.getElementById('inputVolume').value = data.volume || 1; document.getElementById('fileNameLabel').innerText = data.file ? "Audio présent" : "Audio vide"; tempFileData = data.file; document.getElementById('editOverlay').style.display = 'flex'; } document.getElementById('fileInput').onchange = (e) => { const file = e.target.files[0]; if (file) { const reader = new FileReader(); reader.onload = (ev) => { tempFileData = ev.target.result; document.getElementById('fileNameLabel').innerText = "Fichier : " + file.name; }; reader.readAsDataURL(file); } }; function saveSettings() { btnData[editingIndex].name = document.getElementById('inputName').value; btnData[editingIndex].loop = document.getElementById('inputLoop').checked; btnData[editingIndex].volume = parseFloat(document.getElementById('inputVolume').value); btnData[editingIndex].file = tempFileData; localStorage.setItem('sb_studio_data', JSON.stringify(btnData)); if (players[editingIndex]) delete players[editingIndex]; closeEdit(); init(); } // Désactive le menu contextuel (clic droit) sur toute la page window.oncontextmenu = function(event) { event.preventDefault(); event.stopPropagation(); return false; }; function closeEdit() { document.getElementById('editOverlay').style.display = 'none'; } init(); if ('serviceWorker' in navigator) { navigator.serviceWorker.register('sw.js') .then(() => console.log("Service Worker Enregistré")); }