콘텐츠 메인 다시듣기 탭
- 채널별 라이브 다시듣기 추가
This commit is contained in:
		@@ -344,6 +344,12 @@ interface AudioContentApi {
 | 
			
		||||
        @Header("Authorization") authHeader: String
 | 
			
		||||
    ): Single<ApiResponse<GetContentMainTabLiveReplayResponse>>
 | 
			
		||||
 | 
			
		||||
    @GET("/v2/audio-content/main/replay/popular-content-by-creator")
 | 
			
		||||
    fun getPopularReplayContentByCreator(
 | 
			
		||||
        @Query("creatorId") creatorId: Long,
 | 
			
		||||
        @Header("Authorization") authHeader: String
 | 
			
		||||
    ): Single<ApiResponse<GetPopularContentByCreatorResponse>>
 | 
			
		||||
 | 
			
		||||
    @GET("/v2/audio-content/main/free")
 | 
			
		||||
    fun getContentMainFree(
 | 
			
		||||
        @Header("Authorization") authHeader: String
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
package kr.co.vividnext.sodalive.audio_content.main.v2.asmr
 | 
			
		||||
 | 
			
		||||
import android.annotation.SuppressLint
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.widget.Toast
 | 
			
		||||
@@ -36,6 +37,7 @@ class AsmrNewContentAllActivity : BaseActivity<ActivityAsmrNewContentAllBinding>
 | 
			
		||||
        viewModel.selectTheme(theme = "ASMR", isFree = false)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @SuppressLint("SetTextI18n")
 | 
			
		||||
    override fun setupView() {
 | 
			
		||||
        loadingDialog = LoadingDialog(this, layoutInflater)
 | 
			
		||||
        binding.toolbar.tvBack.text = "새로운 ASMR"
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,9 @@ import android.graphics.Rect
 | 
			
		||||
import android.net.Uri
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.view.View
 | 
			
		||||
import android.widget.ImageView
 | 
			
		||||
import android.widget.LinearLayout
 | 
			
		||||
import android.widget.TextView
 | 
			
		||||
import android.widget.Toast
 | 
			
		||||
import androidx.annotation.OptIn
 | 
			
		||||
import androidx.core.content.ContextCompat
 | 
			
		||||
@@ -14,6 +16,9 @@ import androidx.media3.common.util.UnstableApi
 | 
			
		||||
import androidx.recyclerview.widget.GridLayoutManager
 | 
			
		||||
import androidx.recyclerview.widget.LinearLayoutManager
 | 
			
		||||
import androidx.recyclerview.widget.RecyclerView
 | 
			
		||||
import coil.load
 | 
			
		||||
import coil.transform.CircleCropTransformation
 | 
			
		||||
import coil.transform.RoundedCornersTransformation
 | 
			
		||||
import com.zhpan.bannerview.BaseBannerAdapter
 | 
			
		||||
import com.zhpan.indicator.enums.IndicatorSlideMode
 | 
			
		||||
import com.zhpan.indicator.enums.IndicatorStyle
 | 
			
		||||
@@ -21,9 +26,11 @@ import kr.co.vividnext.sodalive.R
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.detail.AudioContentDetailActivity
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.main.AudioContentBannerType
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.main.AudioContentMainContentAdapter
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentRankingItem
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.main.banner.AudioContentMainBannerAdapter
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.main.ranking.AudioContentMainRankingAdapter
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.main.v2.AudioContentMainContentCurationAdapter
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.main.v2.ContentRankCreatorAdapter
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.series.detail.SeriesDetailActivity
 | 
			
		||||
import kr.co.vividnext.sodalive.base.BaseFragment
 | 
			
		||||
import kr.co.vividnext.sodalive.common.Constants
 | 
			
		||||
@@ -47,6 +54,7 @@ class AudioContentMainTabReplayFragment : BaseFragment<FragmentAudioContentMainT
 | 
			
		||||
    private lateinit var newContentAdapter: AudioContentMainContentAdapter
 | 
			
		||||
    private lateinit var contentRankingAdapter: AudioContentMainRankingAdapter
 | 
			
		||||
    private lateinit var curationAdapter: AudioContentMainContentCurationAdapter
 | 
			
		||||
    private lateinit var contentRankCreatorAdapter: ContentRankCreatorAdapter
 | 
			
		||||
 | 
			
		||||
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
 | 
			
		||||
        super.onViewCreated(view, savedInstanceState)
 | 
			
		||||
@@ -62,6 +70,7 @@ class AudioContentMainTabReplayFragment : BaseFragment<FragmentAudioContentMainT
 | 
			
		||||
        setupContentBanner()
 | 
			
		||||
        setupNewContent()
 | 
			
		||||
        setupContentRanking()
 | 
			
		||||
        setupPopularContentByCreator()
 | 
			
		||||
        setupEventBanner()
 | 
			
		||||
        setupCuration()
 | 
			
		||||
    }
 | 
			
		||||
@@ -265,6 +274,66 @@ class AudioContentMainTabReplayFragment : BaseFragment<FragmentAudioContentMainT
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun setupPopularContentByCreator() {
 | 
			
		||||
        contentRankCreatorAdapter = ContentRankCreatorAdapter {
 | 
			
		||||
            loadingPopularContentByCreator()
 | 
			
		||||
            viewModel.getPopularContentByCreator(it)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        binding.rvRankingCreator.layoutManager = LinearLayoutManager(
 | 
			
		||||
            context,
 | 
			
		||||
            LinearLayoutManager.HORIZONTAL,
 | 
			
		||||
            false
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        binding.rvRankingCreator.addItemDecoration(object : RecyclerView.ItemDecoration() {
 | 
			
		||||
            override fun getItemOffsets(
 | 
			
		||||
                outRect: Rect,
 | 
			
		||||
                view: View,
 | 
			
		||||
                parent: RecyclerView,
 | 
			
		||||
                state: RecyclerView.State
 | 
			
		||||
            ) {
 | 
			
		||||
                super.getItemOffsets(outRect, view, parent, state)
 | 
			
		||||
 | 
			
		||||
                when (parent.getChildAdapterPosition(view)) {
 | 
			
		||||
                    0 -> {
 | 
			
		||||
                        outRect.left = 0
 | 
			
		||||
                        outRect.right = 4f.dpToPx().toInt()
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    contentRankCreatorAdapter.itemCount - 1 -> {
 | 
			
		||||
                        outRect.left = 4f.dpToPx().toInt()
 | 
			
		||||
                        outRect.right = 0
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    else -> {
 | 
			
		||||
                        outRect.left = 4f.dpToPx().toInt()
 | 
			
		||||
                        outRect.right = 4f.dpToPx().toInt()
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
 | 
			
		||||
        binding.rvRankingCreator.adapter = contentRankCreatorAdapter
 | 
			
		||||
 | 
			
		||||
        viewModel.contentCreatorListLiveData.observe(viewLifecycleOwner) {
 | 
			
		||||
            contentRankCreatorAdapter.addItems(it)
 | 
			
		||||
            if (contentRankCreatorAdapter.itemCount <= 0 && it.isEmpty()) {
 | 
			
		||||
                binding.llCreatorContentRanking.visibility = View.GONE
 | 
			
		||||
            } else {
 | 
			
		||||
                binding.llCreatorContentRanking.visibility = View.VISIBLE
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun loadingPopularContentByCreator() {
 | 
			
		||||
        binding.llSales2.visibility = View.GONE
 | 
			
		||||
        binding.llSalesTop2.visibility = View.GONE
 | 
			
		||||
        binding.llSalesCount2.visibility = View.GONE
 | 
			
		||||
        binding.llSalesCountTop2.visibility = View.GONE
 | 
			
		||||
        binding.llNoItems.visibility = View.VISIBLE
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun setupEventBanner() {
 | 
			
		||||
        val imageSliderLp = binding.eventBannerSlider.layoutParams
 | 
			
		||||
        imageSliderLp.width = screenWidth
 | 
			
		||||
@@ -391,5 +460,94 @@ class AudioContentMainTabReplayFragment : BaseFragment<FragmentAudioContentMainT
 | 
			
		||||
                loadingDialog.dismiss()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        viewModel.salesRankContentListLiveData.observe(viewLifecycleOwner) {
 | 
			
		||||
            if (it.isNotEmpty()) {
 | 
			
		||||
                binding.llNoItems.visibility = View.GONE
 | 
			
		||||
                binding.llSalesTop2.visibility = View.VISIBLE
 | 
			
		||||
 | 
			
		||||
                setSalesRankContent(
 | 
			
		||||
                    item = it[0],
 | 
			
		||||
                    titleTextView = binding.tvSalesTitle1,
 | 
			
		||||
                    coverImageView = binding.ivSales1,
 | 
			
		||||
                    creatorTextView = binding.tvSalesCreator1,
 | 
			
		||||
                    creatorImageView = binding.ivSalesCreator1
 | 
			
		||||
                )
 | 
			
		||||
 | 
			
		||||
                if (it.size > 1) {
 | 
			
		||||
                    binding.llSales2.visibility = View.VISIBLE
 | 
			
		||||
                    setSalesRankContent(
 | 
			
		||||
                        item = it[1],
 | 
			
		||||
                        titleTextView = binding.tvSalesTitle2,
 | 
			
		||||
                        coverImageView = binding.ivSales2,
 | 
			
		||||
                        creatorTextView = binding.tvSalesCreator2,
 | 
			
		||||
                        creatorImageView = binding.ivSalesCreator2
 | 
			
		||||
                    )
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        viewModel.salesCountRankContentListLiveData.observe(viewLifecycleOwner) {
 | 
			
		||||
            if (it.isNotEmpty()) {
 | 
			
		||||
                binding.llNoItems.visibility = View.GONE
 | 
			
		||||
                binding.llSalesCountTop2.visibility = View.VISIBLE
 | 
			
		||||
 | 
			
		||||
                setSalesRankContent(
 | 
			
		||||
                    item = it[0],
 | 
			
		||||
                    titleTextView = binding.tvSalesCountTitle1,
 | 
			
		||||
                    coverImageView = binding.ivSalesCount1,
 | 
			
		||||
                    creatorTextView = binding.tvSalesCountCreator1,
 | 
			
		||||
                    creatorImageView = binding.ivSalesCountCreator1
 | 
			
		||||
                )
 | 
			
		||||
 | 
			
		||||
                if (it.size > 1) {
 | 
			
		||||
                    binding.llSalesCount2.visibility = View.VISIBLE
 | 
			
		||||
                    setSalesRankContent(
 | 
			
		||||
                        item = it[1],
 | 
			
		||||
                        titleTextView = binding.tvSalesCountTitle2,
 | 
			
		||||
                        coverImageView = binding.ivSalesCount2,
 | 
			
		||||
                        creatorTextView = binding.tvSalesCountCreator2,
 | 
			
		||||
                        creatorImageView = binding.ivSalesCountCreator2
 | 
			
		||||
                    )
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun setSalesRankContent(
 | 
			
		||||
        item: GetAudioContentRankingItem,
 | 
			
		||||
        titleTextView: TextView,
 | 
			
		||||
        creatorTextView: TextView,
 | 
			
		||||
        coverImageView: ImageView,
 | 
			
		||||
        creatorImageView: ImageView
 | 
			
		||||
    ) {
 | 
			
		||||
        coverImageView.load(item.coverImageUrl) {
 | 
			
		||||
            crossfade(true)
 | 
			
		||||
            placeholder(R.drawable.bg_placeholder)
 | 
			
		||||
            transformations(RoundedCornersTransformation(5.3f.dpToPx()))
 | 
			
		||||
        }
 | 
			
		||||
        titleTextView.text = item.title
 | 
			
		||||
        creatorTextView.text = item.creatorNickname
 | 
			
		||||
        creatorImageView.load(item.creatorProfileImageUrl) {
 | 
			
		||||
            transformations(CircleCropTransformation())
 | 
			
		||||
            placeholder(R.drawable.ic_place_holder)
 | 
			
		||||
            crossfade(true)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        coverImageView.setOnClickListener {
 | 
			
		||||
            startActivity(
 | 
			
		||||
                Intent(requireActivity(), AudioContentDetailActivity::class.java).apply {
 | 
			
		||||
                    putExtra(Constants.EXTRA_AUDIO_CONTENT_ID, item.contentId)
 | 
			
		||||
                }
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        creatorImageView.setOnClickListener {
 | 
			
		||||
            startActivity(
 | 
			
		||||
                Intent(requireActivity(), UserProfileActivity::class.java).apply {
 | 
			
		||||
                    putExtra(Constants.EXTRA_USER_ID, item.creatorId)
 | 
			
		||||
                }
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,4 +4,8 @@ import kr.co.vividnext.sodalive.audio_content.AudioContentApi
 | 
			
		||||
 | 
			
		||||
class AudioContentMainTabReplayRepository(private val api: AudioContentApi) {
 | 
			
		||||
    fun getContentMainReplay(token: String) = api.getContentMainReplay(authHeader = token)
 | 
			
		||||
    fun getPopularContentByCreator(
 | 
			
		||||
        creatorId: Long,
 | 
			
		||||
        token: String
 | 
			
		||||
    ) = api.getPopularReplayContentByCreator(creatorId, authHeader = token)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@ import androidx.lifecycle.MutableLiveData
 | 
			
		||||
import com.orhanobut.logger.Logger
 | 
			
		||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
 | 
			
		||||
import io.reactivex.rxjava3.schedulers.Schedulers
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.main.ContentCreatorResponse
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentBannerResponse
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentMainItem
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentRankingItem
 | 
			
		||||
@@ -36,6 +37,19 @@ class AudioContentMainTabReplayViewModel(
 | 
			
		||||
    val contentRankingLiveData: LiveData<List<GetAudioContentRankingItem>>
 | 
			
		||||
        get() = _contentRankingLiveData
 | 
			
		||||
 | 
			
		||||
    private val _contentCreatorListLiveData = MutableLiveData<List<ContentCreatorResponse>>()
 | 
			
		||||
    val contentCreatorListLiveData: LiveData<List<ContentCreatorResponse>>
 | 
			
		||||
        get() = _contentCreatorListLiveData
 | 
			
		||||
 | 
			
		||||
    private val _salesRankContentListLiveData = MutableLiveData<List<GetAudioContentRankingItem>>()
 | 
			
		||||
    val salesRankContentListLiveData: LiveData<List<GetAudioContentRankingItem>>
 | 
			
		||||
        get() = _salesRankContentListLiveData
 | 
			
		||||
 | 
			
		||||
    private val _salesCountRankContentListLiveData =
 | 
			
		||||
        MutableLiveData<List<GetAudioContentRankingItem>>()
 | 
			
		||||
    val salesCountRankContentListLiveData: LiveData<List<GetAudioContentRankingItem>>
 | 
			
		||||
        get() = _salesCountRankContentListLiveData
 | 
			
		||||
 | 
			
		||||
    private val _eventLiveData = MutableLiveData<List<EventItem>>()
 | 
			
		||||
    val eventLiveData: LiveData<List<EventItem>>
 | 
			
		||||
        get() = _eventLiveData
 | 
			
		||||
@@ -59,6 +73,10 @@ class AudioContentMainTabReplayViewModel(
 | 
			
		||||
                            _contentBannerLiveData.value = data.contentBannerList
 | 
			
		||||
                            _newContentListLiveData.value = data.newLiveReplayContentList
 | 
			
		||||
                            _contentRankingLiveData.value = data.rankLiveReplayContentList
 | 
			
		||||
                            _contentCreatorListLiveData.value = data.creatorList
 | 
			
		||||
                            _salesRankContentListLiveData.value = data.salesRankContentList
 | 
			
		||||
                            _salesCountRankContentListLiveData.value =
 | 
			
		||||
                                data.salesCountRankContentList
 | 
			
		||||
                            _eventLiveData.value = data.eventBannerList.eventList
 | 
			
		||||
                            _curationListLiveData.value = data.curationList
 | 
			
		||||
                        } else {
 | 
			
		||||
@@ -81,4 +99,40 @@ class AudioContentMainTabReplayViewModel(
 | 
			
		||||
                )
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun getPopularContentByCreator(creatorId: Long) {
 | 
			
		||||
        _isLoading.value = true
 | 
			
		||||
        compositeDisposable.add(
 | 
			
		||||
            repository.getPopularContentByCreator(
 | 
			
		||||
                creatorId = creatorId,
 | 
			
		||||
                token = "Bearer ${SharedPreferenceManager.token}"
 | 
			
		||||
            )
 | 
			
		||||
                .subscribeOn(Schedulers.io())
 | 
			
		||||
                .observeOn(AndroidSchedulers.mainThread())
 | 
			
		||||
                .subscribe(
 | 
			
		||||
                    {
 | 
			
		||||
                        _isLoading.value = false
 | 
			
		||||
                        if (it.success && it.data != null) {
 | 
			
		||||
                            val data = it.data
 | 
			
		||||
                            _salesRankContentListLiveData.value = data.salesRankContentList
 | 
			
		||||
                            _salesCountRankContentListLiveData.value =
 | 
			
		||||
                                data.salesCountRankContentList
 | 
			
		||||
                        } else {
 | 
			
		||||
                            if (it.message != null) {
 | 
			
		||||
                                _toastLiveData.postValue(it.message)
 | 
			
		||||
                            } else {
 | 
			
		||||
                                _toastLiveData.postValue(
 | 
			
		||||
                                    "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
 | 
			
		||||
                                )
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    },
 | 
			
		||||
                    {
 | 
			
		||||
                        _isLoading.value = false
 | 
			
		||||
                        it.message?.let { message -> Logger.e(message) }
 | 
			
		||||
                        _toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
 | 
			
		||||
                    }
 | 
			
		||||
                )
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@ package kr.co.vividnext.sodalive.audio_content.main.v2.replay
 | 
			
		||||
 | 
			
		||||
import androidx.annotation.Keep
 | 
			
		||||
import com.google.gson.annotations.SerializedName
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.main.ContentCreatorResponse
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentBannerResponse
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentMainItem
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentRankingItem
 | 
			
		||||
@@ -10,9 +11,20 @@ import kr.co.vividnext.sodalive.settings.event.GetEventResponse
 | 
			
		||||
 | 
			
		||||
@Keep
 | 
			
		||||
data class GetContentMainTabLiveReplayResponse(
 | 
			
		||||
    @SerializedName("contentBannerList") val contentBannerList: List<GetAudioContentBannerResponse>,
 | 
			
		||||
    @SerializedName("newLiveReplayContentList") val newLiveReplayContentList: List<GetAudioContentMainItem>,
 | 
			
		||||
    @SerializedName("rankLiveReplayContentList") val rankLiveReplayContentList: List<GetAudioContentRankingItem>,
 | 
			
		||||
    @SerializedName("eventBannerList") val eventBannerList: GetEventResponse,
 | 
			
		||||
    @SerializedName("curationList") val curationList: List<GetContentCurationResponse>
 | 
			
		||||
    @SerializedName("contentBannerList")
 | 
			
		||||
    val contentBannerList: List<GetAudioContentBannerResponse>,
 | 
			
		||||
    @SerializedName("newLiveReplayContentList")
 | 
			
		||||
    val newLiveReplayContentList: List<GetAudioContentMainItem>,
 | 
			
		||||
    @SerializedName("rankLiveReplayContentList")
 | 
			
		||||
    val rankLiveReplayContentList: List<GetAudioContentRankingItem>,
 | 
			
		||||
    @SerializedName("creatorList")
 | 
			
		||||
    val creatorList: List<ContentCreatorResponse>,
 | 
			
		||||
    @SerializedName("salesRankContentList")
 | 
			
		||||
    val salesRankContentList: List<GetAudioContentRankingItem>,
 | 
			
		||||
    @SerializedName("salesCountRankContentList")
 | 
			
		||||
    val salesCountRankContentList: List<GetAudioContentRankingItem>,
 | 
			
		||||
    @SerializedName("eventBannerList")
 | 
			
		||||
    val eventBannerList: GetEventResponse,
 | 
			
		||||
    @SerializedName("curationList")
 | 
			
		||||
    val curationList: List<GetContentCurationResponse>
 | 
			
		||||
)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user