From 363d611e0fc5248902d6b80c8ff50cd056c9f0be Mon Sep 17 00:00:00 2001 From: klaus Date: Thu, 13 Feb 2025 16:30:40 +0900 Subject: [PATCH] =?UTF-8?q?=EC=BD=98=ED=85=90=EC=B8=A0=20=EB=A9=94?= =?UTF-8?q?=EC=9D=B8=20-=20=EB=8B=A8=ED=8E=B8=20=ED=83=AD=20UI=20=EA=B5=AC?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sodalive/audio_content/AudioContentApi.kt | 27 + .../AudioContentMainTabContentFragment.kt | 565 ++++++++++++++++++ .../AudioContentMainTabContentRepository.kt | 28 + .../AudioContentMainTabContentViewModel.kt | 217 +++++++ .../GetContentMainTabContentResponse.kt | 22 + .../AudioContentMainTabSeriesViewModel.kt | 2 - .../java/kr/co/vividnext/sodalive/di/AppDI.kt | 4 + ...ragment_audio_content_main_tab_content.xml | 422 ++++++++++++- 8 files changed, 1282 insertions(+), 5 deletions(-) create mode 100644 app/src/main/java/kr/co/vividnext/sodalive/audio_content/main/v2/content/AudioContentMainTabContentRepository.kt create mode 100644 app/src/main/java/kr/co/vividnext/sodalive/audio_content/main/v2/content/AudioContentMainTabContentViewModel.kt create mode 100644 app/src/main/java/kr/co/vividnext/sodalive/audio_content/main/v2/content/GetContentMainTabContentResponse.kt diff --git a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/AudioContentApi.kt b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/AudioContentApi.kt index 75cd06b..559306f 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/AudioContentApi.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/AudioContentApi.kt @@ -15,7 +15,9 @@ import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentBannerResponse import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentCurationResponse import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentMainItem import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentRanking +import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentRankingItem import kr.co.vividnext.sodalive.audio_content.main.v2.GetPopularContentByCreatorResponse +import kr.co.vividnext.sodalive.audio_content.main.v2.content.GetContentMainTabContentResponse import kr.co.vividnext.sodalive.audio_content.main.v2.home.GetContentMainTabHomeResponse import kr.co.vividnext.sodalive.audio_content.main.v2.series.GetContentMainTabSeriesResponse import kr.co.vividnext.sodalive.audio_content.order.GetAudioContentOrderListResponse @@ -255,4 +257,29 @@ interface AudioContentApi { fun getContentMainSeries( @Header("Authorization") authHeader: String ): Single> + + @GET("/v2/audio-content/main/content") + fun getContentMainContent( + @Header("Authorization") authHeader: String + ): Single> + + @GET("/v2/audio-content/main/content/new-content-by-theme") + fun getContentMainNewContentOfTheme( + @Query("theme") theme: String, + @Query("isAdultContentVisible") isAdultContentVisible: Boolean, + @Query("contentType") contentType: ContentType, + @Header("Authorization") authHeader: String + ): Single>> + + @GET("/v2/audio-content/main/content/ranking") + fun getDailyContentRanking( + @Query("sort-type") sortType: String, + @Header("Authorization") authHeader: String + ): Single>> + + @GET("/v2/audio-content/main/content/popular-content-by-creator") + fun getContentMainContentPopularContentByCreator( + @Query("creatorId") creatorId: Long, + @Header("Authorization") authHeader: String + ): Single> } diff --git a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/main/v2/content/AudioContentMainTabContentFragment.kt b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/main/v2/content/AudioContentMainTabContentFragment.kt index 1e23d84..7bd83dc 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/main/v2/content/AudioContentMainTabContentFragment.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/main/v2/content/AudioContentMainTabContentFragment.kt @@ -1,9 +1,574 @@ package kr.co.vividnext.sodalive.audio_content.main.v2.content +import android.annotation.SuppressLint +import android.content.Intent +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 +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 +import kr.co.vividnext.sodalive.R +import kr.co.vividnext.sodalive.audio_content.all.AudioContentNewAllActivity +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.new_content.AudioContentMainNewContentThemeAdapter +import kr.co.vividnext.sodalive.audio_content.main.ranking.AudioContentMainRankingAdapter +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 +import kr.co.vividnext.sodalive.common.LoadingDialog import kr.co.vividnext.sodalive.databinding.FragmentAudioContentMainTabContentBinding +import kr.co.vividnext.sodalive.explorer.profile.UserProfileActivity +import kr.co.vividnext.sodalive.extensions.dpToPx +import kr.co.vividnext.sodalive.live.event_banner.EventBannerAdapter +import kr.co.vividnext.sodalive.settings.event.EventDetailActivity +import org.koin.android.ext.android.inject +import kotlin.math.roundToInt +@OptIn(UnstableApi::class) class AudioContentMainTabContentFragment : BaseFragment( FragmentAudioContentMainTabContentBinding::inflate ) { + private val viewModel: AudioContentMainTabContentViewModel by inject() + + private lateinit var loadingDialog: LoadingDialog + private lateinit var contentBannerAdapter: AudioContentMainBannerAdapter + private lateinit var newContentThemeAdapter: AudioContentMainNewContentThemeAdapter + private lateinit var newContentAdapter: AudioContentMainContentAdapter + private lateinit var contentRankingSortAdapter: AudioContentMainNewContentThemeAdapter + private lateinit var contentRankingAdapter: AudioContentMainRankingAdapter + private lateinit var contentRankCreatorAdapter: ContentRankCreatorAdapter + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setupView() + bindData() + + viewModel.fetchData() + } + + private fun setupView() { + loadingDialog = LoadingDialog(requireActivity(), layoutInflater) + + setupContentBanner() + setupNewContentTheme() + setupNewContent() + setupContentRankingSortType() + setupContentRanking() + setupEventBanner() + setupPopularContentByCreator() + } + + private fun setupContentBanner() { + val layoutParams = binding + .rvBanner + .layoutParams as LinearLayout.LayoutParams + + val pagerWidth = screenWidth.toDouble() - 26.7f.dpToPx() + val pagerHeight = (pagerWidth * 0.53).roundToInt() + layoutParams.width = pagerWidth.roundToInt() + layoutParams.height = pagerHeight + + contentBannerAdapter = AudioContentMainBannerAdapter( + requireContext(), + pagerWidth.roundToInt(), + pagerHeight + ) { + when (it.type) { + AudioContentBannerType.EVENT -> { + startActivity( + Intent(requireContext(), EventDetailActivity::class.java).apply { + putExtra(Constants.EXTRA_EVENT, it.eventItem!!) + } + ) + } + + AudioContentBannerType.CREATOR -> { + startActivity( + Intent(requireContext(), UserProfileActivity::class.java).apply { + putExtra(Constants.EXTRA_USER_ID, it.creatorId!!) + } + ) + } + + AudioContentBannerType.SERIES -> { + startActivity( + Intent(requireContext(), SeriesDetailActivity::class.java).apply { + putExtra(Constants.EXTRA_SERIES_ID, it.seriesId!!) + } + ) + } + + AudioContentBannerType.LINK -> { + startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(it.link!!))) + } + } + } + + binding + .rvBanner + .layoutParams = layoutParams + + binding.rvBanner.apply { + adapter = contentBannerAdapter as BaseBannerAdapter + + setLifecycleRegistry(lifecycle) + setScrollDuration(1000) + setInterval(4 * 1000) + }.create() + + binding + .rvBanner + .setIndicatorView(binding.indicatorBanner) + .setIndicatorStyle(IndicatorStyle.ROUND_RECT) + .setIndicatorSlideMode(IndicatorSlideMode.SMOOTH) + .setIndicatorVisibility(View.GONE) + .setIndicatorSliderColor( + ContextCompat.getColor(requireContext(), R.color.color_909090), + ContextCompat.getColor(requireContext(), R.color.color_3bb9f1) + ) + .setIndicatorSliderWidth(4f.dpToPx().toInt(), 10f.dpToPx().toInt()) + .setIndicatorHeight(4f.dpToPx().toInt()) + + viewModel.contentBannerLiveData.observe(viewLifecycleOwner) { + if (contentBannerAdapter.itemCount <= 0 && it.isEmpty()) { + binding.rvBanner.visibility = View.GONE + binding.indicatorBanner.visibility = View.GONE + } else { + binding.rvBanner.visibility = View.VISIBLE + binding.indicatorBanner.visibility = View.VISIBLE + binding.rvBanner.refreshData(it) + } + } + } + + private fun setupNewContentTheme() { + newContentThemeAdapter = AudioContentMainNewContentThemeAdapter { + viewModel.getNewContentOfTheme(theme = it) + } + + binding.rvNewContentTheme.layoutManager = LinearLayoutManager( + context, + LinearLayoutManager.HORIZONTAL, + false + ) + + binding.rvNewContentTheme.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() + } + + newContentThemeAdapter.itemCount - 1 -> { + outRect.left = 4f.dpToPx().toInt() + outRect.right = 0 + } + + else -> { + outRect.left = 4f.dpToPx().toInt() + outRect.right = 4f.dpToPx().toInt() + } + } + } + }) + + binding.rvNewContentTheme.adapter = newContentThemeAdapter + + viewModel.themeListLiveData.observe(viewLifecycleOwner) { + binding.llNewContent.visibility = View.VISIBLE + newContentThemeAdapter.addItems(it) + } + } + + private fun setupNewContent() { + binding.ivNewContentAll.setOnClickListener { + startActivity(Intent(requireContext(), AudioContentNewAllActivity::class.java)) + } + + newContentAdapter = AudioContentMainContentAdapter( + onClickItem = { + startActivity( + Intent(requireContext(), AudioContentDetailActivity::class.java).apply { + putExtra(Constants.EXTRA_AUDIO_CONTENT_ID, it) + } + ) + }, + onClickCreator = { + startActivity( + Intent(requireContext(), UserProfileActivity::class.java).apply { + putExtra(Constants.EXTRA_USER_ID, it) + } + ) + } + ) + + binding.rvNewContent.layoutManager = LinearLayoutManager( + context, + LinearLayoutManager.HORIZONTAL, + false + ) + + binding.rvNewContent.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 = 6.7f.dpToPx().toInt() + } + + newContentAdapter.itemCount - 1 -> { + outRect.left = 6.7f.dpToPx().toInt() + outRect.right = 0 + } + + else -> { + outRect.left = 6.7f.dpToPx().toInt() + outRect.right = 6.7f.dpToPx().toInt() + } + } + } + }) + + binding.rvNewContent.adapter = newContentAdapter + + viewModel.newContentListLiveData.observe(viewLifecycleOwner) { + newContentAdapter.addItems(it) + } + } + + private fun setupContentRankingSortType() { + contentRankingSortAdapter = AudioContentMainNewContentThemeAdapter { + viewModel.getContentRanking(sort = it) + } + + binding.rvContentRankingSort.layoutManager = LinearLayoutManager( + context, + LinearLayoutManager.HORIZONTAL, + false + ) + + binding.rvContentRankingSort.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() + } + + contentRankingSortAdapter.itemCount - 1 -> { + outRect.left = 4f.dpToPx().toInt() + outRect.right = 0 + } + + else -> { + outRect.left = 4f.dpToPx().toInt() + outRect.right = 4f.dpToPx().toInt() + } + } + } + }) + + binding.rvContentRankingSort.adapter = contentRankingSortAdapter + + viewModel.contentRankingSortListLiveData.observe(viewLifecycleOwner) { + binding.llContentRanking.visibility = View.VISIBLE + contentRankingSortAdapter.addItems(it) + } + } + + @SuppressLint("SetTextI18n") + private fun setupContentRanking() { + contentRankingAdapter = AudioContentMainRankingAdapter( + width = (screenWidth * 0.66).toInt() + ) { + startActivity( + Intent(requireContext(), AudioContentDetailActivity::class.java).apply { + putExtra(Constants.EXTRA_AUDIO_CONTENT_ID, it) + } + ) + } + + binding.rvContentRanking.layoutManager = GridLayoutManager( + context, + 3, + GridLayoutManager.HORIZONTAL, + false + ) + + binding.rvContentRanking.addItemDecoration(object : RecyclerView.ItemDecoration() { + override fun getItemOffsets( + outRect: Rect, + view: View, + parent: RecyclerView, + state: RecyclerView.State + ) { + super.getItemOffsets(outRect, view, parent, state) + outRect.top = 13.3f.dpToPx().toInt() + outRect.bottom = 13.3f.dpToPx().toInt() + outRect.left = 13.3f.dpToPx().toInt() + outRect.right = 13.3f.dpToPx().toInt() + } + }) + + binding.rvContentRanking.adapter = contentRankingAdapter + + viewModel.contentRankingLiveData.observe(viewLifecycleOwner) { + binding.llContentRanking.visibility = View.VISIBLE + contentRankingAdapter.addItems(it) + } + } + + private fun setupEventBanner() { + val imageSliderLp = binding.eventBannerSlider.layoutParams + imageSliderLp.width = screenWidth + imageSliderLp.height = (screenWidth * 300) / 1000 + binding.eventBannerSlider.layoutParams = imageSliderLp + + binding.eventBannerSlider.apply { + adapter = EventBannerAdapter(requireContext()) { + if (it.detailImageUrl != null) { + val intent = Intent(requireActivity(), EventDetailActivity::class.java) + intent.putExtra(Constants.EXTRA_EVENT, it) + startActivity(intent) + } else if (!it.link.isNullOrBlank()) { + startActivity( + Intent( + Intent.ACTION_VIEW, + Uri.parse(it.link) + ) + ) + } + } as BaseBannerAdapter + setLifecycleRegistry(lifecycle) + setScrollDuration(800) + }.create() + + binding.eventBannerSlider + .setIndicatorView(binding.indicatorEventBanner) + .setIndicatorStyle(IndicatorStyle.ROUND_RECT) + .setIndicatorSlideMode(IndicatorSlideMode.SMOOTH) + .setIndicatorVisibility(View.GONE) + .setIndicatorSliderColor( + ContextCompat.getColor(requireContext(), R.color.color_909090), + ContextCompat.getColor(requireContext(), R.color.color_3bb9f1) + ) + .setIndicatorSliderWidth(4f.dpToPx().toInt(), 10f.dpToPx().toInt()) + .setIndicatorHeight(4f.dpToPx().toInt()) + + viewModel.eventLiveData.observe(viewLifecycleOwner) { + if (it.isNotEmpty()) { + binding.eventBannerSlider.visibility = View.VISIBLE + binding.indicatorEventBanner.visibility = View.VISIBLE + binding.eventBannerSlider.refreshData(it) + } else { + binding.eventBannerSlider.visibility = View.GONE + binding.indicatorEventBanner.visibility = View.GONE + } + } + } + + 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.contentRankCreatorListLiveData.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 bindData() { + viewModel.toastLiveData.observe(viewLifecycleOwner) { + it?.let { Toast.makeText(requireContext(), it, Toast.LENGTH_LONG).show() } + } + + viewModel.isLoading.observe(viewLifecycleOwner) { + if (it) { + loadingDialog.show(screenWidth) + } else { + 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) + } + ) + } + } } diff --git a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/main/v2/content/AudioContentMainTabContentRepository.kt b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/main/v2/content/AudioContentMainTabContentRepository.kt new file mode 100644 index 0000000..3d1a454 --- /dev/null +++ b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/main/v2/content/AudioContentMainTabContentRepository.kt @@ -0,0 +1,28 @@ +package kr.co.vividnext.sodalive.audio_content.main.v2.content + +import kr.co.vividnext.sodalive.audio_content.AudioContentApi +import kr.co.vividnext.sodalive.common.SharedPreferenceManager +import kr.co.vividnext.sodalive.settings.ContentType + +class AudioContentMainTabContentRepository(private val api: AudioContentApi) { + fun getContentMainContent(token: String) = api.getContentMainContent(authHeader = token) + fun getNewContentOfTheme(theme: String, token: String) = api.getContentMainNewContentOfTheme( + theme = theme, + isAdultContentVisible = SharedPreferenceManager.isAdultContentVisible, + contentType = ContentType.values()[SharedPreferenceManager.contentPreference], + authHeader = token + ) + + fun getContentRanking( + sortType: String = "매출", + token: String + ) = api.getDailyContentRanking( + sortType = sortType, + authHeader = token + ) + + fun getPopularContentByCreator( + creatorId: Long, + token: String + ) = api.getContentMainContentPopularContentByCreator(creatorId, authHeader = token) +} diff --git a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/main/v2/content/AudioContentMainTabContentViewModel.kt b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/main/v2/content/AudioContentMainTabContentViewModel.kt new file mode 100644 index 0000000..79ac9a5 --- /dev/null +++ b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/main/v2/content/AudioContentMainTabContentViewModel.kt @@ -0,0 +1,217 @@ +package kr.co.vividnext.sodalive.audio_content.main.v2.content + +import androidx.lifecycle.LiveData +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 +import kr.co.vividnext.sodalive.base.BaseViewModel +import kr.co.vividnext.sodalive.common.SharedPreferenceManager +import kr.co.vividnext.sodalive.settings.event.EventItem + +class AudioContentMainTabContentViewModel( + private val repository: AudioContentMainTabContentRepository +) : BaseViewModel() { + private val _toastLiveData = MutableLiveData() + val toastLiveData: LiveData + get() = _toastLiveData + + private var _isLoading = MutableLiveData(false) + val isLoading: LiveData + get() = _isLoading + + private var _contentBannerLiveData = MutableLiveData>() + val contentBannerLiveData: LiveData> + get() = _contentBannerLiveData + + private var _newContentListLiveData = MutableLiveData>() + val newContentListLiveData: LiveData> + get() = _newContentListLiveData + + private var _themeListLiveData = MutableLiveData>() + val themeListLiveData: LiveData> + get() = _themeListLiveData + + private var _contentRankingSortListLiveData = MutableLiveData>() + val contentRankingSortListLiveData: LiveData> + get() = _contentRankingSortListLiveData + + private var _contentRankingLiveData = MutableLiveData>() + val contentRankingLiveData: LiveData> + get() = _contentRankingLiveData + + private val _eventLiveData = MutableLiveData>() + val eventLiveData: LiveData> + get() = _eventLiveData + + private val _contentRankCreatorListLiveData = MutableLiveData>() + val contentRankCreatorListLiveData: LiveData> + get() = _contentRankCreatorListLiveData + + private val _salesRankContentListLiveData = MutableLiveData>() + val salesRankContentListLiveData: LiveData> + get() = _salesRankContentListLiveData + + private val _salesCountRankContentListLiveData = + MutableLiveData>() + val salesCountRankContentListLiveData: LiveData> + get() = _salesCountRankContentListLiveData + + fun fetchData() { + _isLoading.value = true + compositeDisposable.add( + repository.getContentMainContent(token = "Bearer ${SharedPreferenceManager.token}") + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + { + if (it.success && it.data != null) { + val data = it.data + + Logger.e("data: $data") + _contentBannerLiveData.value = data.bannerList + + val themeList = listOf("전체").union(data.contentThemeList).toList() + _themeListLiveData.value = themeList + _newContentListLiveData.value = data.newContentList + + _contentRankingSortListLiveData.value = data.rankSortTypeList + _contentRankingLiveData.value = data.rankContentList + + _eventLiveData.value = data.eventBannerList.eventList + _contentRankCreatorListLiveData.value = data.contentRankCreatorList + _salesRankContentListLiveData.value = data.salesRankContentList + _salesCountRankContentListLiveData.value = + data.salesCountRankContentList + } else { + if (it.message != null) { + _toastLiveData.postValue(it.message) + } else { + _toastLiveData.postValue( + "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요." + ) + } + } + + _isLoading.value = false + }, + { + _isLoading.value = false + it.message?.let { message -> Logger.e(message) } + _toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.") + } + ) + ) + } + + fun getNewContentOfTheme(theme: String) { + _isLoading.value = true + compositeDisposable.add( + repository.getNewContentOfTheme( + theme = if (theme == "전체") { + "" + } else { + theme + }, + token = "Bearer ${SharedPreferenceManager.token}" + ) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + { + if (it.success && it.data != null) { + _newContentListLiveData.value = it.data!! + } else { + if (it.message != null) { + _toastLiveData.postValue(it.message) + } else { + _toastLiveData.postValue( + "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요." + ) + } + } + + _isLoading.value = false + }, + { + it.message?.let { message -> Logger.e(message) } + _toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.") + _isLoading.value = false + } + ) + ) + } + + fun getContentRanking(sort: String = "매출") { + _isLoading.value = true + compositeDisposable.add( + repository.getContentRanking( + sortType = sort, + token = "Bearer ${SharedPreferenceManager.token}" + ) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + { + if (it.success && it.data != null) { + _contentRankingLiveData.value = it.data!! + } else { + if (it.message != null) { + _toastLiveData.postValue(it.message) + } else { + _toastLiveData.postValue( + "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요." + ) + } + } + _isLoading.value = false + }, + { + it.message?.let { message -> Logger.e(message) } + _toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.") + _isLoading.value = false + } + ) + ) + } + + 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("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.") + } + ) + ) + } +} diff --git a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/main/v2/content/GetContentMainTabContentResponse.kt b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/main/v2/content/GetContentMainTabContentResponse.kt new file mode 100644 index 0000000..91225c5 --- /dev/null +++ b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/main/v2/content/GetContentMainTabContentResponse.kt @@ -0,0 +1,22 @@ +package kr.co.vividnext.sodalive.audio_content.main.v2.content + +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 +import kr.co.vividnext.sodalive.settings.event.GetEventResponse + +@Keep +data class GetContentMainTabContentResponse( + @SerializedName("bannerList") val bannerList: List, + @SerializedName("contentThemeList") val contentThemeList: List, + @SerializedName("newContentList") val newContentList: List, + @SerializedName("rankSortTypeList") val rankSortTypeList: List, + @SerializedName("rankContentList") val rankContentList: List, + @SerializedName("contentRankCreatorList") val contentRankCreatorList: List, + @SerializedName("salesRankContentList") val salesRankContentList: List, + @SerializedName("salesCountRankContentList") val salesCountRankContentList: List, + @SerializedName("eventBannerList") val eventBannerList: GetEventResponse +) diff --git a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/main/v2/series/AudioContentMainTabSeriesViewModel.kt b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/main/v2/series/AudioContentMainTabSeriesViewModel.kt index b058bb2..19a8dd4 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/main/v2/series/AudioContentMainTabSeriesViewModel.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/main/v2/series/AudioContentMainTabSeriesViewModel.kt @@ -83,8 +83,6 @@ class AudioContentMainTabSeriesViewModel( if (it.success && it.data != null) { val data = it.data - Logger.e("data: $data") - _contentBannerLiveData.value = data.contentBannerList _originalAudioDramaLiveData.value = data.originalAudioDrama _rankSeriesListLiveData.value = data.rankSeriesList diff --git a/app/src/main/java/kr/co/vividnext/sodalive/di/AppDI.kt b/app/src/main/java/kr/co/vividnext/sodalive/di/AppDI.kt index 065b645..1078099 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/di/AppDI.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/di/AppDI.kt @@ -23,6 +23,8 @@ import kr.co.vividnext.sodalive.audio_content.main.order.AudioContentMainOrderLi import kr.co.vividnext.sodalive.audio_content.main.ranking.AudioContentMainCreatorRankingViewModel import kr.co.vividnext.sodalive.audio_content.main.ranking.AudioContentMainRankingViewModel import kr.co.vividnext.sodalive.audio_content.main.recommend_series.AudioContentMainRecommendSeriesViewModel +import kr.co.vividnext.sodalive.audio_content.main.v2.content.AudioContentMainTabContentRepository +import kr.co.vividnext.sodalive.audio_content.main.v2.content.AudioContentMainTabContentViewModel import kr.co.vividnext.sodalive.audio_content.main.v2.home.AudioContentMainTabHomeRepository import kr.co.vividnext.sodalive.audio_content.main.v2.home.AudioContentMainTabHomeViewModel import kr.co.vividnext.sodalive.audio_content.main.v2.series.AudioContentMainTabSeriesRepository @@ -296,6 +298,7 @@ class AppDI(private val context: Context, isDebugMode: Boolean) { viewModel { AudioContentMainCreatorRankingViewModel(get()) } viewModel { AudioContentMainTabHomeViewModel(get(), get()) } viewModel { AudioContentMainTabSeriesViewModel(get()) } + viewModel { AudioContentMainTabContentViewModel(get()) } } private val repositoryModule = module { @@ -329,6 +332,7 @@ class AppDI(private val context: Context, isDebugMode: Boolean) { factory { AuditionRepository(get()) } factory { AudioContentMainTabHomeRepository(get()) } factory { AudioContentMainTabSeriesRepository(get()) } + factory { AudioContentMainTabContentRepository(get()) } } private val moduleList = listOf( diff --git a/app/src/main/res/layout/fragment_audio_content_main_tab_content.xml b/app/src/main/res/layout/fragment_audio_content_main_tab_content.xml index 1b31835..e26f76b 100644 --- a/app/src/main/res/layout/fragment_audio_content_main_tab_content.xml +++ b/app/src/main/res/layout/fragment_audio_content_main_tab_content.xml @@ -1,7 +1,10 @@ + android:layout_height="match_parent" + tools:background="@color/black"> + android:layout_marginTop="30dp" + android:visibility="gone" /> + android:layout_marginTop="6.7dp" + android:visibility="gone" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +