콘텐츠 메인
- 콘텐츠 미니 플레이어 추가
This commit is contained in:
		@@ -1,22 +1,48 @@
 | 
			
		||||
package kr.co.vividnext.sodalive.audio_content.main.v2
 | 
			
		||||
 | 
			
		||||
import android.annotation.SuppressLint
 | 
			
		||||
import android.content.BroadcastReceiver
 | 
			
		||||
import android.content.ComponentName
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import android.content.IntentFilter
 | 
			
		||||
import android.content.SharedPreferences
 | 
			
		||||
import android.graphics.Typeface
 | 
			
		||||
import android.os.Build
 | 
			
		||||
import android.os.Handler
 | 
			
		||||
import android.os.Looper
 | 
			
		||||
import android.view.View
 | 
			
		||||
import android.view.ViewGroup
 | 
			
		||||
import android.widget.TextView
 | 
			
		||||
import androidx.annotation.OptIn
 | 
			
		||||
import androidx.core.content.ContextCompat
 | 
			
		||||
import androidx.core.content.res.ResourcesCompat
 | 
			
		||||
import androidx.media3.common.MediaItem
 | 
			
		||||
import androidx.media3.common.MediaMetadata
 | 
			
		||||
import androidx.media3.common.Player
 | 
			
		||||
import androidx.media3.common.util.UnstableApi
 | 
			
		||||
import androidx.media3.session.MediaController
 | 
			
		||||
import androidx.media3.session.SessionToken
 | 
			
		||||
import coil.load
 | 
			
		||||
import coil.transform.RoundedCornersTransformation
 | 
			
		||||
import com.google.android.material.tabs.TabLayout
 | 
			
		||||
import kr.co.vividnext.sodalive.R
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.AudioContentPlayService
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.box.AudioContentBoxActivity
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.detail.AudioContentDetailActivity
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.main.v2.alarm.AudioContentMainTabAlarmFragment
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.main.v2.asmr.AudioContentMainTabAsmrFragment
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.main.v2.content.AudioContentMainTabContentFragment
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.main.v2.free.AudioContentMainTabFreeFragment
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.main.v2.replay.AudioContentMainTabReplayFragment
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.main.v2.series.AudioContentMainTabSeriesFragment
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.player.AudioContentPlayerFragment
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.player.AudioContentPlayerService
 | 
			
		||||
import kr.co.vividnext.sodalive.base.BaseActivity
 | 
			
		||||
import kr.co.vividnext.sodalive.common.Constants
 | 
			
		||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
 | 
			
		||||
import kr.co.vividnext.sodalive.databinding.ActivityAudioContentMainBinding
 | 
			
		||||
import kr.co.vividnext.sodalive.extensions.dpToPx
 | 
			
		||||
import kr.co.vividnext.sodalive.mypage.alarm.AlarmListActivity
 | 
			
		||||
import kotlin.math.min
 | 
			
		||||
 | 
			
		||||
