fix(creator): 채널 라이브 진입을 보강한다

This commit is contained in:
2026-06-17 10:58:49 +09:00
parent 34876cf46f
commit f2f2a3143d
5 changed files with 330 additions and 30 deletions

View File

@@ -11,6 +11,7 @@ import kr.co.vividnext.sodalive.v2.creator.channel.ui.calculateCreatorChannelSer
import kr.co.vividnext.sodalive.v2.creator.channel.ui.calculateCreatorChannelSeriesCardWidthDp
import kr.co.vividnext.sodalive.v2.creator.channel.ui.calculateCreatorChannelScheduleTimelineLineCount
import kr.co.vividnext.sodalive.v2.creator.channel.ui.formatCreatorChannelDebutActivityValue
import kr.co.vividnext.sodalive.v2.creator.channel.ui.formatCreatorChannelLiveDateTime
import kr.co.vividnext.sodalive.v2.creator.channel.ui.formatCreatorChannelScheduleDate
import kr.co.vividnext.sodalive.v2.creator.channel.ui.formatCreatorChannelScheduleDayOfWeek
import kr.co.vividnext.sodalive.v2.creator.channel.ui.formatCreatorChannelScheduleTime
@@ -904,6 +905,132 @@ class CreatorChannelActivitySourceTest {
assertEquals("오전 12:00", formatCreatorChannelScheduleTime("2026-06-29T15:00:00Z", timeZone, locale))
}
@Test
fun `현재 진행 중인 라이브 시간은 디바이스 timezone 기준 초 단위 날짜 시간으로 표시한다`() {
val timeZone = TimeZone.getTimeZone("Asia/Seoul")
val locale = Locale.KOREA
assertEquals("2026.06.30 00:00:01", formatCreatorChannelLiveDateTime("2026-06-29T15:00:01Z", timeZone, locale))
}
@Test
fun `owner FAB 라이브 생성 결과는 기존 enterLiveRoom 플로우로 입장한다`() {
val source = projectFile(
"app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivity.kt"
).readText()
val coordinator = projectFile(
"app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelLiveCoordinator.kt"
).readText()
assertTrue(source.contains("ActivityResultContracts.StartActivityForResult()"))
assertTrue(source.contains("private val liveViewModel: LiveViewModel by inject()"))
assertTrue(source.contains("private val liveCoordinator: CreatorChannelLiveCoordinator by lazy"))
assertTrue(source.contains("private val liveRoomCreateLauncher"))
assertTrue(source.contains("result.resultCode == RESULT_OK"))
assertTrue(source.contains("result.data?.getLongExtra(Constants.EXTRA_ROOM_ID, 0L)"))
assertTrue(source.contains("result.data?.getStringExtra(Constants.EXTRA_ROOM_CHANNEL_NAME)"))
assertTrue(source.contains("if (channelName != null)"))
assertTrue(source.contains("?.takeIf { it > 0L }"))
assertTrue(source.contains("?.let(liveCoordinator::enterLiveRoom)"))
assertTrue(source.contains("showToast(getString(R.string.creator_channel_live_created_message))"))
assertTrue(source.contains("homeActionDelegate?.refreshHome()"))
assertTrue(coordinator.contains("fun enterLiveRoom(roomId: Long)"))
assertTrue(coordinator.contains("liveViewModel.getRoomDetail(roomId)"))
assertTrue(coordinator.contains("it.manager.id == SharedPreferenceManager.userId"))
assertTrue(coordinator.contains("liveViewModel.enterRoom(roomId, onEnterRoomSuccess)"))
assertTrue(coordinator.contains("LiveRoomPasswordDialog("))
assertTrue(coordinator.contains("LivePaymentDialog("))
assertTrue(coordinator.contains("putExtra(Constants.EXTRA_ROOM_ID, roomId)"))
assertTrue(source.contains("liveRoomCreateLauncher.launch(Intent(this, LiveRoomCreateActivity::class.java))"))
assertFalse(source.contains("startActivity(Intent(this, LiveRoomCreateActivity::class.java))"))
}
@Test
fun `크리에이터 채널 라이브 로직은 coordinator로 분리한다`() {
val activity = projectFile(
"app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivity.kt"
).readText()
val coordinator = projectFile(
"app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelLiveCoordinator.kt"
).readText()
assertTrue(coordinator.contains("class CreatorChannelLiveCoordinator("))
assertTrue(coordinator.contains("private val liveViewModel: LiveViewModel"))
assertTrue(coordinator.contains("private val refreshHome: () -> Unit"))
assertTrue(activity.contains("liveCoordinator.enterLiveRoom(live.liveId)"))
assertTrue(activity.contains("CreatorActivityType.Live -> liveCoordinator.showLiveRoomDetail(schedule.targetId)"))
assertFalse(activity.contains("private fun enterLiveRoom(roomId: Long)"))
assertFalse(activity.contains("private fun showPaidLiveEntryDialog("))
assertFalse(activity.contains("private fun openLiveRoom(roomId: Long)"))
}
@Test
fun `현재 라이브 입장 API 진행과 오류는 LoadingDialog와 toast로 표시한다`() {
val source = projectFile(
"app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivity.kt"
).readText()
assertTrue(source.contains("private lateinit var loadingDialog: LoadingDialog"))
assertTrue(source.contains("loadingDialog = LoadingDialog(this, layoutInflater)"))
assertTrue(source.contains("liveViewModel.toastLiveData.observe(this)"))
assertTrue(source.contains("it?.let(::showToast)"))
assertTrue(source.contains("liveViewModel.isLoading.observe(this)"))
assertTrue(source.contains("loadingDialog.show(screenWidth, getString(R.string.screen_live_loading))"))
assertTrue(source.contains("loadingDialog.dismiss()"))
assertTrue(source.contains("setupLiveEntryObservers()"))
}
@Test
fun `현재 라이브 카드는 동일한 enterLiveRoom 플로우로 입장한다`() {
val activity = projectFile(
"app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivity.kt"
).readText()
val fragment = projectFile(
"app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeFragment.kt"
).readText()
val adapter = projectFile(
"app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/ui/CreatorChannelHomeSectionAdapter.kt"
).readText()
assertTrue(adapter.contains("private val onLiveClick: (CreatorChannelLiveResponse) -> Unit = {}"))
assertTrue(adapter.contains("private val currentLiveCard: View?"))
assertTrue(adapter.contains("currentLiveCard?.setOnClickListener"))
assertTrue(adapter.contains("onLiveClick(item.live)"))
assertTrue(fragment.contains("onLiveClick = ::onCurrentLiveClicked"))
assertTrue(fragment.contains("private fun onCurrentLiveClicked(live: CreatorChannelLiveResponse)"))
assertTrue(fragment.contains("host.onCreatorChannelCurrentLiveClicked(live)"))
assertTrue(activity.contains("override fun onCreatorChannelCurrentLiveClicked(live: CreatorChannelLiveResponse)"))
assertTrue(activity.contains("ensureLoginAndAdultAuth(isAdult = live.isAdult)"))
assertTrue(activity.contains("liveCoordinator.enterLiveRoom(live.liveId)"))
assertTrue(activity.contains("private fun ensureLoginAndAdultAuth(isAdult: Boolean, onAuthed: () -> Unit)"))
assertTrue(activity.contains("SharedPreferenceManager.token.isBlank()"))
assertTrue(activity.contains("SodaDialog("))
assertTrue(activity.contains("R.string.auth_desc_live"))
assertTrue(activity.contains("ContentSettingsActivity::class.java"))
assertTrue(activity.contains("Constants.EXTRA_SHOW_SENSITIVE_CONTENT_GUIDE"))
}
@Test
fun `커뮤니티 작성 완료 결과는 홈 Fragment를 새로고침한다`() {
val activity = projectFile(
"app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivity.kt"
).readText()
val fragment = projectFile(
"app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeFragment.kt"
).readText()
val writeActivity = projectFile(
"app/src/main/java/kr/co/vividnext/sodalive/explorer/profile/creator_community/write/CreatorCommunityWriteActivity.kt"
).readText()
assertTrue(activity.contains("private val communityWriteLauncher"))
assertTrue(activity.contains("homeActionDelegate?.refreshHome()"))
assertTrue(activity.contains("communityWriteLauncher.launch(Intent(this, CreatorCommunityWriteActivity::class.java))"))
assertFalse(activity.contains("startActivity(Intent(this, CreatorCommunityWriteActivity::class.java))"))
assertTrue(fragment.contains("fun refreshHome()"))
assertTrue(fragment.contains("viewModel.loadHome(creatorId)"))
assertTrue(writeActivity.contains("setResult(Activity.RESULT_OK)"))
}
@Test
fun `일정 클릭은 콘텐츠 상세와 라이브 상세 이동 계약을 연결한다`() {
val source = projectFile(
@@ -922,9 +1049,29 @@ class CreatorChannelActivitySourceTest {
assertTrue(source.contains("AudioContentDetailActivity::class.java"))
assertTrue(source.contains("putExtra(Constants.EXTRA_AUDIO_CONTENT_ID, schedule.targetId)"))
assertTrue(source.contains("CreatorActivityType.Live"))
assertTrue(source.contains("CreatorActivityType.Live -> showLiveRoomDetail(schedule.targetId)"))
assertTrue(source.contains("LiveRoomDetailFragment("))
assertTrue(source.contains("detailFragment.show(supportFragmentManager, detailFragment.tag)"))
assertTrue(source.contains("CreatorActivityType.Live -> liveCoordinator.showLiveRoomDetail(schedule.targetId)"))
}
@Test
fun `일정 라이브 상세는 예약 수정 시작 취소 액션을 연결한다`() {
val coordinator = projectFile(
"app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelLiveCoordinator.kt"
).readText()
assertTrue(coordinator.contains("fun showLiveRoomDetail(roomId: Long)"))
assertTrue(coordinator.contains("LiveRoomDetailFragment("))
assertTrue(coordinator.contains("onClickReservation = { reservationRoom(roomId) }"))
assertTrue(coordinator.contains("onClickModify = { roomDetailResponse -> modifyLive(roomDetailResponse) }"))
assertTrue(coordinator.contains("onClickStart = { startLive(roomId) }"))
assertTrue(coordinator.contains("onClickCancel = { cancelLive(roomId) }"))
assertTrue(coordinator.contains("private fun reservationRoom(roomId: Long)"))
assertTrue(coordinator.contains("private fun processLiveReservation(roomId: Long, password: String? = null)"))
assertTrue(coordinator.contains("LiveReservationCompleteActivity::class.java"))
assertTrue(coordinator.contains("LiveRoomEditActivity::class.java"))
assertTrue(coordinator.contains("liveViewModel.startLive(roomId)"))
assertTrue(coordinator.contains("LiveCancelDialog("))
assertTrue(coordinator.contains("liveViewModel.cancelLive(roomId, reason)"))
assertTrue(coordinator.contains("refreshHome()"))
}
@Test
@@ -1471,9 +1618,9 @@ class CreatorChannelActivitySourceTest {
assertTrue(source.contains("private fun onOwnerFabCommunityClicked()"))
assertTrue(source.contains("private fun onOwnerFabAudioClicked()"))
assertTrue(source.contains("private fun onOwnerFabLiveClicked()"))
assertTrue(source.contains("startActivity(Intent(this, CreatorCommunityWriteActivity::class.java))"))
assertTrue(source.contains("communityWriteLauncher.launch(Intent(this, CreatorCommunityWriteActivity::class.java))"))
assertTrue(source.contains("startActivity(Intent(this, AudioContentUploadActivity::class.java))"))
assertTrue(source.contains("startActivity(Intent(this, LiveRoomCreateActivity::class.java))"))
assertTrue(source.contains("liveRoomCreateLauncher.launch(Intent(this, LiveRoomCreateActivity::class.java))"))
assertTrue(source.contains("collapseOwnerFab(animate = false)"))
}