import 'dart:js_interop'; import 'package:web/web.dart' as web; import 'package:em2rp/utils/debug_log.dart'; /// Service pour émettre des feedbacks sonores lors des interactions (Web) class AudioFeedbackService { static bool _isInitialized = false; static bool _audioUnlocked = false; /// Initialiser le service static Future _initialize() async { if (_isInitialized) return; try { DebugLog.info('[AudioFeedbackService] Initializing audio service for Web...'); _isInitialized = true; } catch (e) { DebugLog.error('[AudioFeedbackService] Error initializing audio', e); } } /// Débloquer l'audio (à appeler lors de la première interaction utilisateur) static Future unlockAudio() async { if (_audioUnlocked) { DebugLog.info('[AudioFeedbackService] Audio already unlocked'); return; } try { if (!_isInitialized) await _initialize(); DebugLog.info('[AudioFeedbackService] Attempting to unlock audio...'); // Créer un audio temporaire et le jouer avec volume 0 final tempAudio = web.HTMLAudioElement(); tempAudio.src = 'assets/assets/sounds/ok.mp3'; tempAudio.volume = 0.01; // Volume très faible mais pas 0 tempAudio.preload = 'auto'; try { await tempAudio.play().toDart; await Future.delayed(const Duration(milliseconds: 100)); tempAudio.pause(); _audioUnlocked = true; DebugLog.info('[AudioFeedbackService] ✓ Audio unlocked successfully'); } catch (e) { DebugLog.warning('[AudioFeedbackService] ⚠ Could not unlock audio: $e'); DebugLog.warning('[AudioFeedbackService] User interaction may be required'); } } catch (e) { DebugLog.error('[AudioFeedbackService] Error unlocking audio', e); } } /// Créer et jouer un son static Future _playSound(String assetPath, double volume) async { try { if (!_isInitialized) await _initialize(); DebugLog.info('[AudioFeedbackService] Attempting to play: $assetPath (volume: $volume)'); // Créer un nouvel élément audio à chaque fois final audio = web.HTMLAudioElement(); audio.src = assetPath; audio.volume = volume; audio.preload = 'auto'; // Ajouter des événements pour debug audio.onloadeddata = ((web.Event event) { DebugLog.info('[AudioFeedbackService] Audio data loaded: $assetPath'); }.toJS); audio.onerror = ((web.Event event) { DebugLog.error('[AudioFeedbackService] ✗ Audio error for $assetPath: ${audio.error}'); }.toJS); audio.onplay = ((web.Event event) { DebugLog.info('[AudioFeedbackService] Audio started playing'); }.toJS); audio.onended = ((web.Event event) { DebugLog.info('[AudioFeedbackService] Audio finished playing'); }.toJS); try { // Essayer de jouer await audio.play().toDart; DebugLog.info('[AudioFeedbackService] ✓ Sound played successfully'); } catch (e) { DebugLog.error('[AudioFeedbackService] ✗ Play failed: $e'); // Si c'est un problème d'autoplay, essayer de débloquer if (!_audioUnlocked) { DebugLog.info('[AudioFeedbackService] Trying to unlock audio on error...'); _audioUnlocked = false; // Forcer le déblocage await unlockAudio(); // Réessayer une fois après déblocage try { final retryAudio = web.HTMLAudioElement(); retryAudio.src = assetPath; retryAudio.volume = volume; await retryAudio.play().toDart; DebugLog.info('[AudioFeedbackService] ✓ Sound played on retry'); } catch (retryError) { DebugLog.error('[AudioFeedbackService] ✗ Retry also failed: $retryError'); } } } } catch (e) { DebugLog.error('[AudioFeedbackService] Error in _playSound', e); } } /// Jouer un son de succès static Future playSuccessBeep() async { await _playSound('assets/assets/sounds/ok.mp3', 1.0); } /// Jouer un son d'erreur static Future playErrorBeep() async { await _playSound('assets/assets/sounds/error.mp3', 0.8); } /// Jouer un feedback complet (son uniquement, sans vibration) static Future playFullFeedback({bool isSuccess = true}) async { if (isSuccess) { await playSuccessBeep(); } else { await playErrorBeep(); } } /// Nettoyer les ressources static Future dispose() async { try { _isInitialized = false; _audioUnlocked = false; } catch (e) { DebugLog.error('[AudioFeedbackService] Error disposing', e); } } }