완결 시리즈
- 페이지 추가
This commit is contained in:
		@@ -283,6 +283,13 @@ interface AudioContentApi {
 | 
			
		||||
        @Header("Authorization") authHeader: String
 | 
			
		||||
    ): Single<ApiResponse<List<GetSeriesListResponse.SeriesListItem>>>
 | 
			
		||||
 | 
			
		||||
    @GET("/v2/audio-content/main/series/completed-monthly-rank")
 | 
			
		||||
    fun getCompletedSeries(
 | 
			
		||||
        @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
 | 
			
		||||
 
 | 
			
		||||
@@ -18,6 +18,7 @@ import kr.co.vividnext.sodalive.R
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.main.AudioContentBannerType
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.main.banner.AudioContentMainBannerAdapter
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.main.v2.ContentRankCreatorAdapter
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.main.v2.series.completed.CompletedSeriesActivity
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.main.v2.series.curation.AudioContentMainSeriesCurationAdapter
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.main.v2.series.new_series.AudioContentMainNewSeriesAdapter
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.main.v2.series.origianl_audio_drama.AudioContentMainTabSeriesOriginalAudioDramaAdapter
 | 
			
		||||
@@ -456,6 +457,15 @@ class AudioContentMainTabSeriesFragment : BaseFragment<FragmentAudioContentMainT
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun setupCompleteSeries() {
 | 
			
		||||
        binding.ivCompleteSeriesAll.setOnClickListener {
 | 
			
		||||
            startActivity(
 | 
			
		||||
                Intent(
 | 
			
		||||
                    requireContext(),
 | 
			
		||||
                    CompletedSeriesActivity::class.java
 | 
			
		||||
                )
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        completedSeriesAdapter = UserProfileSeriesListAdapter(
 | 
			
		||||
            onClickItem = {
 | 
			
		||||
                startActivity(
 | 
			
		||||
 
 | 
			
		||||
@@ -13,4 +13,14 @@ class AudioContentMainTabSeriesRepository(private val api: AudioContentApi) {
 | 
			
		||||
        creatorId: Long,
 | 
			
		||||
        token: String
 | 
			
		||||
    ) = api.getRecommendSeriesByCreator(creatorId, authHeader = token)
 | 
			
		||||
 | 
			
		||||
    fun getCompletedSeries(
 | 
			
		||||
        page: Int,
 | 
			
		||||
        size: Int,
 | 
			
		||||
        token: String
 | 
			
		||||
    ) = api.getCompletedSeries(
 | 
			
		||||
        page = page - 1,
 | 
			
		||||
        size = size,
 | 
			
		||||
        authHeader = token
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,109 @@
 | 
			
		||||
package kr.co.vividnext.sodalive.audio_content.main.v2.series.completed
 | 
			
		||||
 | 
			
		||||
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.ActivityCompletedSeriesBinding
 | 
			
		||||
import kr.co.vividnext.sodalive.extensions.dpToPx
 | 
			
		||||
import org.koin.android.ext.android.inject
 | 
			
		||||
import kotlin.math.roundToInt
 | 
			
		||||
 | 
			
		||||
class CompletedSeriesActivity : BaseActivity<ActivityCompletedSeriesBinding>(
 | 
			
		||||
    ActivityCompletedSeriesBinding::inflate
 | 
			
		||||
) {
 | 
			
		||||
 | 
			
		||||
    private val viewModel: CompletedSeriesViewModel by inject()
 | 
			
		||||
 | 
			
		||||
    private lateinit var loadingDialog: LoadingDialog
 | 
			
		||||
    private lateinit var adapter: SeriesListAdapter
 | 
			
		||||
 | 
			
		||||
    override fun onCreate(savedInstanceState: Bundle?) {
 | 
			
		||||
        super.onCreate(savedInstanceState)
 | 
			
		||||
        bindData()
 | 
			
		||||
 | 
			
		||||
        viewModel.getCompletedSeries()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun setupView() {
 | 
			
		||||
        loadingDialog = LoadingDialog(this, layoutInflater)
 | 
			
		||||
        binding.toolbar.tvBack.text = "완결 시리즈"
 | 
			
		||||
        binding.toolbar.tvBack.setOnClickListener { finish() }
 | 
			
		||||
 | 
			
		||||
        setupCompletedSeriesListView()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun setupCompletedSeriesListView() {
 | 
			
		||||
        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.getCompletedSeries()
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
 | 
			
		||||
        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.completedSeriesLiveData.observe(this) {
 | 
			
		||||
            adapter.addItems(it)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,75 @@
 | 
			
		||||
package kr.co.vividnext.sodalive.audio_content.main.v2.series.completed
 | 
			
		||||
 | 
			
		||||
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.v2.series.AudioContentMainTabSeriesRepository
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.series.GetSeriesListResponse
 | 
			
		||||
import kr.co.vividnext.sodalive.base.BaseViewModel
 | 
			
		||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
 | 
			
		||||
 | 
			
		||||
class CompletedSeriesViewModel(
 | 
			
		||||
    private val repository: AudioContentMainTabSeriesRepository
 | 
			
		||||
) : 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 _completedSeriesLiveData =
 | 
			
		||||
        MutableLiveData<List<GetSeriesListResponse.SeriesListItem>>()
 | 
			
		||||
    val completedSeriesLiveData: LiveData<List<GetSeriesListResponse.SeriesListItem>>
 | 
			
		||||
        get() = _completedSeriesLiveData
 | 
			
		||||
 | 
			
		||||
    var isLast = false
 | 
			
		||||
    var page = 1
 | 
			
		||||
    private val size = 20
 | 
			
		||||
 | 
			
		||||
    fun getCompletedSeries() {
 | 
			
		||||
        if (!_isLoading.value!! && !isLast) {
 | 
			
		||||
            _isLoading.value = true
 | 
			
		||||
 | 
			
		||||
            compositeDisposable.add(
 | 
			
		||||
                repository.getCompletedSeries(
 | 
			
		||||
                    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()) {
 | 
			
		||||
                                    _completedSeriesLiveData.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("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
 | 
			
		||||
                        }
 | 
			
		||||
                    )
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -38,6 +38,7 @@ 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.completed.CompletedSeriesViewModel
 | 
			
		||||
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
 | 
			
		||||
@@ -316,6 +317,7 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
 | 
			
		||||
        viewModel { AudioContentMainTabFreeViewModel(get()) }
 | 
			
		||||
        viewModel { OriginalAudioDramaContentAllViewModel(get()) }
 | 
			
		||||
        viewModel { IntroduceCreatorViewModel(get()) }
 | 
			
		||||
        viewModel { CompletedSeriesViewModel(get()) }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private val repositoryModule = module {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user