feat: 메인 라이브
- 라이브 다시 듣기 UI 추가
This commit is contained in:
		@@ -1,5 +1,6 @@
 | 
			
		||||
package kr.co.vividnext.sodalive.audio_content
 | 
			
		||||
 | 
			
		||||
import io.reactivex.rxjava3.core.Flowable
 | 
			
		||||
import io.reactivex.rxjava3.core.Single
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.all.GetNewContentAllResponse
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.all.by_theme.GetContentByThemeResponse
 | 
			
		||||
@@ -56,6 +57,13 @@ interface AudioContentApi {
 | 
			
		||||
        @Header("Authorization") authHeader: String
 | 
			
		||||
    ): Single<ApiResponse<GetAudioContentListResponse>>
 | 
			
		||||
 | 
			
		||||
    @GET("/audio-content/replay-live")
 | 
			
		||||
    fun getAudioContentReplayLiveList(
 | 
			
		||||
        @Query("isAdultContentVisible") isAdultContentVisible: Boolean,
 | 
			
		||||
        @Query("contentType") contentType: ContentType,
 | 
			
		||||
        @Header("Authorization") authHeader: String
 | 
			
		||||
    ): Flowable<ApiResponse<List<GetAudioContentMainItem>>>
 | 
			
		||||
 | 
			
		||||
    @GET("/audio-content/theme")
 | 
			
		||||
    fun getAudioContentThemeList(
 | 
			
		||||
        @Header("Authorization") authHeader: String
 | 
			
		||||
 
 | 
			
		||||
@@ -50,6 +50,12 @@ class AudioContentRepository(
 | 
			
		||||
        authHeader = token
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    fun getAudioContentReplayLiveList(token: String) = api.getAudioContentReplayLiveList(
 | 
			
		||||
        isAdultContentVisible = SharedPreferenceManager.isAdultContentVisible,
 | 
			
		||||
        contentType = ContentType.values()[SharedPreferenceManager.contentPreference],
 | 
			
		||||
        authHeader = token
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    fun getAudioContentThemeList(token: String) = api.getAudioContentThemeList(token)
 | 
			
		||||
 | 
			
		||||
    fun uploadAudioContent(
 | 
			
		||||
 
 | 
			
		||||
@@ -252,7 +252,7 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
 | 
			
		||||
        viewModel { TermsViewModel(get()) }
 | 
			
		||||
        viewModel { FindPasswordViewModel(get()) }
 | 
			
		||||
        viewModel { MainViewModel(get(), get(), get(), get(), get()) }
 | 
			
		||||
        viewModel { LiveViewModel(get(), get(), get(), get()) }
 | 
			
		||||
        viewModel { LiveViewModel(get(), get(), get(), get(), get()) }
 | 
			
		||||
        viewModel { MyPageViewModel(get(), get()) }
 | 
			
		||||
        viewModel { CanStatusViewModel(get()) }
 | 
			
		||||
        viewModel { CanChargePgViewModel(get()) }
 | 
			
		||||
 
 | 
			
		||||
@@ -15,6 +15,7 @@ import androidx.activity.result.ActivityResultLauncher
 | 
			
		||||
import androidx.activity.result.contract.ActivityResultContracts
 | 
			
		||||
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 com.zhpan.bannerview.BaseBannerAdapter
 | 
			
		||||
@@ -22,6 +23,7 @@ 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.AudioContentPlayService
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.detail.AudioContentDetailActivity
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.player.AudioContentPlayerService
 | 
			
		||||
import kr.co.vividnext.sodalive.base.BaseFragment
 | 
			
		||||
import kr.co.vividnext.sodalive.common.Constants
 | 
			
		||||
@@ -34,6 +36,8 @@ import kr.co.vividnext.sodalive.explorer.profile.creator_community.all.CreatorCo
 | 
			
		||||
import kr.co.vividnext.sodalive.extensions.dpToPx
 | 
			
		||||
import kr.co.vividnext.sodalive.extensions.moneyFormat
 | 
			
		||||
import kr.co.vividnext.sodalive.following.FollowingCreatorActivity
 | 
			
		||||
import kr.co.vividnext.sodalive.home.AudioContentMainItem
 | 
			
		||||
import kr.co.vividnext.sodalive.home.HomeContentAdapter
 | 
			
		||||
import kr.co.vividnext.sodalive.live.now.LiveNowAdapter
 | 
			
		||||
import kr.co.vividnext.sodalive.live.now.all.LiveNowAllActivity
 | 
			
		||||
import kr.co.vividnext.sodalive.live.recommend.RecommendLiveAdapter
 | 
			
		||||
@@ -162,6 +166,7 @@ class LiveFragment : BaseFragment<FragmentLiveBinding>(FragmentLiveBinding::infl
 | 
			
		||||
        setupRecommendLive()
 | 
			
		||||
        setupRecommendChannel()
 | 
			
		||||
        setupLatestFinishedLiveChannel()
 | 
			
		||||
        setupLiveReplay()
 | 
			
		||||
        setupLiveReservation()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -403,6 +408,83 @@ class LiveFragment : BaseFragment<FragmentLiveBinding>(FragmentLiveBinding::infl
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun setupLiveReplay() {
 | 
			
		||||
        val adapter = HomeContentAdapter {
 | 
			
		||||
            if (SharedPreferenceManager.token.isNotBlank()) {
 | 
			
		||||
                startActivity(
 | 
			
		||||
                    Intent(requireContext(), AudioContentDetailActivity::class.java).apply {
 | 
			
		||||
                        putExtra(Constants.EXTRA_AUDIO_CONTENT_ID, it)
 | 
			
		||||
                    }
 | 
			
		||||
                )
 | 
			
		||||
            } else {
 | 
			
		||||
                (requireActivity() as MainActivity).showLoginActivity()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        val rvContent = binding.rvReplayLive
 | 
			
		||||
        rvContent.layoutManager = GridLayoutManager(context, 2, RecyclerView.HORIZONTAL, false)
 | 
			
		||||
        rvContent.addItemDecoration(object : RecyclerView.ItemDecoration() {
 | 
			
		||||
            override fun getItemOffsets(
 | 
			
		||||
                outRect: Rect,
 | 
			
		||||
                view: View,
 | 
			
		||||
                parent: RecyclerView,
 | 
			
		||||
                state: RecyclerView.State
 | 
			
		||||
            ) {
 | 
			
		||||
                super.getItemOffsets(outRect, view, parent, state)
 | 
			
		||||
                outRect.top = 8f.dpToPx().toInt()
 | 
			
		||||
                outRect.bottom = 8f.dpToPx().toInt()
 | 
			
		||||
 | 
			
		||||
                val position = parent.getChildAdapterPosition(view)
 | 
			
		||||
 | 
			
		||||
                if (position == 0 || position == 1) {
 | 
			
		||||
                    outRect.left = 0f.dpToPx().toInt()
 | 
			
		||||
                } else {
 | 
			
		||||
                    outRect.left = 8f.dpToPx().toInt()
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                outRect.right = 8f.dpToPx().toInt()
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
        rvContent.adapter = adapter
 | 
			
		||||
 | 
			
		||||
        adapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
 | 
			
		||||
            override fun onChanged() {
 | 
			
		||||
                if (adapter.itemCount < 2) {
 | 
			
		||||
                    // 1개일 땐 단일 행
 | 
			
		||||
                    rvContent.layoutManager =
 | 
			
		||||
                        LinearLayoutManager(rvContent.context, RecyclerView.HORIZONTAL, false)
 | 
			
		||||
                } else {
 | 
			
		||||
                    // 2개 이상일 땐 2행 바둑판
 | 
			
		||||
                    rvContent.layoutManager =
 | 
			
		||||
                        GridLayoutManager(rvContent.context, 2, RecyclerView.HORIZONTAL, false)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
 | 
			
		||||
        viewModel.replayContentListLiveData.observe(viewLifecycleOwner) { contentList ->
 | 
			
		||||
            if (contentList.isNotEmpty()) {
 | 
			
		||||
                adapter.addItems(
 | 
			
		||||
                    contentList.map {
 | 
			
		||||
                        AudioContentMainItem(
 | 
			
		||||
                            contentId = it.contentId,
 | 
			
		||||
                            creatorId = it.creatorId,
 | 
			
		||||
                            title = it.title,
 | 
			
		||||
                            coverImageUrl = it.coverImageUrl,
 | 
			
		||||
                            creatorNickname = it.creatorNickname,
 | 
			
		||||
                            isPointAvailable = it.isPointAvailable
 | 
			
		||||
                        )
 | 
			
		||||
                    }
 | 
			
		||||
                )
 | 
			
		||||
 | 
			
		||||
                binding.llReplayLive.visibility = View.VISIBLE
 | 
			
		||||
                binding.rvReplayLive.visibility = View.VISIBLE
 | 
			
		||||
            } else {
 | 
			
		||||
                binding.llReplayLive.visibility = View.GONE
 | 
			
		||||
                binding.rvReplayLive.visibility = View.GONE
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @SuppressLint("NotifyDataSetChanged")
 | 
			
		||||
    private fun setupLiveNow() {
 | 
			
		||||
        binding
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@ package kr.co.vividnext.sodalive.live
 | 
			
		||||
 | 
			
		||||
import androidx.annotation.Keep
 | 
			
		||||
import com.google.gson.annotations.SerializedName
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentMainItem
 | 
			
		||||
import kr.co.vividnext.sodalive.common.ApiResponse
 | 
			
		||||
import kr.co.vividnext.sodalive.live.recommend.GetRecommendLiveResponse
 | 
			
		||||
import kr.co.vividnext.sodalive.settings.event.GetEventResponse
 | 
			
		||||
@@ -17,5 +18,7 @@ data class LiveSummary(
 | 
			
		||||
    @SerializedName("recommendLive")
 | 
			
		||||
    val recommendLive: ApiResponse<List<GetRecommendLiveResponse>>,
 | 
			
		||||
    @SerializedName("latestFinishedLive")
 | 
			
		||||
    val latestFinishedLive: ApiResponse<List<GetLatestFinishedLiveResponse>>
 | 
			
		||||
    val latestFinishedLive: ApiResponse<List<GetLatestFinishedLiveResponse>>,
 | 
			
		||||
    @SerializedName("replayLive")
 | 
			
		||||
    val replayLive: ApiResponse<List<GetAudioContentMainItem>>
 | 
			
		||||
)
 | 
			
		||||
 
 | 
			
		||||
@@ -6,10 +6,13 @@ import com.orhanobut.logger.Logger
 | 
			
		||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
 | 
			
		||||
import io.reactivex.rxjava3.core.Flowable
 | 
			
		||||
import io.reactivex.rxjava3.schedulers.Schedulers
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.AudioContentRepository
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentMainItem
 | 
			
		||||
import kr.co.vividnext.sodalive.base.BaseViewModel
 | 
			
		||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
 | 
			
		||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.CreatorCommunityRepository
 | 
			
		||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.GetCommunityPostListResponse
 | 
			
		||||
import kr.co.vividnext.sodalive.home.AudioContentMainItem
 | 
			
		||||
import kr.co.vividnext.sodalive.live.recommend.GetRecommendLiveResponse
 | 
			
		||||
import kr.co.vividnext.sodalive.live.recommend.LiveRecommendRepository
 | 
			
		||||
import kr.co.vividnext.sodalive.live.recommend_channel.GetRecommendChannelResponse
 | 
			
		||||
@@ -26,6 +29,7 @@ import kr.co.vividnext.sodalive.settings.event.EventRepository
 | 
			
		||||
class LiveViewModel(
 | 
			
		||||
    private val repository: LiveRepository,
 | 
			
		||||
    private val eventRepository: EventRepository,
 | 
			
		||||
    private val contentRepository: AudioContentRepository,
 | 
			
		||||
    private val liveRecommendRepository: LiveRecommendRepository,
 | 
			
		||||
    private val creatorCommunityRepository: CreatorCommunityRepository
 | 
			
		||||
) : BaseViewModel() {
 | 
			
		||||
@@ -61,6 +65,10 @@ class LiveViewModel(
 | 
			
		||||
    val communityPostItemLiveData: LiveData<List<GetCommunityPostListResponse>>
 | 
			
		||||
        get() = _communityPostItemLiveData
 | 
			
		||||
 | 
			
		||||
    private var _replayContentListLiveData = MutableLiveData<List<GetAudioContentMainItem>>()
 | 
			
		||||
    val replayContentListLiveData: LiveData<List<GetAudioContentMainItem>>
 | 
			
		||||
        get() = _replayContentListLiveData
 | 
			
		||||
 | 
			
		||||
    private val _latestFinishedLiveListLiveData =
 | 
			
		||||
        MutableLiveData<List<GetLatestFinishedLiveResponse>>()
 | 
			
		||||
    val latestFinishedLiveListLiveData: LiveData<List<GetLatestFinishedLiveResponse>>
 | 
			
		||||
@@ -166,6 +174,10 @@ class LiveViewModel(
 | 
			
		||||
                token = "Bearer ${SharedPreferenceManager.token}"
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
            val replayLive = contentRepository.getAudioContentReplayLiveList(
 | 
			
		||||
                token = "Bearer ${SharedPreferenceManager.token}"
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
            _isLoading.postValue(true)
 | 
			
		||||
 | 
			
		||||
            compositeDisposable.add(
 | 
			
		||||
@@ -174,8 +186,18 @@ class LiveViewModel(
 | 
			
		||||
                    liveReservation,
 | 
			
		||||
                    event,
 | 
			
		||||
                    recommendLive,
 | 
			
		||||
                    latestFinishedLive
 | 
			
		||||
                ) { t1, t2, t3, t4, t5 -> LiveSummary(t1, t2, t3, t4, t5) }
 | 
			
		||||
                    latestFinishedLive,
 | 
			
		||||
                    replayLive
 | 
			
		||||
                ) { t1, t2, t3, t4, t5, t6 ->
 | 
			
		||||
                    LiveSummary(
 | 
			
		||||
                        liveNow = t1,
 | 
			
		||||
                        liveReservation = t2,
 | 
			
		||||
                        event = t3,
 | 
			
		||||
                        recommendLive = t4,
 | 
			
		||||
                        latestFinishedLive = t5,
 | 
			
		||||
                        replayLive = t6
 | 
			
		||||
                    )
 | 
			
		||||
                }
 | 
			
		||||
                    .subscribeOn(Schedulers.io())
 | 
			
		||||
                    .subscribe(
 | 
			
		||||
                        {
 | 
			
		||||
@@ -245,6 +267,12 @@ class LiveViewModel(
 | 
			
		||||
                                _latestFinishedLiveListLiveData.postValue(emptyList())
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
                            val replayLive = it.replayLive
 | 
			
		||||
                            if (replayLive.success && replayLive.data != null) {
 | 
			
		||||
                                val data = replayLive.data!!
 | 
			
		||||
                                _replayContentListLiveData.postValue(data)
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
                            _isLoading.postValue(false)
 | 
			
		||||
                        },
 | 
			
		||||
                        {
 | 
			
		||||
 
 | 
			
		||||
@@ -134,6 +134,38 @@
 | 
			
		||||
                android:clipToPadding="false"
 | 
			
		||||
                android:paddingHorizontal="24dp" />
 | 
			
		||||
 | 
			
		||||
            <LinearLayout
 | 
			
		||||
                android:id="@+id/ll_replay_live"
 | 
			
		||||
                android:layout_width="match_parent"
 | 
			
		||||
                android:layout_height="wrap_content"
 | 
			
		||||
                android:layout_marginHorizontal="24dp"
 | 
			
		||||
                android:orientation="horizontal">
 | 
			
		||||
 | 
			
		||||
                <TextView
 | 
			
		||||
                    android:layout_width="wrap_content"
 | 
			
		||||
                    android:layout_height="wrap_content"
 | 
			
		||||
                    android:fontFamily="@font/pretendard_bold"
 | 
			
		||||
                    android:text="라이브 "
 | 
			
		||||
                    android:textColor="@color/color_3bb9f1"
 | 
			
		||||
                    android:textSize="26sp" />
 | 
			
		||||
 | 
			
		||||
                <TextView
 | 
			
		||||
                    android:layout_width="wrap_content"
 | 
			
		||||
                    android:layout_height="wrap_content"
 | 
			
		||||
                    android:fontFamily="@font/pretendard_bold"
 | 
			
		||||
                    android:text="다시 듣기"
 | 
			
		||||
                    android:textColor="@color/white"
 | 
			
		||||
                    android:textSize="26sp" />
 | 
			
		||||
            </LinearLayout>
 | 
			
		||||
 | 
			
		||||
            <androidx.recyclerview.widget.RecyclerView
 | 
			
		||||
                android:id="@+id/rv_replay_live"
 | 
			
		||||
                android:layout_width="match_parent"
 | 
			
		||||
                android:layout_height="wrap_content"
 | 
			
		||||
                android:layout_marginTop="16dp"
 | 
			
		||||
                android:layout_marginBottom="48dp"
 | 
			
		||||
                android:clipToPadding="false"
 | 
			
		||||
                android:paddingHorizontal="24dp" />
 | 
			
		||||
 | 
			
		||||
            <include
 | 
			
		||||
                android:id="@+id/layout_recommend_channel"
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user