콘텐츠 메인

- 단편 탭 UI 구성
This commit is contained in:
klaus 2025-02-13 16:30:40 +09:00
parent f75134c7e7
commit 363d611e0f
8 changed files with 1282 additions and 5 deletions

View File

@ -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<ApiResponse<GetContentMainTabSeriesResponse>>
@GET("/v2/audio-content/main/content")
fun getContentMainContent(
@Header("Authorization") authHeader: String
): Single<ApiResponse<GetContentMainTabContentResponse>>
@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<ApiResponse<List<GetAudioContentMainItem>>>
@GET("/v2/audio-content/main/content/ranking")
fun getDailyContentRanking(
@Query("sort-type") sortType: String,
@Header("Authorization") authHeader: String
): Single<ApiResponse<List<GetAudioContentRankingItem>>>
@GET("/v2/audio-content/main/content/popular-content-by-creator")
fun getContentMainContentPopularContentByCreator(
@Query("creatorId") creatorId: Long,
@Header("Authorization") authHeader: String
): Single<ApiResponse<GetPopularContentByCreatorResponse>>
}

View File

@ -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>(
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<Any>
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<Any>
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)
}
)
}
}
}

View File

@ -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)
}

View File

@ -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<String?>()
val toastLiveData: LiveData<String?>
get() = _toastLiveData
private var _isLoading = MutableLiveData(false)
val isLoading: LiveData<Boolean>
get() = _isLoading
private var _contentBannerLiveData = MutableLiveData<List<GetAudioContentBannerResponse>>()
val contentBannerLiveData: LiveData<List<GetAudioContentBannerResponse>>
get() = _contentBannerLiveData
private var _newContentListLiveData = MutableLiveData<List<GetAudioContentMainItem>>()
val newContentListLiveData: LiveData<List<GetAudioContentMainItem>>
get() = _newContentListLiveData
private var _themeListLiveData = MutableLiveData<List<String>>()
val themeListLiveData: LiveData<List<String>>
get() = _themeListLiveData
private var _contentRankingSortListLiveData = MutableLiveData<List<String>>()
val contentRankingSortListLiveData: LiveData<List<String>>
get() = _contentRankingSortListLiveData
private var _contentRankingLiveData = MutableLiveData<List<GetAudioContentRankingItem>>()
val contentRankingLiveData: LiveData<List<GetAudioContentRankingItem>>
get() = _contentRankingLiveData
private val _eventLiveData = MutableLiveData<List<EventItem>>()
val eventLiveData: LiveData<List<EventItem>>
get() = _eventLiveData
private val _contentRankCreatorListLiveData = MutableLiveData<List<ContentCreatorResponse>>()
val contentRankCreatorListLiveData: LiveData<List<ContentCreatorResponse>>
get() = _contentRankCreatorListLiveData
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
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("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
}
)
)
}
}

View File

@ -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<GetAudioContentBannerResponse>,
@SerializedName("contentThemeList") val contentThemeList: List<String>,
@SerializedName("newContentList") val newContentList: List<GetAudioContentMainItem>,
@SerializedName("rankSortTypeList") val rankSortTypeList: List<String>,
@SerializedName("rankContentList") val rankContentList: List<GetAudioContentRankingItem>,
@SerializedName("contentRankCreatorList") val contentRankCreatorList: List<ContentCreatorResponse>,
@SerializedName("salesRankContentList") val salesRankContentList: List<GetAudioContentRankingItem>,
@SerializedName("salesCountRankContentList") val salesCountRankContentList: List<GetAudioContentRankingItem>,
@SerializedName("eventBannerList") val eventBannerList: GetEventResponse
)

View File

@ -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

View File

