콘텐츠 메인 - 시리즈 탭

- 오리지널 오디오 드라마 전체보기 페이지 추가
This commit is contained in:
2025-02-14 05:22:08 +09:00
parent cc10bce487
commit e1028ada43
9 changed files with 332 additions and 101 deletions

View File

@@ -27,6 +27,7 @@ import kr.co.vividnext.sodalive.audio_content.main.v2.series.GetContentMainTabSe
import kr.co.vividnext.sodalive.audio_content.order.GetAudioContentOrderListResponse
import kr.co.vividnext.sodalive.audio_content.order.OrderRequest
import kr.co.vividnext.sodalive.audio_content.player.GenerateUrlResponse
import kr.co.vividnext.sodalive.audio_content.series.GetSeriesListResponse
import kr.co.vividnext.sodalive.audio_content.upload.theme.GetAudioContentThemeResponse
import kr.co.vividnext.sodalive.common.ApiResponse
import kr.co.vividnext.sodalive.explorer.profile.GetAudioContentListResponse
@@ -262,6 +263,13 @@ interface AudioContentApi {
@Header("Authorization") authHeader: String
): Single<ApiResponse<GetContentMainTabSeriesResponse>>
@GET("/v2/audio-content/main/series/original")
fun getOriginalAudioDramaList(
@Query("page") page: Int,
@Query("size") size: Int,
@Header("Authorization") authHeader: String
): Single<ApiResponse<GetSeriesListResponse>>
@GET("/v2/audio-content/main/content")
fun getContentMainContent(
@Header("Authorization") authHeader: String

View File

@@ -0,0 +1,109 @@
package kr.co.vividnext.sodalive.audio_content.main.v2.series.origianl_audio_drama
import android.content.Intent
import android.os.Bundle
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import kr.co.vividnext.sodalive.audio_content.series.SeriesListAdapter
import kr.co.vividnext.sodalive.audio_content.series.detail.SeriesDetailActivity
import kr.co.vividnext.sodalive.base.BaseActivity
import kr.co.vividnext.sodalive.common.Constants
import kr.co.vividnext.sodalive.common.DifferentSpacingItemDecoration
import kr.co.vividnext.sodalive.common.LoadingDialog
import kr.co.vividnext.sodalive.databinding.ActivityOriginalAudioDramaContentAllBinding
import kr.co.vividnext.sodalive.extensions.dpToPx
import org.koin.android.ext.android.inject
import kotlin.math.roundToInt
class OriginalAudioDramaContentAllActivity :
BaseActivity<ActivityOriginalAudioDramaContentAllBinding>(
ActivityOriginalAudioDramaContentAllBinding::inflate
) {
private val viewModel: OriginalAudioDramaContentAllViewModel by inject()
private lateinit var loadingDialog: LoadingDialog
private lateinit var adapter: SeriesListAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
bindData()
viewModel.getOriginalAudioDramaList()
}
override fun setupView() {
loadingDialog = LoadingDialog(this, layoutInflater)
binding.toolbar.tvBack.text = "오리지널 오디오 드라마"
binding.toolbar.tvBack.setOnClickListener { finish() }
setupOriginalAudioDramaListView()
}
private fun setupOriginalAudioDramaListView() {
val spacing = 13.3f.dpToPx().roundToInt()
adapter = SeriesListAdapter(
itemWidth = ((screenWidth - spacing * 3) / 2f).roundToInt(),
onClickItem = {
startActivity(
Intent(applicationContext, SeriesDetailActivity::class.java).apply {
putExtra(Constants.EXTRA_SERIES_ID, it)
}
)
},
onClickCreator = {},
isVisibleCreator = false
)
val spanCount = 2
val recyclerView = binding.rvSeries
recyclerView.layoutManager = GridLayoutManager(this, spanCount)
recyclerView.addItemDecoration(
DifferentSpacingItemDecoration(
spanCount = spanCount,
horizontalSpacing = spacing,
verticalSpacing = spacing,
includeEdge = true
)
)
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
val lastVisibleItemPosition = (recyclerView.layoutManager as LinearLayoutManager?)!!
.findLastCompletelyVisibleItemPosition()
val itemTotalCount = recyclerView.adapter!!.itemCount - 1
// 스크롤이 끝에 도달했는지 확인
if (!recyclerView.canScrollVertically(1) &&
lastVisibleItemPosition == itemTotalCount
) {
viewModel.getOriginalAudioDramaList()
}
}
})
recyclerView.adapter = adapter
}
private fun bindData() {
viewModel.toastLiveData.observe(this) {
it?.let { showToast(it) }
}
viewModel.isLoading.observe(this) {
if (it) {
loadingDialog.show(screenWidth)
} else {
loadingDialog.dismiss()
}
}
viewModel.originalAudioDramaLiveData.observe(this) {
adapter.addItems(it)
}
}
}