@@ -30,6 +56,7 @@ enum class AudioContentMainTab {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@OptIn(UnstableApi::class)
 | 
			
		||||
class AudioContentMainActivity : BaseActivity<ActivityAudioContentMainBinding>(
 | 
			
		||||
    ActivityAudioContentMainBinding::inflate
 | 
			
		||||
) {
 | 
			
		||||
@@ -39,6 +66,43 @@ class AudioContentMainActivity : BaseActivity<ActivityAudioContentMainBinding>(
 | 
			
		||||
 | 
			
		||||
    private var startTabPosition: AudioContentMainTab = AudioContentMainTab.SERIES
 | 
			
		||||
 | 
			
		||||
    private var mediaController: MediaController? = null
 | 
			
		||||
    private val handler = Handler(Looper.getMainLooper())
 | 
			
		||||
    private val audioContentReceiver = AudioContentReceiver()
 | 
			
		||||
 | 
			
		||||
    override fun onDestroy() {
 | 
			
		||||
        deInitMiniPlayer()
 | 
			
		||||
        SharedPreferenceManager.unregisterOnSharedPreferenceChangeListener(preferenceChangeListener)
 | 
			
		||||
        super.onDestroy()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun showPlayerFragment() {
 | 
			
		||||
        val playerFragment = AudioContentPlayerFragment(screenWidth, arrayListOf())
 | 
			
		||||
        playerFragment.show(supportFragmentManager, playerFragment.tag)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @SuppressLint("UnspecifiedRegisterReceiverFlag")
 | 
			
		||||
    override fun onResume() {
 | 
			
		||||
        super.onResume()
 | 
			
		||||
        val intentFilter = IntentFilter(Constants.ACTION_MAIN_AUDIO_CONTENT_RECEIVER)
 | 
			
		||||
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
 | 
			
		||||
            registerReceiver(audioContentReceiver, intentFilter, Context.RECEIVER_NOT_EXPORTED)
 | 
			
		||||
        } else {
 | 
			
		||||
            registerReceiver(audioContentReceiver, intentFilter)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        startService(
 | 
			
		||||
            Intent(this, AudioContentPlayService::class.java).apply {
 | 
			
		||||
                action = AudioContentPlayService.MusicAction.INIT.name
 | 
			
		||||
            }
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onPause() {
 | 
			
		||||
        unregisterReceiver(audioContentReceiver)
 | 
			
		||||
        super.onPause()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun setupView() {
 | 
			
		||||
        startTabPosition = AudioContentMainTab.fromOrdinal(
 | 
			
		||||
            intent.getIntExtra(
 | 
			
		||||
@@ -50,6 +114,13 @@ class AudioContentMainActivity : BaseActivity<ActivityAudioContentMainBinding>(
 | 
			
		||||
        setupToolbar()
 | 
			
		||||
        loadFont()
 | 
			
		||||
        setupTabs()
 | 
			
		||||
 | 
			
		||||
        SharedPreferenceManager.registerOnSharedPreferenceChangeListener(preferenceChangeListener)
 | 
			
		||||
        if (SharedPreferenceManager.isPlayerServiceRunning) {
 | 
			
		||||
            initAndVisibleMiniPlayer()
 | 
			
		||||
        } else {
 | 
			
		||||
            deInitMiniPlayer()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun setupToolbar() {
 | 
			
		||||
@@ -149,4 +220,199 @@ class AudioContentMainActivity : BaseActivity<ActivityAudioContentMainBinding>(
 | 
			
		||||
    private fun setTabFont(tab: TabLayout.Tab, font: Typeface?) {
 | 
			
		||||
        (tab.view.getChildAt(1) as? TextView)?.typeface = font
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private val preferenceChangeListener =
 | 
			
		||||
        SharedPreferences.OnSharedPreferenceChangeListener { sharedPreferences, key ->
 | 
			
		||||
            // 특정 키에 대한 값이 변경될 때 UI 업데이트
 | 
			
		||||
            if (key == Constants.PREF_IS_PLAYER_SERVICE_RUNNING) {
 | 
			
		||||
                if (sharedPreferences.getBoolean(key, false)) {
 | 
			
		||||
                    handler.postDelayed(
 | 
			
		||||
                        {
 | 
			
		||||
                            initAndVisibleMiniPlayer()
 | 
			
		||||
                        },
 | 
			
		||||
                        1500
 | 
			
		||||
                    )
 | 
			
		||||
                } else {
 | 
			
		||||
                    deInitMiniPlayer()
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    private fun initAndVisibleMiniPlayer() {
 | 
			
		||||
        binding.clMiniPlayer.visibility = View.VISIBLE
 | 
			
		||||
        binding.clMiniPlayer.setOnClickListener { showPlayerFragment() }
 | 
			
		||||
        binding.ivPlayerStop.setOnClickListener {
 | 
			
		||||
            startService(
 | 
			
		||||
                Intent(applicationContext, AudioContentPlayerService::class.java).apply {
 | 
			
		||||
                    action = "STOP_SERVICE"
 | 
			
		||||
                }
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
        connectPlayerService()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun connectPlayerService() {
 | 
			
		||||
        val componentName = ComponentName(applicationContext, AudioContentPlayerService::class.java)
 | 
			
		||||
        val sessionToken = SessionToken(applicationContext, componentName)
 | 
			
		||||
        val mediaControllerFuture =
 | 
			
		||||
            MediaController.Builder(applicationContext, sessionToken).buildAsync()
 | 
			
		||||
        mediaControllerFuture.addListener(
 | 
			
		||||
            {
 | 
			
		||||
                mediaController = mediaControllerFuture.get()
 | 
			
		||||
                setupMediaController()
 | 
			
		||||
                updateMediaMetadata(mediaController?.mediaMetadata)
 | 
			
		||||
 | 
			
		||||
                binding.ivPlayerPlayOrPause.setImageResource(
 | 
			
		||||
                    if (mediaController!!.isPlaying) {
 | 
			
		||||
                        R.drawable.ic_player_pause
 | 
			
		||||
                    } else {
 | 
			
		||||
                        R.drawable.ic_player_play
 | 
			
		||||
                    }
 | 
			
		||||
                )
 | 
			
		||||
 | 
			
		||||
                binding.ivPlayerPlayOrPause.setOnClickListener {
 | 
			
		||||
                    mediaController?.let {
 | 
			
		||||
                        if (it.playWhenReady) {
 | 
			
		||||
                            it.pause()
 | 
			
		||||
                        } else {
 | 
			
		||||
                            it.play()
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            ContextCompat.getMainExecutor(applicationContext)
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun updateMediaMetadata(metadata: MediaMetadata?) {
 | 
			
		||||
        metadata?.let {
 | 
			
		||||
            binding.tvPlayerTitle.text = it.title
 | 
			
		||||
            binding.tvPlayerNickname.text = it.artist
 | 
			
		||||
 | 
			
		||||
            binding.ivPlayerCover.load(it.artworkUri) {
 | 
			
		||||
                crossfade(true)
 | 
			
		||||
                placeholder(R.drawable.ic_place_holder)
 | 
			
		||||
                transformations(RoundedCornersTransformation(4f))
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun setupMediaController() {
 | 
			
		||||
        if (mediaController == null) {
 | 
			
		||||
            deInitMiniPlayer()
 | 
			
		||||
            return
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        mediaController!!.addListener(object : Player.Listener {
 | 
			
		||||
            override fun onMediaItemTransition(mediaItem: MediaItem?, reason: Int) {
 | 
			
		||||
                updateMediaMetadata(mediaItem?.mediaMetadata)
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            override fun onPlayWhenReadyChanged(playWhenReady: Boolean, reason: Int) {
 | 
			
		||||
                binding.ivPlayerPlayOrPause.setImageResource(
 | 
			
		||||
                    if (playWhenReady) {
 | 
			
		||||
                        R.drawable.ic_player_pause
 | 
			
		||||
                    } else {
 | 
			
		||||
                        R.drawable.ic_player_play
 | 
			
		||||
                    }
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun deInitMiniPlayer() {
 | 
			
		||||
        binding.clMiniPlayer.visibility = View.GONE
 | 
			
		||||
        mediaController?.release()
 | 
			
		||||
        mediaController = null
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inner class AudioContentReceiver : BroadcastReceiver() {
 | 
			
		||||
        override fun onReceive(context: Context?, intent: Intent?) {
 | 
			
		||||
            val contentId = intent?.getLongExtra(Constants.EXTRA_AUDIO_CONTENT_ID, 0)
 | 
			
		||||
            val title = intent?.getStringExtra(Constants.EXTRA_AUDIO_CONTENT_TITLE)
 | 
			
		||||
            val nickname = intent?.getStringExtra(Constants.EXTRA_NICKNAME)
 | 
			
		||||
            val coverImageUrl = intent?.getStringExtra(
 | 
			
		||||
                Constants.EXTRA_AUDIO_CONTENT_COVER_IMAGE_URL
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
            val isPlaying = intent?.getBooleanExtra(Constants.EXTRA_AUDIO_CONTENT_PLAYING, false)
 | 
			
		||||
            val isShowing = intent?.getBooleanExtra(Constants.EXTRA_AUDIO_CONTENT_SHOWING, false)
 | 
			
		||||
 | 
			
		||||
            if (isShowing == true) {
 | 
			
		||||
                binding.rlMiniPlayer.visibility = View.VISIBLE
 | 
			
		||||
                if (contentId != null && contentId > 0) {
 | 
			
		||||
                    binding.rlMiniPlayer.setOnClickListener {
 | 
			
		||||
                        startActivity(
 | 
			
		||||
                            Intent(applicationContext, AudioContentDetailActivity::class.java)
 | 
			
		||||
                                .apply {
 | 
			
		||||
                                    putExtra(Constants.EXTRA_AUDIO_CONTENT_ID, contentId)
 | 
			
		||||
                                }
 | 
			
		||||
                        )
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (isPlaying == true) {
 | 
			
		||||
                    binding.ivPlayOrPause.setImageResource(R.drawable.ic_noti_pause)
 | 
			
		||||
                    binding.ivPlayOrPause.setOnClickListener {
 | 
			
		||||
                        startService(
 | 
			
		||||
                            Intent(
 | 
			
		||||
                                this@AudioContentMainActivity,
 | 
			
		||||
                                AudioContentPlayService::class.java
 | 
			
		||||
                            ).apply {
 | 
			
		||||
                                action = AudioContentPlayService.MusicAction.PAUSE.name
 | 
			
		||||
                            }
 | 
			
		||||
                        )
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    binding.ivPlayOrPause.setImageResource(R.drawable.ic_noti_play)
 | 
			
		||||
                    binding.ivPlayOrPause.setOnClickListener {
 | 
			
		||||
                        startService(
 | 
			
		||||
                            Intent(
 | 
			
		||||
                                this@AudioContentMainActivity,
 | 
			
		||||
                                AudioContentPlayService::class.java
 | 
			
		||||
                            ).apply {
 | 
			
		||||
                                action = AudioContentPlayService.MusicAction.PLAY.name
 | 
			
		||||
                            }
 | 
			
		||||
                        )
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                binding.ivStop.setOnClickListener {
 | 
			
		||||
                    startService(
 | 
			
		||||
                        Intent(
 | 
			
		||||
                            this@AudioContentMainActivity,
 | 
			
		||||
                            AudioContentPlayService::class.java
 | 
			
		||||
                        ).apply {
 | 
			
		||||
                            action = AudioContentPlayService.MusicAction.STOP.name
 | 
			
		||||
                        }
 | 
			
		||||
                    )
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (!title.isNullOrBlank()) {
 | 
			
		||||
                    binding.tvMiniPlayerTitle.text = title
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (!nickname.isNullOrBlank()) {
 | 
			
		||||
                    binding.tvNickname.text = nickname
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (!coverImageUrl.isNullOrBlank()) {
 | 
			
		||||
                    binding.ivCover.load(coverImageUrl) {
 | 
			
		||||
                        crossfade(true)
 | 
			
		||||
                        placeholder(R.drawable.bg_placeholder)
 | 
			
		||||
                        transformations(RoundedCornersTransformation(5.3f.dpToPx()))
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                handler.post {
 | 
			
		||||
                    binding.ivPlayOrPause.setImageResource(0)
 | 
			
		||||
                    binding.ivCover.setImageResource(0)
 | 
			
		||||
                    binding.tvMiniPlayerTitle.text = ""
 | 
			
		||||
                    binding.tvNickname.text = ""
 | 
			
		||||
                    binding.rlMiniPlayer.visibility = View.GONE
 | 
			
		||||
                    binding.ivPlayOrPause.setOnClickListener {}
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user