feat(creator): 라이브 탭 본인 CTA를 연결한다
This commit is contained in:
@@ -387,6 +387,7 @@ class CreatorChannelActivity :
|
||||
bindHeader(header)
|
||||
bindTitleBar(header)
|
||||
updateOwnerFabVisibility()
|
||||
findLiveFragment()?.onCreatorChannelOwnerChanged(header.isOwner)
|
||||
}
|
||||
|
||||
override fun onCreatorChannelFollowProgressChanged(inProgress: Boolean) {
|
||||
@@ -425,6 +426,10 @@ class CreatorChannelActivity :
|
||||
postCheckCreatorChannelLiveNeedsMore()
|
||||
}
|
||||
|
||||
override fun isCreatorChannelOwner(): Boolean {
|
||||
return currentHeader?.isOwner == true
|
||||
}
|
||||
|
||||
private fun setupOwnerFabInsets() {
|
||||
ViewCompat.setOnApplyWindowInsetsListener(binding.ownerFabButton) { _, insets ->
|
||||
val navigationBottomInset = insets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom
|
||||
@@ -556,6 +561,10 @@ class CreatorChannelActivity :
|
||||
startAudioContentDetail(audioContentId)
|
||||
}
|
||||
|
||||
override fun onCreatorChannelLiveStartClicked() {
|
||||
onOwnerFabLiveClicked()
|
||||
}
|
||||
|
||||
private fun findLiveFragment(): CreatorChannelLiveFragment? {
|
||||
val fragmentTag = "f${CreatorChannelTab.Live.ordinal}"
|
||||
return supportFragmentManager.findFragmentByTag(fragmentTag) as? CreatorChannelLiveFragment
|
||||
|
||||
@@ -3,11 +3,17 @@ package kr.co.vividnext.sodalive.v2.creator.channel.live
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.core.view.updatePadding
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.base.BaseFragment
|
||||
import kr.co.vividnext.sodalive.databinding.FragmentCreatorChannelLiveBinding
|
||||
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||
import kr.co.vividnext.sodalive.extensions.moneyFormat
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.data.CreatorChannelLiveResponse
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.live.model.toLabelResId
|
||||
@@ -28,6 +34,8 @@ class CreatorChannelLiveFragment : BaseFragment<FragmentCreatorChannelLiveBindin
|
||||
private var lastContentLayoutKey: CreatorChannelLiveContentLayoutKey? = null
|
||||
private var sortPopup: CreatorChannelLiveSortPopup? = null
|
||||
private var currentContentState: CreatorChannelLiveUiState.Content? = null
|
||||
private var isOwner: Boolean = false
|
||||
private var ownerCtaBottomInset: Int = 0
|
||||
private val creatorId: Long by lazy { arguments?.getLong(ARG_CREATOR_ID) ?: 0L }
|
||||
private val host: Host
|
||||
get() = requireActivity() as Host
|
||||
@@ -36,8 +44,15 @@ class CreatorChannelLiveFragment : BaseFragment<FragmentCreatorChannelLiveBindin
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
bindLoading()
|
||||
setupReplayList()
|
||||
setupOwnerCtaInsets()
|
||||
setupClickListeners()
|
||||
observeViewModel()
|
||||
bindOwnerCta(host.isCreatorChannelOwner())
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
binding.layoutCreatorChannelLiveOwnerCta.isEnabled = true
|
||||
}
|
||||
|
||||
fun onCreatorChannelLiveTabSelected() {
|
||||
@@ -63,6 +78,19 @@ class CreatorChannelLiveFragment : BaseFragment<FragmentCreatorChannelLiveBindin
|
||||
viewModel.loadMore()
|
||||
}
|
||||
|
||||
fun onCreatorChannelOwnerChanged(isOwner: Boolean) {
|
||||
bindOwnerCta(isOwner)
|
||||
}
|
||||
|
||||
private fun setupOwnerCtaInsets() {
|
||||
ViewCompat.setOnApplyWindowInsetsListener(binding.layoutCreatorChannelLiveOwnerCta) { _, insets ->
|
||||
ownerCtaBottomInset = insets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom
|
||||
updateOwnerCtaInsets()
|
||||
insets
|
||||
}
|
||||
ViewCompat.requestApplyInsets(binding.layoutCreatorChannelLiveOwnerCta)
|
||||
}
|
||||
|
||||
private fun setupClickListeners() {
|
||||
binding.ivCreatorChannelLiveSort.setImageResource(R.drawable.ic_new_sort)
|
||||
binding.layoutCreatorChannelLiveSortButton.setOnClickListener {
|
||||
@@ -71,6 +99,29 @@ class CreatorChannelLiveFragment : BaseFragment<FragmentCreatorChannelLiveBindin
|
||||
binding.btnCreatorChannelLiveRetry.setOnClickListener {
|
||||
viewModel.retryLive()
|
||||
}
|
||||
binding.layoutCreatorChannelLiveOwnerCta.setOnClickListener {
|
||||
binding.layoutCreatorChannelLiveOwnerCta.isEnabled = false
|
||||
host.onCreatorChannelLiveStartClicked()
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindOwnerCta(isOwner: Boolean) = with(binding) {
|
||||
this@CreatorChannelLiveFragment.isOwner = isOwner
|
||||
layoutCreatorChannelLiveOwnerCta.isVisible = isOwner
|
||||
updateOwnerCtaInsets()
|
||||
}
|
||||
|
||||
private fun updateOwnerCtaInsets() = with(binding) {
|
||||
val baseBottomMargin = OWNER_CTA_BASE_MARGIN_DP.dpToPx().toInt()
|
||||
val listBottomPadding = if (isOwner) {
|
||||
OWNER_CTA_LIST_BOTTOM_PADDING_DP.dpToPx().toInt() + ownerCtaBottomInset
|
||||
} else {
|
||||
DEFAULT_LIST_BOTTOM_PADDING_DP.dpToPx().toInt()
|
||||
}
|
||||
layoutCreatorChannelLiveOwnerCta.updateLayoutParams<ConstraintLayout.LayoutParams> {
|
||||
bottomMargin = baseBottomMargin + ownerCtaBottomInset
|
||||
}
|
||||
rvCreatorChannelLiveReplays.updatePadding(bottom = listBottomPadding)
|
||||
}
|
||||
|
||||
private fun observeViewModel() {
|
||||
@@ -174,13 +225,18 @@ class CreatorChannelLiveFragment : BaseFragment<FragmentCreatorChannelLiveBindin
|
||||
}
|
||||
|
||||
interface Host {
|
||||
fun isCreatorChannelOwner(): Boolean
|
||||
fun onCreatorChannelCurrentLiveClicked(live: CreatorChannelLiveResponse)
|
||||
fun onCreatorChannelLiveReplayClicked(audioContentId: Long)
|
||||
fun onCreatorChannelLiveStartClicked()
|
||||
fun onCreatorChannelLiveContentChanged()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val ARG_CREATOR_ID: String = "arg_creator_id"
|
||||
private const val DEFAULT_LIST_BOTTOM_PADDING_DP = 32
|
||||
private const val OWNER_CTA_BASE_MARGIN_DP = 14
|
||||
private const val OWNER_CTA_LIST_BOTTOM_PADDING_DP = 102
|
||||
|
||||
fun newInstance(creatorId: Long): CreatorChannelLiveFragment {
|
||||
return CreatorChannelLiveFragment().apply {
|
||||
|
||||
@@ -994,6 +994,25 @@ class CreatorChannelActivitySourceTest {
|
||||
assertFalse(source.contains("startActivity(Intent(this, LiveRoomCreateActivity::class.java))"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `라이브 탭 owner CTA는 header 본인 여부와 기존 라이브 생성 플로우를 재사용한다`() {
|
||||
val source = 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/live/CreatorChannelLiveFragment.kt"
|
||||
).readText()
|
||||
|
||||
assertTrue(source.contains("findLiveFragment()?.onCreatorChannelOwnerChanged(header.isOwner)"))
|
||||
assertTrue(source.contains("override fun isCreatorChannelOwner(): Boolean"))
|
||||
assertTrue(source.contains("return currentHeader?.isOwner == true"))
|
||||
assertTrue(source.contains("override fun onCreatorChannelLiveStartClicked()"))
|
||||
assertTrue(source.contains("onOwnerFabLiveClicked()"))
|
||||
assertTrue(source.contains("liveRoomCreateLauncher.launch(Intent(this, LiveRoomCreateActivity::class.java))"))
|
||||
assertTrue(fragment.contains("fun onCreatorChannelOwnerChanged(isOwner: Boolean)"))
|
||||
assertTrue(fragment.contains("host.onCreatorChannelLiveStartClicked()"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `크리에이터 채널 라이브 로직은 coordinator로 분리한다`() {
|
||||
val activity = projectFile(
|
||||
|
||||
@@ -196,6 +196,32 @@ class CreatorChannelLiveFragmentLayoutTest {
|
||||
assertTrue(adapter.contains("layoutCreatorChannelLiveReplayActionText.isVisible = true"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `라이브 owner CTA source는 본인 여부 노출 inset padding click 연결을 포함한다`() {
|
||||
val fragment = projectFile(
|
||||
"app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/live/CreatorChannelLiveFragment.kt"
|
||||
).readText()
|
||||
val layout = projectFile("app/src/main/res/layout/fragment_creator_channel_live.xml").readText()
|
||||
|
||||
assertTrue(layout.contains("android:id=\"@+id/layout_creator_channel_live_owner_cta\""))
|
||||
assertTrue(layout.contains("@drawable/ic_new_create_live"))
|
||||
assertTrue(layout.contains("@string/creator_channel_live_start_button"))
|
||||
assertTrue(fragment.contains("setupOwnerCtaInsets()"))
|
||||
assertTrue(fragment.contains("WindowInsetsCompat.Type.navigationBars()"))
|
||||
assertTrue(fragment.contains("layoutCreatorChannelLiveOwnerCta.updateLayoutParams<ConstraintLayout.LayoutParams>"))
|
||||
assertTrue(fragment.contains("rvCreatorChannelLiveReplays.updatePadding"))
|
||||
assertTrue(fragment.contains("onCreatorChannelOwnerChanged(isOwner: Boolean)"))
|
||||
assertTrue(fragment.contains("bindOwnerCta(host.isCreatorChannelOwner())"))
|
||||
assertTrue(fragment.contains("layoutCreatorChannelLiveOwnerCta.isVisible = isOwner"))
|
||||
assertTrue(fragment.contains("layoutCreatorChannelLiveOwnerCta.setOnClickListener"))
|
||||
assertTrue(fragment.contains("host.onCreatorChannelLiveStartClicked()"))
|
||||
assertTrue(fragment.contains("layoutCreatorChannelLiveOwnerCta.isEnabled = false"))
|
||||
assertTrue(fragment.contains("onResume()"))
|
||||
assertTrue(fragment.contains("interface Host"))
|
||||
assertTrue(fragment.contains("fun isCreatorChannelOwner(): Boolean"))
|
||||
assertTrue(fragment.contains("fun onCreatorChannelLiveStartClicked()"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `라이브 sort popup source는 outside dismiss와 화면 밖 보정 및 같은 정렬 dismiss를 포함한다`() {
|
||||
val popup = projectFile(
|
||||
|
||||
Reference in New Issue
Block a user