View File

@@ -0,0 +1,15 @@
package kr.co.vividnext.sodalive.audio_content.main.v2.series.origianl_audio_drama
import kr.co.vividnext.sodalive.audio_content.AudioContentApi
class OriginalAudioDramaContentAllRepository(private val api: AudioContentApi) {
fun getOriginalAudioDramaList(
page: Int,
size: Int,
token: String
) = api.getOriginalAudioDramaList(
page = page - 1,
size = size,
authHeader = token
)
}

View File

@@ -0,0 +1,74 @@
package kr.co.vividnext.sodalive.audio_content.main.v2.series.origianl_audio_drama
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.series.GetSeriesListResponse
import kr.co.vividnext.sodalive.base.BaseViewModel
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
class OriginalAudioDramaContentAllViewModel(
private val repository: OriginalAudioDramaContentAllRepository
) : 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 _originalAudioDramaLiveData =
MutableLiveData<List<GetSeriesListResponse.SeriesListItem>>()
val originalAudioDramaLiveData: LiveData<List<GetSeriesListResponse.SeriesListItem>>
get() = _originalAudioDramaLiveData
var isLast = false
var page = 1
private val size = 15
fun getOriginalAudioDramaList() {
if (!_isLoading.value!! && !isLast) {
_isLoading.value = true
compositeDisposable.add(
repository.getOriginalAudioDramaList(
page = page,
size = size,
token = "Bearer ${SharedPreferenceManager.token}"
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
if (it.success && it.data != null) {
page += 1
if (it.data.items.isNotEmpty()) {
_originalAudioDramaLiveData.value = it.data.items
} else {
isLast = true
}
} else {
if (it.message != null) {
_toastLiveData.value = it.message
} else {
_toastLiveData.value = "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
}
}
_isLoading.value = false
},
{
_isLoading.value = false
it.message?.let { message -> Logger.e(message) }
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
}
)
)
}
}
}

View File

@@ -4,7 +4,7 @@ import android.annotation.SuppressLint
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.constraintlayout.widget.ConstraintLayout
import android.widget.LinearLayout
import androidx.recyclerview.widget.RecyclerView
import coil.load
import coil.transform.CircleCropTransformation
@@ -27,10 +27,10 @@ class SeriesListAdapter(
) : RecyclerView.ViewHolder(binding.root) {
@SuppressLint("SetTextI18n")
fun bind(item: GetSeriesListResponse.SeriesListItem) {
val lp = binding.ivCover.layoutParams as ConstraintLayout.LayoutParams
val lp = binding.clCover.layoutParams as LinearLayout.LayoutParams
lp.width = itemWidth
lp.height = itemWidth * 432 / 306
binding.ivCover.layoutParams = lp
binding.clCover.layoutParams = lp
binding.ivCover.load(item.coverImage) {
crossfade(true)

View File

@@ -37,6 +37,8 @@ import kr.co.vividnext.sodalive.audio_content.main.v2.replay.AudioContentMainTab
import kr.co.vividnext.sodalive.audio_content.main.v2.replay.AudioContentMainTabReplayViewModel
import kr.co.vividnext.sodalive.audio_content.main.v2.series.AudioContentMainTabSeriesRepository
import kr.co.vividnext.sodalive.audio_content.main.v2.series.AudioContentMainTabSeriesViewModel
import kr.co.vividnext.sodalive.audio_content.main.v2.series.origianl_audio_drama.OriginalAudioDramaContentAllRepository
import kr.co.vividnext.sodalive.audio_content.main.v2.series.origianl_audio_drama.OriginalAudioDramaContentAllViewModel
import kr.co.vividnext.sodalive.audio_content.modify.AudioContentModifyViewModel
import kr.co.vividnext.sodalive.audio_content.order.AudioContentOrderListViewModel
import kr.co.vividnext.sodalive.audio_content.player.AudioContentGenerateUrlRepository
@@ -311,6 +313,7 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
viewModel { AudioContentMainTabAsmrViewModel(get()) }
viewModel { AudioContentMainTabReplayViewModel(get()) }
viewModel { AudioContentMainTabFreeViewModel(get()) }
viewModel { OriginalAudioDramaContentAllViewModel(get()) }
}
private val repositoryModule = module {
@@ -349,6 +352,7 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
factory { AudioContentMainTabAsmrRepository(get()) }
factory { AudioContentMainTabReplayRepository(get()) }
factory { AudioContentMainTabFreeRepository(get()) }
factory { OriginalAudioDramaContentAllRepository(get()) }
}
private val moduleList = listOf(