diff --git a/app/src/main/java/kr/co/vividnext/sodalive/home/ContentRankingSortAdapter.kt b/app/src/main/java/kr/co/vividnext/sodalive/home/ContentRankingSortAdapter.kt new file mode 100644 index 00000000..fd0e8193 --- /dev/null +++ b/app/src/main/java/kr/co/vividnext/sodalive/home/ContentRankingSortAdapter.kt @@ -0,0 +1,59 @@ +package kr.co.vividnext.sodalive.home + +import android.annotation.SuppressLint +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import kr.co.vividnext.sodalive.R +import kr.co.vividnext.sodalive.databinding.ItemHomeContentThemeBinding + +/** + * 보온 주간 차트 정렬 선택 어댑터 + * - 최신 콘텐츠 테마 선택 UI와 동일한 스타일 재사용 + */ +class ContentRankingSortAdapter( + private val onClickSort: (ContentRankingSortType) -> Unit +) : RecyclerView.Adapter() { + + private val sorts = ContentRankingSortType.entries + private var selected: ContentRankingSortType = ContentRankingSortType.REVENUE + + inner class ViewHolder( + private val binding: ItemHomeContentThemeBinding + ) : RecyclerView.ViewHolder(binding.root) { + @SuppressLint("NotifyDataSetChanged") + fun bind(type: ContentRankingSortType) { + binding.tvTheme.text = type.toKoreanLabel() + if (type == selected) { + binding.tvTheme.setBackgroundResource(R.drawable.bg_round_corner_999_3bb9f1) + } else { + binding.tvTheme.setBackgroundResource(R.drawable.bg_round_corner_999_263238) + } + + binding.root.setOnClickListener { + if (selected != type) { + selected = type + notifyDataSetChanged() + onClickSort(type) + } + } + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder( + ItemHomeContentThemeBinding.inflate(LayoutInflater.from(parent.context), parent, false) + ) + + override fun getItemCount() = sorts.size + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + holder.bind(sorts[position]) + } +} + +private fun ContentRankingSortType.toKoreanLabel(): String = when (this) { + ContentRankingSortType.REVENUE -> "매출" + ContentRankingSortType.SALES_COUNT -> "판매량" + ContentRankingSortType.COMMENT_COUNT -> "댓글" + ContentRankingSortType.LIKE_COUNT -> "좋아요" +} diff --git a/app/src/main/java/kr/co/vividnext/sodalive/home/ContentRankingSortType.kt b/app/src/main/java/kr/co/vividnext/sodalive/home/ContentRankingSortType.kt new file mode 100644 index 00000000..d1892a46 --- /dev/null +++ b/app/src/main/java/kr/co/vividnext/sodalive/home/ContentRankingSortType.kt @@ -0,0 +1,18 @@ +package kr.co.vividnext.sodalive.home + +/** + * 콘텐츠 랭킹 정렬 기준 + */ +enum class ContentRankingSortType { + // 매출 + REVENUE, + + // 판매량 + SALES_COUNT, + + // 댓글 수 + COMMENT_COUNT, + + // 좋아요 수 + LIKE_COUNT +} diff --git a/app/src/main/java/kr/co/vividnext/sodalive/home/HomeApi.kt b/app/src/main/java/kr/co/vividnext/sodalive/home/HomeApi.kt index dd34b4b6..3faae189 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/home/HomeApi.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/home/HomeApi.kt @@ -1,11 +1,13 @@ package kr.co.vividnext.sodalive.home import io.reactivex.rxjava3.core.Single +import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentRankingItem import kr.co.vividnext.sodalive.audio_content.series.GetSeriesListResponse import kr.co.vividnext.sodalive.common.ApiResponse import kr.co.vividnext.sodalive.settings.ContentType import retrofit2.http.GET import retrofit2.http.Header +import retrofit2.http.Path import retrofit2.http.Query interface HomeApi { @@ -39,4 +41,12 @@ interface HomeApi { @Query("contentType") contentType: ContentType, @Header("Authorization") authHeader: String ): Single>> + + @GET("/api/home/content-ranking") + fun getContentRankingBySort( + @Query("sort") sort: ContentRankingSortType, + @Query("isAdultContentVisible") isAdultContentVisible: Boolean, + @Query("contentType") contentType: ContentType, + @Header("Authorization") authHeader: String + ): Single>> } diff --git a/app/src/main/java/kr/co/vividnext/sodalive/home/HomeFragment.kt b/app/src/main/java/kr/co/vividnext/sodalive/home/HomeFragment.kt index 587752d4..42420138 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/home/HomeFragment.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/home/HomeFragment.kt @@ -869,6 +869,41 @@ class HomeFragment : BaseFragment(FragmentHomeBinding::infl ) binding.tvWeeklyChart.text = spSectionTitle + // 정렬 선택 RecyclerView 설정 + val sortAdapter = ContentRankingSortAdapter { + viewModel.getContentRanking(it) + } + binding.rvWeeklyChartSort.apply { + layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false) + 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 = 8f.dpToPx().toInt() + } + + sortAdapter.itemCount - 1 -> { + outRect.left = 8f.dpToPx().toInt() + outRect.right = 0 + } + + else -> { + outRect.left = 8f.dpToPx().toInt() + outRect.right = 8f.dpToPx().toInt() + } + } + } + }) + adapter = sortAdapter + } + weelyChartAdapter = HomeWeeklyChartAdapter( width = screenWidth, onClickItem = { @@ -935,12 +970,7 @@ class HomeFragment : BaseFragment(FragmentHomeBinding::infl recyclerView.adapter = weelyChartAdapter viewModel.contentRankingLiveData.observe(viewLifecycleOwner) { - if (it.isNotEmpty()) { - binding.llWeeklyChart.visibility = View.VISIBLE - weelyChartAdapter.addItems(it) - } else { - binding.llWeeklyChart.visibility = View.GONE - } + weelyChartAdapter.addItems(it) } } diff --git a/app/src/main/java/kr/co/vividnext/sodalive/home/HomeRepository.kt b/app/src/main/java/kr/co/vividnext/sodalive/home/HomeRepository.kt index 13dd7f3c..286ff727 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/home/HomeRepository.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/home/HomeRepository.kt @@ -33,4 +33,14 @@ class HomeRepository(private val api: HomeApi) { contentType = ContentType.entries[SharedPreferenceManager.contentPreference], authHeader = token ) + + fun getContentRanking( + sortType: ContentRankingSortType, + token: String + ) = api.getContentRankingBySort( + sort = sortType, + isAdultContentVisible = SharedPreferenceManager.isAdultContentVisible, + contentType = ContentType.entries[SharedPreferenceManager.contentPreference], + authHeader = token + ) } diff --git a/app/src/main/java/kr/co/vividnext/sodalive/home/HomeViewModel.kt b/app/src/main/java/kr/co/vividnext/sodalive/home/HomeViewModel.kt index 7afcac94..5873c3ae 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/home/HomeViewModel.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/home/HomeViewModel.kt @@ -113,6 +113,9 @@ class HomeViewModel( data.pointAvailableContentList _recommendChannelListLiveData.value = data.recommendChannelList _recommendContentListLiveData.value = data.recommendContentList + + // 홈 진입 시 기본 정렬(REVENUE) 랭킹을 최신화 + getContentRanking(ContentRankingSortType.REVENUE) } else { if (it.message != null) { _toastLiveData.postValue(it.message) @@ -132,6 +135,32 @@ class HomeViewModel( ) } + fun getContentRanking(sortType: ContentRankingSortType) { + compositeDisposable.add( + repository.getContentRanking(sortType, token = "Bearer ${SharedPreferenceManager.token}") + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + { + val data = it.data + if (it.success && data != null) { + _contentRankingLiveData.value = data + } else { + if (it.message != null) { + _toastLiveData.postValue(it.message) + } else { + _toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.") + } + } + }, + { + it.message?.let { message -> Logger.e(message) } + _toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.") + } + ) + ) + } + fun refreshRecommendContents() { _isLoading.value = true compositeDisposable.add( diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml index 44778198..5b462388 100644 --- a/app/src/main/res/layout/fragment_home.xml +++ b/app/src/main/res/layout/fragment_home.xml @@ -313,8 +313,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="48dp" - android:orientation="vertical" - android:visibility="gone"> + android:orientation="vertical"> + + +