콘텐츠 메인 - 무료 탭
- 크리에이터 소개 전체보기 페이지 추가
This commit is contained in:
		@@ -326,4 +326,11 @@ interface AudioContentApi {
 | 
			
		||||
    fun getContentMainFree(
 | 
			
		||||
        @Header("Authorization") authHeader: String
 | 
			
		||||
    ): Single<ApiResponse<GetContentMainTabLiveFreeResponse>>
 | 
			
		||||
 | 
			
		||||
    @GET("/v2/audio-content/main/free/introduce-creator")
 | 
			
		||||
    fun getIntroduceCreatorList(
 | 
			
		||||
        @Query("page") page: Int,
 | 
			
		||||
        @Query("size") size: Int,
 | 
			
		||||
        @Header("Authorization") authHeader: String
 | 
			
		||||
    ): Single<ApiResponse<List<GetAudioContentMainItem>>>
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,9 +2,7 @@ package kr.co.vividnext.sodalive.audio_content.curation
 | 
			
		||||
 | 
			
		||||
import android.annotation.SuppressLint
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import android.graphics.Rect
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.view.View
 | 
			
		||||
import android.widget.TextView
 | 
			
		||||
import android.widget.Toast
 | 
			
		||||
import androidx.core.content.ContextCompat
 | 
			
		||||
@@ -21,7 +19,6 @@ import kr.co.vividnext.sodalive.common.GridSpacingItemDecoration
 | 
			
		||||
import kr.co.vividnext.sodalive.common.LoadingDialog
 | 
			
		||||
import kr.co.vividnext.sodalive.databinding.ActivityAudioContentCurationBinding
 | 
			
		||||
import kr.co.vividnext.sodalive.explorer.profile.UserProfileActivity
 | 
			
		||||
import kr.co.vividnext.sodalive.extensions.dpToPx
 | 
			
		||||
import org.koin.android.ext.android.inject
 | 
			
		||||
 | 
			
		||||
class AudioContentCurationActivity : BaseActivity<ActivityAudioContentCurationBinding>(
 | 
			
		||||
 
 | 
			
		||||
@@ -23,6 +23,7 @@ import kr.co.vividnext.sodalive.audio_content.main.AudioContentMainContentAdapte
 | 
			
		||||
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.v2.AudioContentMainContentCurationAdapter
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.main.v2.free.introduce_creator.IntroduceCreatorActivity
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.main.v2.series.new_series.AudioContentMainNewSeriesAdapter
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.series.detail.SeriesDetailActivity
 | 
			
		||||
import kr.co.vividnext.sodalive.base.BaseFragment
 | 
			
		||||
@@ -152,6 +153,12 @@ class AudioContentMainTabFreeFragment : BaseFragment<FragmentAudioContentMainTab
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun setupIntroduceCreator() {
 | 
			
		||||
        binding.ivIntroduceCreatorAll.setOnClickListener {
 | 
			
		||||
            startActivity(
 | 
			
		||||
                Intent(requireContext(), IntroduceCreatorActivity::class.java)
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        introduceCreatorAdapter = AudioContentMainContentAdapter(
 | 
			
		||||
            onClickItem = {
 | 
			
		||||
                startActivity(
 | 
			
		||||
 
 | 
			
		||||
@@ -4,4 +4,9 @@ import kr.co.vividnext.sodalive.audio_content.AudioContentApi
 | 
			
		||||
 | 
			
		||||
class AudioContentMainTabFreeRepository(private val api: AudioContentApi) {
 | 
			
		||||
    fun getContentMainFree(token: String) = api.getContentMainFree(authHeader = token)
 | 
			
		||||
    fun getIntroduceCreatorList(page: Int, size: Int, token: String) = api.getIntroduceCreatorList(
 | 
			
		||||
        page = page - 1,
 | 
			
		||||
        size = size,
 | 
			
		||||
        authHeader = token
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,104 @@
 | 
			
		||||
package kr.co.vividnext.sodalive.audio_content.main.v2.free.introduce_creator
 | 
			
		||||
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.widget.Toast
 | 
			
		||||
import androidx.annotation.OptIn
 | 
			
		||||
import androidx.media3.common.util.UnstableApi
 | 
			
		||||
import androidx.recyclerview.widget.GridLayoutManager
 | 
			
		||||
import androidx.recyclerview.widget.LinearLayoutManager
 | 
			
		||||
import androidx.recyclerview.widget.RecyclerView
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.all.AudioContentNewAllAdapter
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.detail.AudioContentDetailActivity
 | 
			
		||||
import kr.co.vividnext.sodalive.base.BaseActivity
 | 
			
		||||
import kr.co.vividnext.sodalive.common.Constants
 | 
			
		||||
import kr.co.vividnext.sodalive.common.GridSpacingItemDecoration
 | 
			
		||||
import kr.co.vividnext.sodalive.common.LoadingDialog
 | 
			
		||||
import kr.co.vividnext.sodalive.databinding.ActivityIntroduceCreatorBinding
 | 
			
		||||
import kr.co.vividnext.sodalive.explorer.profile.UserProfileActivity
 | 
			
		||||
import kr.co.vividnext.sodalive.extensions.dpToPx
 | 
			
		||||
import org.koin.android.ext.android.inject
 | 
			
		||||
import kotlin.math.roundToInt
 | 
			
		||||
 | 
			
		||||
@OptIn(UnstableApi::class)
 | 
			
		||||
class IntroduceCreatorActivity : BaseActivity<ActivityIntroduceCreatorBinding>(
 | 
			
		||||
    ActivityIntroduceCreatorBinding::inflate
 | 
			
		||||
) {
 | 
			
		||||
    private val viewModel: IntroduceCreatorViewModel by inject()
 | 
			
		||||
 | 
			
		||||
    private lateinit var loadingDialog: LoadingDialog
 | 
			
		||||
    private lateinit var adapter: AudioContentNewAllAdapter
 | 
			
		||||
 | 
			
		||||
    override fun onCreate(savedInstanceState: Bundle?) {
 | 
			
		||||
        super.onCreate(savedInstanceState)
 | 
			
		||||
 | 
			
		||||
        bindData()
 | 
			
		||||
        viewModel.getIntroduceCreatorList()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun setupView() {
 | 
			
		||||
        loadingDialog = LoadingDialog(this, layoutInflater)
 | 
			
		||||
        binding.toolbar.tvBack.text = "크리에이터 소개"
 | 
			
		||||
        binding.toolbar.tvBack.setOnClickListener { finish() }
 | 
			
		||||
 | 
			
		||||
        val spanCount = 3
 | 
			
		||||
        val spacing = 13.3f.dpToPx().roundToInt()
 | 
			
		||||
        adapter = AudioContentNewAllAdapter(
 | 
			
		||||
            itemWidth = (screenWidth - (spacing * (spanCount + 1))) / 3,
 | 
			
		||||
            onClickItem = {
 | 
			
		||||
                startActivity(
 | 
			
		||||
                    Intent(this, AudioContentDetailActivity::class.java).apply {
 | 
			
		||||
                        putExtra(Constants.EXTRA_AUDIO_CONTENT_ID, it)
 | 
			
		||||
                    }
 | 
			
		||||
                )
 | 
			
		||||
            },
 | 
			
		||||
            onClickCreator = {
 | 
			
		||||
                startActivity(
 | 
			
		||||
                    Intent(this, UserProfileActivity::class.java).apply {
 | 
			
		||||
                        putExtra(Constants.EXTRA_USER_ID, it)
 | 
			
		||||
                    }
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        binding.rvContent.layoutManager = GridLayoutManager(this, spanCount)
 | 
			
		||||
        binding.rvContent.addItemDecoration(GridSpacingItemDecoration(spanCount, spacing, true))
 | 
			
		||||
 | 
			
		||||
        binding.rvContent.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.getIntroduceCreatorList()
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
 | 
			
		||||
        binding.rvContent.adapter = adapter
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun bindData() {
 | 
			
		||||
        viewModel.isLoading.observe(this) {
 | 
			
		||||
            if (it) {
 | 
			
		||||
                loadingDialog.show(screenWidth)
 | 
			
		||||
            } else {
 | 
			
		||||
                loadingDialog.dismiss()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        viewModel.toastLiveData.observe(this) {
 | 
			
		||||
            it?.let { Toast.makeText(applicationContext, it, Toast.LENGTH_LONG).show() }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        viewModel.introduceCreatorListLiveData.observe(this) {
 | 
			
		||||
            adapter.addItems(it)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,74 @@
 | 
			
		||||
package kr.co.vividnext.sodalive.audio_content.main.v2.free.introduce_creator
 | 
			
		||||
 | 
			
		||||
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.GetAudioContentMainItem
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.main.v2.free.AudioContentMainTabFreeRepository
 | 
			
		||||
import kr.co.vividnext.sodalive.base.BaseViewModel
 | 
			
		||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
 | 
			
		||||
 | 
			
		||||
class IntroduceCreatorViewModel(
 | 
			
		||||
    private val repository: AudioContentMainTabFreeRepository
 | 
			
		||||
) : 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 _introduceCreatorListLiveData = MutableLiveData<List<GetAudioContentMainItem>>()
 | 
			
		||||
    val introduceCreatorListLiveData: LiveData<List<GetAudioContentMainItem>>
 | 
			
		||||
        get() = _introduceCreatorListLiveData
 | 
			
		||||
 | 
			
		||||
    private var isLast = false
 | 
			
		||||
    private var page = 1
 | 
			
		||||
    private val size = 10
 | 
			
		||||
 | 
			
		||||
    fun getIntroduceCreatorList() {
 | 
			
		||||
        if (!_isLoading.value!! && !isLast) {
 | 
			
		||||
            _isLoading.value = true
 | 
			
		||||
 | 
			
		||||
            compositeDisposable.add(
 | 
			
		||||
                repository.getIntroduceCreatorList(
 | 
			
		||||
                    page = page,
 | 
			
		||||
                    size = size,
 | 
			
		||||
                    token = "Bearer ${SharedPreferenceManager.token}"
 | 
			
		||||
                )
 | 
			
		||||
                    .subscribeOn(Schedulers.io())
 | 
			
		||||
                    .observeOn(AndroidSchedulers.mainThread())
 | 
			
		||||
                    .subscribe(
 | 
			
		||||
                        {
 | 
			
		||||
                            if (it.success && it.data != null) {
 | 
			
		||||
                                if (it.data.isNotEmpty()) {
 | 
			
		||||
                                    page += 1
 | 
			
		||||
                                    _introduceCreatorListLiveData.postValue(it.data!!)
 | 
			
		||||
                                } else {
 | 
			
		||||
                                    isLast = true
 | 
			
		||||
                                }
 | 
			
		||||
                            } 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("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
 | 
			
		||||
                        }
 | 
			
		||||
                    )
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -31,6 +31,7 @@ import kr.co.vividnext.sodalive.audio_content.main.v2.content.AudioContentMainTa
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.main.v2.content.AudioContentMainTabContentViewModel
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.main.v2.free.AudioContentMainTabFreeRepository
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.main.v2.free.AudioContentMainTabFreeViewModel
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.main.v2.free.introduce_creator.IntroduceCreatorViewModel
 | 
			
		||||
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.replay.AudioContentMainTabReplayRepository
 | 
			
		||||
@@ -314,6 +315,7 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
 | 
			
		||||
        viewModel { AudioContentMainTabReplayViewModel(get()) }
 | 
			
		||||
        viewModel { AudioContentMainTabFreeViewModel(get()) }
 | 
			
		||||
        viewModel { OriginalAudioDramaContentAllViewModel(get()) }
 | 
			
		||||
        viewModel { IntroduceCreatorViewModel(get()) }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private val repositoryModule = module {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user