| <!DOCTYPE html> |
| <html lang="fr"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>Talkie-Walkie Offline</title> |
| <script src="https://cdn.tailwindcss.com"></script> |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> |
| <style> |
| @keyframes pulse { |
| 0%, 100% { opacity: 1; } |
| 50% { opacity: 0.5; } |
| } |
| .recording-animation { |
| animation: pulse 1s infinite; |
| } |
| #visualizer { |
| height: 80px; |
| background: linear-gradient(to right, #3b82f6, #8b5cf6); |
| border-radius: 10px; |
| overflow: hidden; |
| } |
| .bar { |
| background-color: white; |
| width: 4px; |
| height: 20px; |
| margin: 0 2px; |
| display: inline-block; |
| border-radius: 2px; |
| } |
| </style> |
| </head> |
| <body class="bg-gray-900 text-white min-h-screen"> |
| <div class="container mx-auto px-4 py-6"> |
| |
| <header class="flex flex-col items-center mb-8"> |
| <div class="flex items-center justify-center mb-2"> |
| <i class="fas fa-walkie-talkie text-4xl text-blue-500 mr-3"></i> |
| <h1 class="text-3xl md:text-4xl font-bold text-center bg-clip-text text-transparent bg-gradient-to-r from-blue-400 to-purple-500"> |
| Talkie-Walkie Offline |
| </h1> |
| </div> |
| <p class="text-lg text-gray-400">Communication sans Internet via Wi-Fi/Bluetooth</p> |
| </header> |
|
|
| |
| <main class="flex flex-col items-center"> |
| |
| <div class="w-full max-w-md bg-gray-800 rounded-xl p-4 mb-6 shadow-lg border border-gray-700"> |
| <div class="flex justify-between items-center"> |
| <div> |
| <h2 class="text-lg font-semibold">État de la connexion</h2> |
| <p id="connectionStatus" class="text-sm text-gray-400">Non connecté</p> |
| </div> |
| <div id="connectionType" class="flex items-center"> |
| <i class="fas fa-wifi text-gray-500 mr-2"></i> |
| <span class="text-sm">Wi-Fi</span> |
| </div> |
| </div> |
| |
| <div class="mt-4 flex flex-col space-y-3"> |
| <button id="discoverBtn" class="w-full py-2 bg-blue-600 hover:bg-blue-700 rounded-lg font-medium flex items-center justify-center gap-2"> |
| <i class="fas fa-search"></i> Découvrir des appareils |
| </button> |
| <button id="hostBtn" class="w-full py-2 bg-purple-600 hover:bg-purple-700 rounded-lg font-medium flex items-center justify-center gap-2"> |
| <i class="fas fa-broadcast-tower"></i> Héberger un réseau |
| </button> |
| </div> |
| </div> |
|
|
| |
| <div id="devicesContainer" class="w-full max-w-md bg-gray-800 rounded-xl p-4 mb-6 shadow-lg border border-gray-700 hidden"> |
| <h2 class="text-lg font-semibold mb-3 flex items-center gap-2"> |
| <i class="fas fa-list"></i> Appareils disponibles |
| </h2> |
| <div id="devicesList" class="space-y-2"> |
| |
| </div> |
| </div> |
|
|
| |
| <div class="w-full max-w-md bg-gray-800 rounded-xl p-4 shadow-lg border border-gray-700"> |
| <h2 class="text-lg font-semibold mb-4 flex items-center gap-2"> |
| <i class="fas fa-microphone"></i> Contrôles |
| </h2> |
| |
| |
| <div id="visualizer" class="mb-4 flex items-end justify-center"> |
| |
| </div> |
| |
| |
| <div class="flex justify-center space-x-4"> |
| <button id="talkBtn" class="w-16 h-16 rounded-full bg-red-600 hover:bg-red-700 flex items-center justify-center shadow-lg transform hover:scale-105 transition-transform disabled:opacity-50" disabled> |
| <i class="fas fa-microphone text-2xl"></i> |
| </button> |
| <button id="settingsBtn" class="w-16 h-16 rounded-full bg-gray-700 hover:bg-gray-600 flex items-center justify-center shadow-lg transform hover:scale-105 transition-transform"> |
| <i class="fas fa-cog text-2xl"></i> |
| </button> |
| </div> |
| |
| |
| <div id="statusIndicator" class="mt-4 text-center text-sm text-gray-400"> |
| Appuyez et maintenez pour parler |
| </div> |
| </div> |
| </main> |
|
|
| |
| <div id="settingsModal" class="fixed inset-0 bg-black bg-opacity-70 flex items-center justify-center p-4 z-50 hidden"> |
| <div class="bg-gray-800 rounded-xl p-6 w-full max-w-md shadow-2xl border border-gray-700"> |
| <div class="flex justify-between items-center mb-4"> |
| <h3 class="text-xl font-semibold">Paramètres</h3> |
| <button id="closeSettingsBtn" class="text-gray-400 hover:text-white"> |
| <i class="fas fa-times text-2xl"></i> |
| </button> |
| </div> |
| |
| <div class="space-y-4"> |
| <div> |
| <label class="block text-sm font-medium mb-1">Mode de connexion</label> |
| <select id="connectionMode" class="w-full bg-gray-700 border border-gray-600 rounded-lg p-2"> |
| <option value="wifi">Wi-Fi Direct</option> |
| <option value="bluetooth">Bluetooth</option> |
| </select> |
| </div> |
| |
| <div> |
| <label class="block text-sm font-medium mb-1">Qualité audio</label> |
| <select id="audioQuality" class="w-full bg-gray-700 border border-gray-600 rounded-lg p-2"> |
| <option value="low">Faible (8kHz)</option> |
| <option value="medium" selected>Moyenne (16kHz)</option> |
| <option value="high">Haute (44.1kHz)</option> |
| </select> |
| </div> |
| |
| <div> |
| <label class="block text-sm font-medium mb-1">Portée estimée</label> |
| <div class="flex items-center gap-2"> |
| <i class="fas fa-signal text-blue-500"></i> |
| <span id="rangeEstimate" class="font-medium">~100 mètres (Wi-Fi)</span> |
| </div> |
| </div> |
| |
| <div class="pt-2"> |
| <button id="saveSettingsBtn" class="w-full py-2 bg-blue-600 hover:bg-blue-700 rounded-lg font-medium"> |
| Enregistrer les paramètres |
| </button> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| <script> |
| document.addEventListener('DOMContentLoaded', function() { |
| |
| const discoverBtn = document.getElementById('discoverBtn'); |
| const hostBtn = document.getElementById('hostBtn'); |
| const talkBtn = document.getElementById('talkBtn'); |
| const settingsBtn = document.getElementById('settingsBtn'); |
| const closeSettingsBtn = document.getElementById('closeSettingsBtn'); |
| const saveSettingsBtn = document.getElementById('saveSettingsBtn'); |
| const settingsModal = document.getElementById('settingsModal'); |
| const connectionStatus = document.getElementById('connectionStatus'); |
| const connectionType = document.getElementById('connectionType'); |
| const devicesContainer = document.getElementById('devicesContainer'); |
| const devicesList = document.getElementById('devicesList'); |
| const statusIndicator = document.getElementById('statusIndicator'); |
| const visualizer = document.getElementById('visualizer'); |
| const connectionMode = document.getElementById('connectionMode'); |
| const audioQuality = document.getElementById('audioQuality'); |
| const rangeEstimate = document.getElementById('rangeEstimate'); |
| |
| |
| let isRecording = false; |
| let isConnected = false; |
| let currentConnectionMode = 'wifi'; |
| |
| |
| function createAudioVisualizer() { |
| visualizer.innerHTML = ''; |
| for (let i = 0; i < 30; i++) { |
| const bar = document.createElement('div'); |
| bar.className = 'bar'; |
| bar.style.height = `${Math.random() * 60 + 20}px`; |
| visualizer.appendChild(bar); |
| } |
| } |
| |
| |
| function updateVisualizer() { |
| if (!isRecording) return; |
| |
| const bars = visualizer.querySelectorAll('.bar'); |
| bars.forEach(bar => { |
| bar.style.height = `${Math.random() * 60 + 20}px`; |
| }); |
| |
| requestAnimationFrame(updateVisualizer); |
| } |
| |
| |
| function discoverDevices() { |
| devicesList.innerHTML = ''; |
| connectionStatus.textContent = 'Recherche en cours...'; |
| |
| |
| setTimeout(() => { |
| const deviceNames = [ |
| 'Talkie-1 (Proche)', |
| 'Talkie-2', |
| 'Talkie-3', |
| 'Talkie-4 (Faible signal)' |
| ]; |
| |
| deviceNames.forEach((name, index) => { |
| const device = document.createElement('div'); |
| device.className = 'flex justify-between items-center p-3 bg-gray-700 rounded-lg hover:bg-gray-600 cursor-pointer'; |
| device.innerHTML = ` |
| <div class="flex items-center gap-3"> |
| <i class="fas fa-mobile-alt text-blue-400"></i> |
| <span>${name}</span> |
| </div> |
| <div class="flex items-center gap-1"> |
| <i class="fas fa-signal ${index === 3 ? 'text-yellow-500' : 'text-green-500'}"></i> |
| <span class="text-xs">${index === 0 ? 'Fort' : index === 3 ? 'Faible' : 'Moyen'}</span> |
| </div> |
| `; |
| |
| device.addEventListener('click', () => connectToDevice(name)); |
| devicesList.appendChild(device); |
| }); |
| |
| devicesContainer.classList.remove('hidden'); |
| connectionStatus.textContent = 'Appareils trouvés'; |
| }, 2000); |
| } |
| |
| |
| function connectToDevice(deviceName) { |
| connectionStatus.textContent = `Connexion à ${deviceName}...`; |
| statusIndicator.textContent = `Connexion à ${deviceName}...`; |
| |
| setTimeout(() => { |
| isConnected = true; |
| connectionStatus.textContent = `Connecté à ${deviceName}`; |
| statusIndicator.textContent = 'Prêt à communiquer'; |
| talkBtn.disabled = false; |
| devicesContainer.classList.add('hidden'); |
| |
| |
| const wifiIcon = connectionType.querySelector('i'); |
| wifiIcon.className = currentConnectionMode === 'wifi' ? 'fas fa-wifi text-green-500 mr-2' : 'fas fa-bluetooth-b text-green-500 mr-2'; |
| connectionType.querySelector('span').textContent = currentConnectionMode === 'wifi' ? 'Wi-Fi Direct' : 'Bluetooth'; |
| }, 1500); |
| } |
| |
| |
| function hostNetwork() { |
| connectionStatus.textContent = 'Création du réseau...'; |
| |
| setTimeout(() => { |
| connectionStatus.textContent = 'Réseau hébergé - En attente de connexion'; |
| statusIndicator.textContent = 'En attente de connexion...'; |
| |
| |
| setTimeout(() => { |
| isConnected = true; |
| connectionStatus.textContent = 'Connecté à Talkie-5'; |
| statusIndicator.textContent = 'Prêt à communiquer'; |
| talkBtn.disabled = false; |
| |
| const wifiIcon = connectionType.querySelector('i'); |
| wifiIcon.className = currentConnectionMode === 'wifi' ? 'fas fa-wifi text-green-500 mr-2' : 'fas fa-bluetooth-b text-green-500 mr-2'; |
| connectionType.querySelector('span').textContent = currentConnectionMode === 'wifi' ? 'Wi-Fi Direct' : 'Bluetooth'; |
| }, 3000); |
| }, 2000); |
| } |
| |
| |
| function toggleRecording() { |
| if (!isRecording) { |
| |
| isRecording = true; |
| talkBtn.classList.add('recording-animation'); |
| statusIndicator.textContent = 'Enregistrement en cours...'; |
| createAudioVisualizer(); |
| updateVisualizer(); |
| } else { |
| |
| isRecording = false; |
| talkBtn.classList.remove('recording-animation'); |
| statusIndicator.textContent = 'Message envoyé'; |
| setTimeout(() => { |
| statusIndicator.textContent = 'Prêt à communiquer'; |
| }, 2000); |
| } |
| } |
| |
| |
| function showSettings() { |
| settingsModal.classList.remove('hidden'); |
| } |
| |
| function hideSettings() { |
| settingsModal.classList.add('hidden'); |
| } |
| |
| function saveSettings() { |
| currentConnectionMode = connectionMode.value; |
| |
| |
| if (currentConnectionMode === 'wifi') { |
| rangeEstimate.textContent = '~100 mètres (Wi-Fi)'; |
| } else { |
| rangeEstimate.textContent = '~10 mètres (Bluetooth)'; |
| } |
| |
| hideSettings(); |
| } |
| |
| |
| discoverBtn.addEventListener('click', discoverDevices); |
| hostBtn.addEventListener('click', hostNetwork); |
| talkBtn.addEventListener('mousedown', toggleRecording); |
| talkBtn.addEventListener('mouseup', toggleRecording); |
| talkBtn.addEventListener('mouseleave', function() { |
| if (isRecording) toggleRecording(); |
| }); |
| settingsBtn.addEventListener('click', showSettings); |
| closeSettingsBtn.addEventListener('click', hideSettings); |
| saveSettingsBtn.addEventListener('click', saveSettings); |
| |
| |
| talkBtn.addEventListener('contextmenu', (e) => e.preventDefault()); |
| |
| |
| createAudioVisualizer(); |
| |
| |
| connectionMode.addEventListener('change', function() { |
| const icon = connectionType.querySelector('i'); |
| if (this.value === 'wifi') { |
| icon.className = 'fas fa-wifi text-gray-500 mr-2'; |
| connectionType.querySelector('span').textContent = 'Wi-Fi'; |
| } else { |
| icon.className = 'fas fa-bluetooth-b text-gray-500 mr-2'; |
| connectionType.querySelector('span').textContent = 'Bluetooth'; |
| } |
| }); |
| }); |
| </script> |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=Comh58/abdoul" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> |
| </html> |