오디션 지원자 콘텐츠 재생/정지 기능 추가
This commit is contained in:
parent
92b201a6fa
commit
b0a97ab941
|
@ -81,6 +81,7 @@ dependencies {
|
||||||
implementation "androidx.media:media:1.7.0"
|
implementation "androidx.media:media:1.7.0"
|
||||||
implementation 'androidx.core:core-ktx:1.13.1'
|
implementation 'androidx.core:core-ktx:1.13.1'
|
||||||
implementation 'androidx.appcompat:appcompat:1.7.0'
|
implementation 'androidx.appcompat:appcompat:1.7.0'
|
||||||
|
implementation 'androidx.recyclerview:recyclerview:1.3.2'
|
||||||
implementation 'com.google.android.material:material:1.12.0'
|
implementation 'com.google.android.material:material:1.12.0'
|
||||||
implementation 'androidx.constraintlayout:constraintlayout:2.2.0'
|
implementation 'androidx.constraintlayout:constraintlayout:2.2.0'
|
||||||
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
|
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
|
||||||
|
|
|
@ -12,10 +12,11 @@ import kr.co.vividnext.sodalive.databinding.ItemAuditionApplicantBinding
|
||||||
|
|
||||||
class AuditionApplicantListAdapter(
|
class AuditionApplicantListAdapter(
|
||||||
private val onClickVote: (Int) -> Unit,
|
private val onClickVote: (Int) -> Unit,
|
||||||
private val onClickPlayOrPause: (Int) -> Unit
|
private val onClickPlayOrPause: (Int, Long, String) -> Unit
|
||||||
) : ListAdapter<GetAuditionRoleApplicantItem, AuditionApplicantListAdapter.ViewHolder>(DiffCallback()) {
|
) : ListAdapter<GetAuditionRoleApplicantItem, AuditionApplicantListAdapter.ViewHolder>(DiffCallback()) {
|
||||||
|
|
||||||
private var currentPlayingIndex: Int = -1
|
private var currentPlayingIndex: Int = -1
|
||||||
|
private var isPlaying: Boolean = false
|
||||||
|
|
||||||
class DiffCallback : DiffUtil.ItemCallback<GetAuditionRoleApplicantItem>() {
|
class DiffCallback : DiffUtil.ItemCallback<GetAuditionRoleApplicantItem>() {
|
||||||
override fun areItemsTheSame(
|
override fun areItemsTheSame(
|
||||||
|
@ -29,16 +30,18 @@ class AuditionApplicantListAdapter(
|
||||||
oldItem: GetAuditionRoleApplicantItem,
|
oldItem: GetAuditionRoleApplicantItem,
|
||||||
newItem: GetAuditionRoleApplicantItem
|
newItem: GetAuditionRoleApplicantItem
|
||||||
): Boolean {
|
): Boolean {
|
||||||
return oldItem == newItem && oldItem.voteCount == newItem.voteCount
|
return oldItem == newItem
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class ViewHolder(
|
inner class ViewHolder(
|
||||||
private val binding: ItemAuditionApplicantBinding
|
private val binding: ItemAuditionApplicantBinding
|
||||||
) : RecyclerView.ViewHolder(binding.root) {
|
) : RecyclerView.ViewHolder(binding.root) {
|
||||||
fun bind(item: GetAuditionRoleApplicantItem, position: Int) {
|
fun bind(item: GetAuditionRoleApplicantItem) {
|
||||||
binding.ivVote.setOnClickListener { onClickVote(position) }
|
binding.ivVote.setOnClickListener { onClickVote(bindingAdapterPosition) }
|
||||||
binding.ivPlayOrPause.setOnClickListener { onClickPlayOrPause(position) }
|
binding.ivPlayOrPause.setOnClickListener {
|
||||||
|
onClickPlayOrPause(bindingAdapterPosition, item.applicantId, item.voiceUrl)
|
||||||
|
}
|
||||||
|
|
||||||
binding.tvNickname.text = item.nickname
|
binding.tvNickname.text = item.nickname
|
||||||
binding.tvCountVote.text = item.voteCount.toString()
|
binding.tvCountVote.text = item.voteCount.toString()
|
||||||
|
@ -49,7 +52,7 @@ class AuditionApplicantListAdapter(
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.ivPlayOrPause.setImageResource(
|
binding.ivPlayOrPause.setImageResource(
|
||||||
if (position == currentPlayingIndex) {
|
if (bindingAdapterPosition == currentPlayingIndex && isPlaying) {
|
||||||
R.drawable.ic_audition_pause
|
R.drawable.ic_audition_pause
|
||||||
} else {
|
} else {
|
||||||
R.drawable.ic_audition_play
|
R.drawable.ic_audition_play
|
||||||
|
@ -67,10 +70,12 @@ class AuditionApplicantListAdapter(
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
holder.bind(getItem(position), position)
|
holder.bind(getItem(position))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updatePlayingIndex(newIndex: Int) {
|
fun updatePlayingIndex(newIndex: Int, isPlaying: Boolean) {
|
||||||
|
this.isPlaying = isPlaying
|
||||||
|
|
||||||
val previousIndex = currentPlayingIndex
|
val previousIndex = currentPlayingIndex
|
||||||
currentPlayingIndex = newIndex
|
currentPlayingIndex = newIndex
|
||||||
notifyItemChanged(previousIndex)
|
notifyItemChanged(previousIndex)
|
||||||
|
|
|
@ -0,0 +1,106 @@
|
||||||
|
package kr.co.vividnext.sodalive.audition.applicant
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.media.AudioAttributes
|
||||||
|
import android.media.MediaPlayer
|
||||||
|
import android.net.Uri
|
||||||
|
import android.widget.Toast
|
||||||
|
import com.orhanobut.logger.Logger
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.AudioContentPlayService
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.player.AudioContentPlayerService
|
||||||
|
import java.io.IOException
|
||||||
|
|
||||||
|
class AuditionApplicantMediaPlayerManager(
|
||||||
|
private val context: Context,
|
||||||
|
private val updateUI: (Int, Boolean) -> Unit
|
||||||
|
) {
|
||||||
|
private var mediaPlayer: MediaPlayer? = null
|
||||||
|
private var currentPlayingApplicantId: Long = -1
|
||||||
|
private var currentPlayingPosition: Int = -1
|
||||||
|
|
||||||
|
fun pauseContent() {
|
||||||
|
mediaPlayer?.pause()
|
||||||
|
updateUI(currentPlayingPosition, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun resumeContent() {
|
||||||
|
pauseAudioContentService()
|
||||||
|
mediaPlayer?.start()
|
||||||
|
updateUI(currentPlayingPosition, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun stopContent() {
|
||||||
|
mediaPlayer?.let {
|
||||||
|
it.stop()
|
||||||
|
it.release()
|
||||||
|
mediaPlayer = null
|
||||||
|
}
|
||||||
|
currentPlayingApplicantId = -1
|
||||||
|
currentPlayingPosition = -1
|
||||||
|
updateUI(currentPlayingPosition, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun toggleContent(position: Int, applicantId: Long, voiceUrl: String) {
|
||||||
|
if (currentPlayingApplicantId == applicantId && currentPlayingPosition == position) {
|
||||||
|
if (mediaPlayer?.isPlaying == true) {
|
||||||
|
pauseContent()
|
||||||
|
} else {
|
||||||
|
resumeContent()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
playContent(position, applicantId, voiceUrl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun playContent(position: Int, applicantId: Long, voiceUrl: String) {
|
||||||
|
pauseAudioContentService()
|
||||||
|
stopContent()
|
||||||
|
|
||||||
|
currentPlayingPosition = position
|
||||||
|
currentPlayingApplicantId = applicantId
|
||||||
|
|
||||||
|
mediaPlayer = MediaPlayer().apply {
|
||||||
|
setAudioAttributes(
|
||||||
|
AudioAttributes.Builder()
|
||||||
|
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
|
||||||
|
.setUsage(AudioAttributes.USAGE_MEDIA)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
|
||||||
|
try {
|
||||||
|
setDataSource(context, Uri.parse(voiceUrl))
|
||||||
|
prepareAsync() // 비동기적으로 준비
|
||||||
|
setOnPreparedListener {
|
||||||
|
start()
|
||||||
|
updateUI(currentPlayingPosition, true)
|
||||||
|
}
|
||||||
|
} catch (e: IOException) {
|
||||||
|
e.printStackTrace()
|
||||||
|
Toast.makeText(context, "콘텐츠를 재생하지 못했습니다.\n다시 시도해 주세요", Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
|
||||||
|
setOnCompletionListener {
|
||||||
|
updateUI(currentPlayingPosition, false)
|
||||||
|
currentPlayingApplicantId = -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun pauseAudioContentService() {
|
||||||
|
context.startService(
|
||||||
|
Intent(
|
||||||
|
context,
|
||||||
|
AudioContentPlayService::class.java
|
||||||
|
).apply {
|
||||||
|
action = AudioContentPlayService.MusicAction.PAUSE.name
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
context.startService(
|
||||||
|
Intent(context, AudioContentPlayerService::class.java).apply {
|
||||||
|
action = "STOP_SERVICE"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,6 +16,7 @@ import coil.transform.RoundedCornersTransformation
|
||||||
import kr.co.vividnext.sodalive.R
|
import kr.co.vividnext.sodalive.R
|
||||||
import kr.co.vividnext.sodalive.audition.applicant.ApplicationMethodDialog
|
import kr.co.vividnext.sodalive.audition.applicant.ApplicationMethodDialog
|
||||||
import kr.co.vividnext.sodalive.audition.applicant.AuditionApplicantListAdapter
|
import kr.co.vividnext.sodalive.audition.applicant.AuditionApplicantListAdapter
|
||||||
|
import kr.co.vividnext.sodalive.audition.applicant.AuditionApplicantMediaPlayerManager
|
||||||
import kr.co.vividnext.sodalive.audition.applicant.AuditionApplyDialogFragment
|
import kr.co.vividnext.sodalive.audition.applicant.AuditionApplyDialogFragment
|
||||||
import kr.co.vividnext.sodalive.base.BaseActivity
|
import kr.co.vividnext.sodalive.base.BaseActivity
|
||||||
import kr.co.vividnext.sodalive.base.SodaDialog
|
import kr.co.vividnext.sodalive.base.SodaDialog
|
||||||
|
@ -72,6 +73,8 @@ class AuditionRoleDetailActivity : BaseActivity<ActivityAuditionRoleDetailBindin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private lateinit var mediaPlayerManager: AuditionApplicantMediaPlayerManager
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
auditionRoleId = intent.getLongExtra(Constants.EXTRA_AUDITION_ROLE_ID, 0)
|
auditionRoleId = intent.getLongExtra(Constants.EXTRA_AUDITION_ROLE_ID, 0)
|
||||||
|
|
||||||
|
@ -87,10 +90,26 @@ class AuditionRoleDetailActivity : BaseActivity<ActivityAuditionRoleDetailBindin
|
||||||
|
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
mediaPlayerManager = AuditionApplicantMediaPlayerManager(
|
||||||
|
this
|
||||||
|
) { position, isPlaying ->
|
||||||
|
adapter.updatePlayingIndex(position, isPlaying)
|
||||||
|
}
|
||||||
|
|
||||||
bindData()
|
bindData()
|
||||||
viewModel.getAuditionRoleDetail(auditionRoleId = auditionRoleId)
|
viewModel.getAuditionRoleDetail(auditionRoleId = auditionRoleId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onPause() {
|
||||||
|
mediaPlayerManager.pauseContent()
|
||||||
|
super.onPause()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
mediaPlayerManager.stopContent()
|
||||||
|
super.onDestroy()
|
||||||
|
}
|
||||||
|
|
||||||
override fun setupView() {
|
override fun setupView() {
|
||||||
loadingDialog = LoadingDialog(this, layoutInflater)
|
loadingDialog = LoadingDialog(this, layoutInflater)
|
||||||
binding.toolbar.tvBack.setOnClickListener { finish() }
|
binding.toolbar.tvBack.setOnClickListener { finish() }
|
||||||
|
@ -133,15 +152,19 @@ class AuditionRoleDetailActivity : BaseActivity<ActivityAuditionRoleDetailBindin
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.tvSortNewest.setOnClickListener {
|
binding.tvSortNewest.setOnClickListener {
|
||||||
|
mediaPlayerManager.stopContent()
|
||||||
viewModel.setSortType(AuditionRoleDetailViewModel.AuditionApplicantSortType.NEWEST)
|
viewModel.setSortType(AuditionRoleDetailViewModel.AuditionApplicantSortType.NEWEST)
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.tvSortLikes.setOnClickListener {
|
binding.tvSortLikes.setOnClickListener {
|
||||||
|
mediaPlayerManager.stopContent()
|
||||||
viewModel.setSortType(AuditionRoleDetailViewModel.AuditionApplicantSortType.LIKES)
|
viewModel.setSortType(AuditionRoleDetailViewModel.AuditionApplicantSortType.LIKES)
|
||||||
}
|
}
|
||||||
|
|
||||||
adapter = AuditionApplicantListAdapter(
|
adapter = AuditionApplicantListAdapter(
|
||||||
onClickPlayOrPause = {},
|
onClickPlayOrPause = { position, applicantId, voiceUrl ->
|
||||||
|
mediaPlayerManager.toggleContent(position, applicantId, voiceUrl)
|
||||||
|
},
|
||||||
onClickVote = {
|
onClickVote = {
|
||||||
if (isShowNotifyVote) {
|
if (isShowNotifyVote) {
|
||||||
SodaDialog(
|
SodaDialog(
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:paddingHorizontal="13.3dp"
|
android:paddingHorizontal="13.3dp"
|
||||||
android:paddingTop="18.7dp"
|
|
||||||
tools:background="@color/black">
|
tools:background="@color/black">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
|
|
Loading…
Reference in New Issue