@ -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(

View File

@ -1,7 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
tools:background="@color/black">
<LinearLayout
android:layout_width="match_parent"
@ -13,13 +16,426 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="13.3dp"
android:layout_marginTop="30dp" />
android:layout_marginTop="30dp"
android:visibility="gone" />
<com.zhpan.indicator.IndicatorView
android:id="@+id/indicator_banner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="6.7dp" />
android:layout_marginTop="6.7dp"
android:visibility="gone" />
<LinearLayout
android:id="@+id/ll_new_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:orientation="vertical"
android:visibility="gone">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="13.3dp"
android:fontFamily="@font/gmarket_sans_bold"
android:text="새로운 단편"
android:textColor="@color/color_eeeeee"
android:textSize="18.3sp" />
<ImageView
android:id="@+id/iv_new_content_all"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:contentDescription="@null"
android:paddingHorizontal="13.3dp"
android:src="@drawable/ic_forward" />
</RelativeLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_new_content_theme"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="13.3dp"
android:clipToPadding="false"
android:paddingHorizontal="13.3dp" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_new_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="13.3dp"
android:clipToPadding="false"
android:paddingHorizontal="13.3dp" />
</LinearLayout>
<LinearLayout
android:id="@+id/ll_content_ranking"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:orientation="vertical"
android:visibility="gone">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="13.3dp"
android:fontFamily="@font/gmarket_sans_bold"
android:text="일간 랭킹"
android:textColor="@color/color_eeeeee"
android:textSize="18.3sp" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_content_ranking_sort"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="13.3dp"
android:clipToPadding="false"
android:paddingHorizontal="13.3dp" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_content_ranking"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="13.3dp"
android:clipToPadding="false"
android:paddingHorizontal="6.7dp" />
</LinearLayout>
<LinearLayout
android:id="@+id/ll_creator_content_ranking"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="13.3dp"
android:fontFamily="@font/gmarket_sans_bold"
android:text="채널별 추천 단편"
android:textColor="@color/color_eeeeee"
android:textSize="18.3sp" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_ranking_creator"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:clipToPadding="false"
android:paddingHorizontal="13.3dp" />
<LinearLayout
android:id="@+id/ll_sales_top2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:baselineAligned="false"
android:orientation="horizontal"
android:paddingHorizontal="13.3dp"
android:visibility="gone">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center">
<ImageView
android:id="@+id/iv_sales_1"
android:layout_width="0dp"
android:layout_height="0dp"
android:contentDescription="@null"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<TextView
android:id="@+id/tv_sales_title_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:fontFamily="@font/gmarket_sans_medium"
android:textColor="@color/color_d2d2d2"
android:textSize="13.3sp" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:gravity="center_vertical"
android:orientation="horizontal"
tools:ignore="UseCompoundDrawables">
<ImageView
android:id="@+id/iv_sales_creator_1"
android:layout_width="21dp"
android:layout_height="21dp"
android:contentDescription="@null" />
<TextView
android:id="@+id/tv_sales_creator_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5.3dp"
android:fontFamily="@font/gmarket_sans_medium"
android:textColor="@color/color_777777"
android:textSize="10sp"
tools:ignore="SmallSp" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/ll_sales_2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="13.3dp"
android:layout_weight="1"
android:orientation="vertical">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center">
<ImageView
android:id="@+id/iv_sales_2"
android:layout_width="0dp"
android:layout_height="0dp"
android:contentDescription="@null"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<TextView
android:id="@+id/tv_sales_title_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:fontFamily="@font/gmarket_sans_medium"
android:textColor="@color/color_d2d2d2"
android:textSize="13.3sp" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:gravity="center_vertical"
android:orientation="horizontal"
tools:ignore="UseCompoundDrawables">
<ImageView
android:id="@+id/iv_sales_creator_2"
android:layout_width="21dp"
android:layout_height="21dp"
android:contentDescription="@null" />
<TextView
android:id="@+id/tv_sales_creator_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5.3dp"
android:fontFamily="@font/gmarket_sans_medium"
android:textColor="@color/color_777777"
android:textSize="10sp"
tools:ignore="SmallSp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/ll_sales_count_top2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:baselineAligned="false"
android:orientation="horizontal"
android:paddingHorizontal="13.3dp"
android:visibility="gone">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
tools:ignore="TooManyViews">
<ImageView
android:id="@+id/iv_sales_count_1"
android:layout_width="0dp"
android:layout_height="0dp"
android:contentDescription="@null"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<TextView
android:id="@+id/tv_sales_count_title_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:fontFamily="@font/gmarket_sans_medium"
android:textColor="@color/color_d2d2d2"
android:textSize="13.3sp" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:gravity="center_vertical"
android:orientation="horizontal"
tools:ignore="UseCompoundDrawables">
<ImageView
android:id="@+id/iv_sales_count_creator_1"
android:layout_width="21dp"
android:layout_height="21dp"
android:contentDescription="@null" />
<TextView
android:id="@+id/tv_sales_count_creator_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5.3dp"
android:fontFamily="@font/gmarket_sans_medium"
android:textColor="@color/color_777777"
android:textSize="10sp"
tools:ignore="SmallSp" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/ll_sales_count_2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="13.3dp"
android:layout_weight="1"
android:orientation="vertical">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center">
<ImageView
android:id="@+id/iv_sales_count_2"
android:layout_width="0dp"
android:layout_height="0dp"
android:contentDescription="@null"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<TextView
android:id="@+id/tv_sales_count_title_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:fontFamily="@font/gmarket_sans_medium"
android:textColor="@color/color_d2d2d2"
android:textSize="13.3sp" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:gravity="center_vertical"
android:orientation="horizontal"
tools:ignore="UseCompoundDrawables">
<ImageView
android:id="@+id/iv_sales_count_creator_2"
android:layout_width="21dp"
android:layout_height="21dp"
android:contentDescription="@null" />
<TextView
android:id="@+id/tv_sales_count_creator_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5.3dp"
android:fontFamily="@font/gmarket_sans_medium"
android:textColor="@color/color_777777"
android:textSize="10sp"
tools:ignore="SmallSp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/ll_no_items"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="13.3dp"
android:layout_marginTop="28.3dp"
android:background="@drawable/bg_round_corner_4_7_13181b"
android:gravity="center"
android:orientation="vertical"
android:paddingVertical="16.7dp">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@null"
android:src="@drawable/ic_no_item" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginVertical="10dp"
android:fontFamily="@font/gmarket_sans_medium"
android:gravity="center"
android:lineSpacingExtra="8dp"
android:text="마이페이지에서 본인인증을 해주세요"
android:textColor="@color/color_bbbbbb"
android:textSize="13sp"
tools:ignore="SmallSp" />
</LinearLayout>
</LinearLayout>
<com.zhpan.bannerview.BannerViewPager
android:id="@+id/event_banner_slider"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:visibility="gone" />
<com.zhpan.indicator.IndicatorView
android:id="@+id/indicator_event_banner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="6.7dp"
android:visibility="gone" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>