package com.craigvg.lichun_android.managers import android.content.Context import android.media.AudioAttributes import android.media.SoundPool import android.util.Log import dagger.hilt.android.qualifiers.ApplicationContext import javax.inject.Inject import javax.inject.Singleton /** * Sound manager for playing audio effects * Ported from iOS SoundManager.swift */ @Singleton class SoundManager @Inject constructor( @ApplicationContext private val context: Context ) { private var soundPool: SoundPool? = null private val soundMap = mutableMapOf() private val prefs = context.getSharedPreferences("baolife_sound", Context.MODE_PRIVATE) private var isMuted = prefs.getBoolean("isMuted", false) private var volume = prefs.getFloat("volume", 1.0f) companion object { private const val TAG = "SoundManager" private const val MAX_STREAMS = 5 } /** * Sound effects available in the app */ enum class SoundEffect(val resourceName: String) { BUTTON_TAP("button_tap"), CLAIM_REWARD("claim_reward"), ACHIEVEMENT_UNLOCK("achievement_unlock"), LEVEL_UP("level_up"), MESSAGE_SENT("message_sent"), MESSAGE_RECEIVED("message_received"), SWIPE_LEFT("swipe_left"), SWIPE_RIGHT("swipe_right"), MATCH("match"), COINS("coins"), DIAMONDS("diamonds"), ERROR("error"), SUCCESS("success"), NOTIFICATION("notification") } /** * Initialize the sound pool and preload sounds */ fun initialize() { val audioAttributes = AudioAttributes.Builder() .setUsage(AudioAttributes.USAGE_GAME) .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) .build() soundPool = SoundPool.Builder() .setMaxStreams(MAX_STREAMS) .setAudioAttributes(audioAttributes) .build() // Preload all sounds SoundEffect.entries.forEach { effect -> loadSound(effect) } Log.d(TAG, "SoundManager initialized") } private fun loadSound(effect: SoundEffect) { try { // Look for the resource in raw folder val resourceId = context.resources.getIdentifier( effect.resourceName, "raw", context.packageName ) if (resourceId != 0) { val soundId = soundPool?.load(context, resourceId, 1) if (soundId != null && soundId != 0) { soundMap[effect] = soundId Log.d(TAG, "Loaded sound: ${effect.resourceName}") } } else { // Resource not found - this is OK, sound files may not exist yet Log.d(TAG, "Sound resource not found: ${effect.resourceName}") } } catch (e: Exception) { Log.w(TAG, "Failed to load sound ${effect.resourceName}: ${e.message}") } } /** * Play a sound effect */ fun play(effect: SoundEffect, rate: Float = 1.0f) { if (isMuted) return val soundId = soundMap[effect] if (soundId != null) { soundPool?.play( soundId, volume, volume, 1, 0, rate.coerceIn(0.5f, 2.0f) ) Log.d(TAG, "Playing sound: ${effect.resourceName}") } else { Log.d(TAG, "Sound not loaded: ${effect.resourceName}") } } /** * Play button tap sound */ fun playButtonTap() = play(SoundEffect.BUTTON_TAP) /** * Play claim reward sound */ fun playClaimReward() = play(SoundEffect.CLAIM_REWARD) /** * Play achievement unlock sound */ fun playAchievementUnlock() = play(SoundEffect.ACHIEVEMENT_UNLOCK) /** * Play level up sound */ fun playLevelUp() = play(SoundEffect.LEVEL_UP) /** * Play message sent sound */ fun playMessageSent() = play(SoundEffect.MESSAGE_SENT) /** * Play message received sound */ fun playMessageReceived() = play(SoundEffect.MESSAGE_RECEIVED) /** * Play swipe left sound */ fun playSwipeLeft() = play(SoundEffect.SWIPE_LEFT) /** * Play swipe right sound */ fun playSwipeRight() = play(SoundEffect.SWIPE_RIGHT) /** * Play match sound */ fun playMatch() = play(SoundEffect.MATCH) /** * Play coins sound */ fun playCoins() = play(SoundEffect.COINS) /** * Play diamonds sound */ fun playDiamonds() = play(SoundEffect.DIAMONDS) /** * Play error sound */ fun playError() = play(SoundEffect.ERROR) /** * Play success sound */ fun playSuccess() = play(SoundEffect.SUCCESS) /** * Play notification sound */ fun playNotification() = play(SoundEffect.NOTIFICATION) // MARK: - Settings /** * Mute/unmute all sounds */ fun setMuted(muted: Boolean) { isMuted = muted prefs.edit().putBoolean("isMuted", muted).apply() Log.d(TAG, "Sound muted: $muted") } /** * Check if sounds are muted */ fun isSoundMuted(): Boolean = isMuted /** * Set the volume level (0.0 to 1.0) */ fun setVolume(level: Float) { volume = level.coerceIn(0f, 1f) prefs.edit().putFloat("volume", volume).apply() Log.d(TAG, "Volume set to: $volume") } /** * Get the current volume level */ fun getVolume(): Float = volume /** * Release resources */ fun release() { soundPool?.release() soundPool = null soundMap.clear() Log.d(TAG, "SoundManager released") } }