import 'package:flutter/services.dart'; import 'package:audioplayers/audioplayers.dart'; import 'package:vibration/vibration.dart'; import 'package:flutter/foundation.dart' show kIsWeb, debugPrint; class AppFeedback { static final AudioPlayer _player = AudioPlayer(); /// Play a sound from assets/sounds/ static Future playSound(String fileName) async { try { // AudioPlayer play from assets/sounds/fileName await _player.play(AssetSource('sounds/$fileName')); } catch (e) { // Web might throw security exception if player triggers before user interaction // or other runtime issues. Catching prevents app crashes. debugPrint('Audio playback error for $fileName: $e'); } } /// Light haptic feedback + subtle click sound static void click() { HapticFeedback.lightImpact(); playSound('click.mp3'); } /// Medium haptic + selection sound static void select() { HapticFeedback.mediumImpact(); playSound('select.mp3'); } /// Celebration sound + strong haptic vibration static void success() { HapticFeedback.heavyImpact(); playSound('success.mp3'); } /// Wrong input -> error haptic (double vibrate) + error sound static void error() { _doubleVibrate(); playSound('error.mp3'); } /// Light haptic feedback (e.g. chip selections) static void lightHaptic() { HapticFeedback.lightImpact(); } /// Medium haptic feedback static void mediumHaptic() { HapticFeedback.mediumImpact(); } /// Heavy haptic feedback static void heavyHaptic() { HapticFeedback.heavyImpact(); } /// Subtle haptic feedback (e.g. screen navigation) static void subtleHaptic() { HapticFeedback.selectionClick(); } /// Double vibrate pattern using vibration package static Future _doubleVibrate() async { try { if (!kIsWeb && await Vibration.hasVibrator() == true) { // Double vibrate pattern: wait 0, vibrate 100ms, wait 100ms, vibrate 100ms Vibration.vibrate(pattern: [0, 100, 100, 100]); } else { // Fallback to native HapticFeedback HapticFeedback.mediumImpact(); } } catch (e) { HapticFeedback.mediumImpact(); } } }