fix(home): 메인 홈 추천 탭 지금 라이브 중 입장을 연결한다
This commit is contained in:
@@ -3,6 +3,7 @@ package kr.co.vividnext.sodalive.v2.creator.channel
|
||||
import android.content.Intent
|
||||
import android.view.LayoutInflater
|
||||
import android.widget.Toast
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.audio_content.AudioContentPlayService
|
||||
@@ -27,7 +28,7 @@ import java.util.Locale
|
||||
import java.util.TimeZone
|
||||
|
||||
class CreatorChannelLiveCoordinator(
|
||||
private val activity: CreatorChannelActivity,
|
||||
private val activity: FragmentActivity,
|
||||
private val layoutInflater: LayoutInflater,
|
||||
private val fragmentManager: FragmentManager,
|
||||
private val liveViewModel: LiveViewModel,
|
||||
@@ -65,38 +66,64 @@ class CreatorChannelLiveCoordinator(
|
||||
}
|
||||
|
||||
liveViewModel.getRoomDetail(roomId) {
|
||||
if (!it.channelName.isNullOrBlank()) {
|
||||
if (it.manager.id == SharedPreferenceManager.userId) {
|
||||
liveViewModel.enterRoom(roomId, onEnterRoomSuccess)
|
||||
} else if (it.price == 0 || it.isPaid) {
|
||||
if (it.isPrivateRoom) {
|
||||
LiveRoomPasswordDialog(
|
||||
activity = activity,
|
||||
layoutInflater = layoutInflater,
|
||||
can = 0,
|
||||
confirmButtonClick = { password ->
|
||||
liveViewModel.enterRoom(
|
||||
roomId = roomId,
|
||||
onSuccess = onEnterRoomSuccess,
|
||||
password = password
|
||||
)
|
||||
}
|
||||
).show(screenWidthProvider())
|
||||
} else {
|
||||
liveViewModel.enterRoom(roomId, onEnterRoomSuccess)
|
||||
}
|
||||
enterLiveRoom(roomId, it, onEnterRoomSuccess)
|
||||
}
|
||||
}
|
||||
|
||||
fun enterLiveRoom(roomId: Long, roomDetail: GetRoomDetailResponse) {
|
||||
activity.startService(
|
||||
Intent(activity, AudioContentPlayService::class.java).apply {
|
||||
action = AudioContentPlayService.MusicAction.STOP.name
|
||||
}
|
||||
)
|
||||
activity.startService(
|
||||
Intent(activity, AudioContentPlayerService::class.java).apply {
|
||||
action = "STOP_SERVICE"
|
||||
}
|
||||
)
|
||||
|
||||
val onEnterRoomSuccess = {
|
||||
activity.runOnUiThread { openLiveRoom(roomId) }
|
||||
}
|
||||
enterLiveRoom(roomId, roomDetail, onEnterRoomSuccess)
|
||||
}
|
||||
|
||||
private fun enterLiveRoom(
|
||||
roomId: Long,
|
||||
roomDetail: GetRoomDetailResponse,
|
||||
onEnterRoomSuccess: () -> Unit
|
||||
) {
|
||||
if (!roomDetail.channelName.isNullOrBlank()) {
|
||||
if (roomDetail.manager.id == SharedPreferenceManager.userId) {
|
||||
liveViewModel.enterRoom(roomId, onEnterRoomSuccess)
|
||||
} else if (roomDetail.price == 0 || roomDetail.isPaid) {
|
||||
if (roomDetail.isPrivateRoom) {
|
||||
LiveRoomPasswordDialog(
|
||||
activity = activity,
|
||||
layoutInflater = layoutInflater,
|
||||
can = 0,
|
||||
confirmButtonClick = { password ->
|
||||
liveViewModel.enterRoom(
|
||||
roomId = roomId,
|
||||
onSuccess = onEnterRoomSuccess,
|
||||
password = password
|
||||
)
|
||||
}
|
||||
).show(screenWidthProvider())
|
||||
} else {
|
||||
showPaidLiveEntryDialog(
|
||||
roomId = roomId,
|
||||
beginDateTimeUtc = it.beginDateTimeUtc,
|
||||
price = it.price,
|
||||
isPrivateRoom = it.isPrivateRoom,
|
||||
onEnterRoomSuccess = onEnterRoomSuccess
|
||||
)
|
||||
liveViewModel.enterRoom(roomId, onEnterRoomSuccess)
|
||||
}
|
||||
} else {
|
||||
showLiveRoomDetail(roomId)
|
||||
showPaidLiveEntryDialog(
|
||||
roomId = roomId,
|
||||
beginDateTimeUtc = roomDetail.beginDateTimeUtc,
|
||||
price = roomDetail.price,
|
||||
isPrivateRoom = roomDetail.isPrivateRoom,
|
||||
onEnterRoomSuccess = onEnterRoomSuccess
|
||||
)
|
||||
}
|
||||
} else {
|
||||
showLiveRoomDetail(roomId)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,9 +17,11 @@ import kr.co.vividnext.sodalive.explorer.profile.creator_community.all.CreatorCo
|
||||
import kr.co.vividnext.sodalive.following.FollowingCreatorActivity
|
||||
import kr.co.vividnext.sodalive.chat.talk.room.ChatRoomActivity
|
||||
import kr.co.vividnext.sodalive.home.pushnotification.PushNotificationListActivity
|
||||
import kr.co.vividnext.sodalive.live.LiveViewModel
|
||||
import kr.co.vividnext.sodalive.mypage.can.charge.CanChargeActivity
|
||||
import kr.co.vividnext.sodalive.search.SearchActivity
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivity
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelLiveCoordinator
|
||||
import kr.co.vividnext.sodalive.v2.live.onair.HomeOnAirLiveActivity
|
||||
import kr.co.vividnext.sodalive.v2.main.chat.dm.DmChatRoomActivity
|
||||
import kr.co.vividnext.sodalive.v2.main.chat.model.ChatRoomListUiItem
|
||||
@@ -74,6 +76,7 @@ import kr.co.vividnext.sodalive.v2.main.home.ui.HomeRecentDebutCreatorAdapter
|
||||
import kr.co.vividnext.sodalive.v2.widget.creatorranking.CreatorRankingAdapter
|
||||
import kr.co.vividnext.sodalive.v2.widget.creatorranking.CreatorRankingItem
|
||||
import kr.co.vividnext.sodalive.v2.widget.feed.FeedItem
|
||||
import org.koin.android.ext.android.inject
|
||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||
|
||||
class HomeMainFragment : BaseFragment<FragmentV2MainHomeBinding>(
|
||||
@@ -82,7 +85,18 @@ class HomeMainFragment : BaseFragment<FragmentV2MainHomeBinding>(
|
||||
private val homeRecommendationViewModel: HomeRecommendationViewModel by viewModel()
|
||||
private val homeCreatorRankingViewModel: HomeCreatorRankingViewModel by viewModel()
|
||||
private val homeFollowingViewModel: HomeFollowingViewModel by viewModel()
|
||||
private val liveViewModel: LiveViewModel by inject()
|
||||
private val loadingDialog: LoadingDialog by lazy { LoadingDialog(requireActivity(), layoutInflater) }
|
||||
private val liveCoordinator: CreatorChannelLiveCoordinator by lazy {
|
||||
CreatorChannelLiveCoordinator(
|
||||
activity = requireActivity(),
|
||||
layoutInflater = layoutInflater,
|
||||
fragmentManager = requireActivity().supportFragmentManager,
|
||||
liveViewModel = liveViewModel,
|
||||
screenWidthProvider = { screenWidth },
|
||||
refreshHome = { homeRecommendationViewModel.loadRecommendations() }
|
||||
)
|
||||
}
|
||||
private val liveAdapter = HomeLiveAdapter()
|
||||
private val recentActivityCreatorAdapter = HomeRecentActivityCreatorAdapter { onRecentActivityClick(it) }
|
||||
private val recentDebutCreatorAdapter = HomeRecentDebutCreatorAdapter { openCreatorProfile(it.creatorId) }
|
||||
@@ -111,6 +125,10 @@ class HomeMainFragment : BaseFragment<FragmentV2MainHomeBinding>(
|
||||
private var hasLoadedCreatorRankings = false
|
||||
private var hasLoadedFollowing = false
|
||||
private var currentHomeTabIndex = HOME_TAB_RECOMMENDATION
|
||||
private var isRecommendationLoading = false
|
||||
private var isCreatorRankingLoading = false
|
||||
private var isFollowingLoading = false
|
||||
private var isLiveEntryLoading = false
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
@@ -138,6 +156,7 @@ class HomeMainFragment : BaseFragment<FragmentV2MainHomeBinding>(
|
||||
bindHomeRecommendationObservers()
|
||||
bindHomeCreatorRankingObservers()
|
||||
bindHomeFollowingObservers()
|
||||
bindLiveEntryObservers()
|
||||
homeRecommendationViewModel.loadRecommendations()
|
||||
}
|
||||
|
||||
@@ -252,11 +271,8 @@ class HomeMainFragment : BaseFragment<FragmentV2MainHomeBinding>(
|
||||
}
|
||||
}
|
||||
homeCreatorRankingViewModel.isLoading.observe(viewLifecycleOwner) { isLoading ->
|
||||
if (isLoading) {
|
||||
loadingDialog.show(screenWidth)
|
||||
} else {
|
||||
loadingDialog.dismiss()
|
||||
}
|
||||
isCreatorRankingLoading = isLoading
|
||||
updateLoadingDialog()
|
||||
}
|
||||
homeCreatorRankingViewModel.toastLiveData.observe(viewLifecycleOwner) { toastMessage ->
|
||||
toastMessage?.let(::showToast)
|
||||
@@ -315,11 +331,8 @@ class HomeMainFragment : BaseFragment<FragmentV2MainHomeBinding>(
|
||||
}
|
||||
}
|
||||
homeFollowingViewModel.isLoading.observe(viewLifecycleOwner) { isLoading ->
|
||||
if (isLoading) {
|
||||
loadingDialog.show(screenWidth)
|
||||
} else {
|
||||
loadingDialog.dismiss()
|
||||
}
|
||||
isFollowingLoading = isLoading
|
||||
updateLoadingDialog()
|
||||
}
|
||||
homeFollowingViewModel.toastLiveData.observe(viewLifecycleOwner) { toastMessage ->
|
||||
toastMessage?.let(::showToast)
|
||||
@@ -337,17 +350,32 @@ class HomeMainFragment : BaseFragment<FragmentV2MainHomeBinding>(
|
||||
}
|
||||
}
|
||||
homeRecommendationViewModel.isLoading.observe(viewLifecycleOwner) { isLoading ->
|
||||
if (isLoading) {
|
||||
loadingDialog.show(screenWidth)
|
||||
} else {
|
||||
loadingDialog.dismiss()
|
||||
}
|
||||
isRecommendationLoading = isLoading
|
||||
updateLoadingDialog()
|
||||
}
|
||||
homeRecommendationViewModel.toastLiveData.observe(viewLifecycleOwner) { toastMessage ->
|
||||
toastMessage?.let(::showToast)
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindLiveEntryObservers() {
|
||||
liveViewModel.isLoading.observe(viewLifecycleOwner) { isLoading ->
|
||||
isLiveEntryLoading = isLoading
|
||||
updateLoadingDialog()
|
||||
}
|
||||
liveViewModel.toastLiveData.observe(viewLifecycleOwner) { message ->
|
||||
message?.let { showToast(it) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateLoadingDialog() {
|
||||
if (isRecommendationLoading || isCreatorRankingLoading || isFollowingLoading || isLiveEntryLoading) {
|
||||
loadingDialog.show(screenWidth)
|
||||
} else {
|
||||
loadingDialog.dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindHomeRecommendationContent(content: HomeRecommendationUiState.Content) {
|
||||
bindLiveSection(content.lives)
|
||||
bindBannerSection(content.banners)
|
||||
@@ -514,7 +542,16 @@ class HomeMainFragment : BaseFragment<FragmentV2MainHomeBinding>(
|
||||
ivSectionTitleChevron.visibility = if (showMore) View.VISIBLE else View.GONE
|
||||
}
|
||||
|
||||
private fun onLiveClick(item: HomeRecommendationLiveUiModel) = Unit
|
||||
private fun onLiveClick(item: HomeRecommendationLiveUiModel) {
|
||||
ensureMainV2NavigationAllowed {
|
||||
liveViewModel.getRoomDetail(item.roomId) { roomDetail ->
|
||||
if (!isAdded || view == null) return@getRoomDetail
|
||||
ensureMainV2NavigationAllowed(requiresAdultContentAccess = roomDetail.isAdult) {
|
||||
liveCoordinator.enterLiveRoom(item.roomId, roomDetail)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun openHomeOnAirLive() {
|
||||
ensureMainV2NavigationAllowed {
|
||||
|
||||
@@ -77,6 +77,46 @@ class HomeMainFragmentLoginGuardSourceTest {
|
||||
assertTrue(showHomeTabSource.contains("currentHomeTabIndex = index"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `HomeMainFragment 추천 라이브 아이템은 로그인과 성인 가드 후 기존 입장 흐름을 실행한다`() {
|
||||
val source = projectFile(
|
||||
"app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/HomeMainFragment.kt"
|
||||
).readText()
|
||||
|
||||
val clickSource = source.substringFrom("private fun onLiveClick(item: HomeRecommendationLiveUiModel)")
|
||||
assertTrue(clickSource.contains("ensureMainV2NavigationAllowed"))
|
||||
assertTrue(clickSource.contains("liveViewModel.getRoomDetail(item.roomId) { roomDetail ->"))
|
||||
assertBefore(clickSource, "if (!isAdded || view == null) return@getRoomDetail", "requiresAdultContentAccess = roomDetail.isAdult")
|
||||
assertBefore(clickSource, "liveViewModel.getRoomDetail(item.roomId) { roomDetail ->", "requiresAdultContentAccess = roomDetail.isAdult")
|
||||
assertBefore(clickSource, "requiresAdultContentAccess = roomDetail.isAdult", "liveCoordinator.enterLiveRoom(item.roomId, roomDetail)")
|
||||
assertFalse(clickSource.contains("= Unit"))
|
||||
|
||||
assertTrue(source.contains("import kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelLiveCoordinator"))
|
||||
assertTrue(source.contains("private val liveCoordinator: CreatorChannelLiveCoordinator by lazy"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `HomeMainFragment loading dialog는 통합 loading state로 제어한다`() {
|
||||
val source = projectFile(
|
||||
"app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/HomeMainFragment.kt"
|
||||
).readText()
|
||||
|
||||
assertTrue(source.contains("private var isRecommendationLoading = false"))
|
||||
assertTrue(source.contains("private var isCreatorRankingLoading = false"))
|
||||
assertTrue(source.contains("private var isFollowingLoading = false"))
|
||||
assertTrue(source.contains("private var isLiveEntryLoading = false"))
|
||||
|
||||
val updateSource = source.substringFrom("private fun updateLoadingDialog()")
|
||||
assertTrue(updateSource.contains("isRecommendationLoading || isCreatorRankingLoading || isFollowingLoading || isLiveEntryLoading"))
|
||||
assertTrue(updateSource.contains("loadingDialog.show(screenWidth)"))
|
||||
assertTrue(updateSource.contains("loadingDialog.dismiss()"))
|
||||
|
||||
assertLoadingObserverUsesUpdate(source, "homeRecommendationViewModel.isLoading.observe(viewLifecycleOwner)", "isRecommendationLoading = isLoading")
|
||||
assertLoadingObserverUsesUpdate(source, "homeCreatorRankingViewModel.isLoading.observe(viewLifecycleOwner)", "isCreatorRankingLoading = isLoading")
|
||||
assertLoadingObserverUsesUpdate(source, "homeFollowingViewModel.isLoading.observe(viewLifecycleOwner)", "isFollowingLoading = isLoading")
|
||||
assertLoadingObserverUsesUpdate(source, "liveViewModel.isLoading.observe(viewLifecycleOwner)", "isLiveEntryLoading = isLoading")
|
||||
}
|
||||
|
||||
private fun assertGuardedStartActivity(source: String, functionSignature: String) {
|
||||
val functionSource = source.substringFrom(functionSignature)
|
||||
assertTrue(
|
||||
@@ -101,6 +141,14 @@ class HomeMainFragmentLoginGuardSourceTest {
|
||||
assertTrue("Missing source after $expectedBefore: $expectedAfter", afterIndex > beforeIndex)
|
||||
}
|
||||
|
||||
private fun assertLoadingObserverUsesUpdate(source: String, observerMarker: String, loadingAssignment: String) {
|
||||
val observerSource = source.substringFrom(observerMarker)
|
||||
assertTrue(observerSource.contains(loadingAssignment))
|
||||
assertTrue(observerSource.contains("updateLoadingDialog()"))
|
||||
assertFalse(observerSource.contains("loadingDialog.show(screenWidth)"))
|
||||
assertFalse(observerSource.contains("loadingDialog.dismiss()"))
|
||||
}
|
||||
|
||||
private fun String.substringFrom(marker: String): String {
|
||||
val startIndex = indexOf(marker)
|
||||
assertTrue("Missing function: $marker", startIndex >= 0)
|
||||
|
||||
Reference in New Issue
Block a user