fix(creator): 라이브 탭 하단 CTA와 sticky 전환을 보정한다
This commit is contained in:
@@ -14,7 +14,6 @@ import android.view.View.MeasureSpec
|
|||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
import androidx.core.view.ViewCompat
|
import androidx.core.view.ViewCompat
|
||||||
import androidx.core.view.WindowCompat
|
import androidx.core.view.WindowCompat
|
||||||
import androidx.core.view.WindowInsetsCompat
|
import androidx.core.view.WindowInsetsCompat
|
||||||
@@ -80,6 +79,7 @@ class CreatorChannelActivity :
|
|||||||
private var statusBarHeight: Int = 0
|
private var statusBarHeight: Int = 0
|
||||||
private var tabLayoutMediator: TabLayoutMediator? = null
|
private var tabLayoutMediator: TabLayoutMediator? = null
|
||||||
private var pageChangeCallback: ViewPager2.OnPageChangeCallback? = null
|
private var pageChangeCallback: ViewPager2.OnPageChangeCallback? = null
|
||||||
|
private var lastSelectedCreatorChannelTabPosition: Int? = null
|
||||||
private var isOwnerFabExpanded: Boolean = false
|
private var isOwnerFabExpanded: Boolean = false
|
||||||
private var isOwnerFabAnimating: Boolean = false
|
private var isOwnerFabAnimating: Boolean = false
|
||||||
private lateinit var loadingDialog: LoadingDialog
|
private lateinit var loadingDialog: LoadingDialog
|
||||||
@@ -129,6 +129,7 @@ class CreatorChannelActivity :
|
|||||||
setStatusBarIconAppearance()
|
setStatusBarIconAppearance()
|
||||||
setTitleBarTopInset()
|
setTitleBarTopInset()
|
||||||
setupOwnerFabInsets()
|
setupOwnerFabInsets()
|
||||||
|
setupLiveOwnerCtaInsets()
|
||||||
setupScrollListener()
|
setupScrollListener()
|
||||||
setupClickListeners()
|
setupClickListeners()
|
||||||
setupLiveEntryObservers()
|
setupLiveEntryObservers()
|
||||||
@@ -159,6 +160,7 @@ class CreatorChannelActivity :
|
|||||||
binding.ownerFabCommunityButton.setOnClickListener { onOwnerFabCommunityClicked() }
|
binding.ownerFabCommunityButton.setOnClickListener { onOwnerFabCommunityClicked() }
|
||||||
binding.ownerFabAudioButton.setOnClickListener { onOwnerFabAudioClicked() }
|
binding.ownerFabAudioButton.setOnClickListener { onOwnerFabAudioClicked() }
|
||||||
binding.ownerFabLiveButton.setOnClickListener { onOwnerFabLiveClicked() }
|
binding.ownerFabLiveButton.setOnClickListener { onOwnerFabLiveClicked() }
|
||||||
|
binding.btnCreatorChannelLiveOwnerCta.setOnClickListener { onLiveOwnerCtaClicked() }
|
||||||
binding.tvChatButton.setOnClickListener {
|
binding.tvChatButton.setOnClickListener {
|
||||||
currentHeader?.characterId?.let { characterId -> homeActionDelegate?.createChatRoom(characterId) }
|
currentHeader?.characterId?.let { characterId -> homeActionDelegate?.createChatRoom(characterId) }
|
||||||
}
|
}
|
||||||
@@ -308,6 +310,22 @@ class CreatorChannelActivity :
|
|||||||
binding.tvTitleNickname.isVisible = shouldUseBlackTitleBar
|
binding.tvTitleNickname.isVisible = shouldUseBlackTitleBar
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun adjustCreatorChannelStickyAnchorOnTabSelected(position: Int) {
|
||||||
|
val previousPosition = lastSelectedCreatorChannelTabPosition
|
||||||
|
lastSelectedCreatorChannelTabPosition = position
|
||||||
|
if (previousPosition == null || previousPosition == position) return
|
||||||
|
|
||||||
|
val stickyScrollY = calculateCreatorChannelStickyScrollY()
|
||||||
|
if (binding.nestedScrollView.scrollY < stickyScrollY) {
|
||||||
|
binding.nestedScrollView.scrollTo(0, stickyScrollY)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun calculateCreatorChannelStickyScrollY(): Int {
|
||||||
|
val stickyTop = CreatorChannelScrollState.calculateStickyTop(statusBarHeight, baseTitleBarHeight)
|
||||||
|
return (binding.headerContainer.height - stickyTop).coerceAtLeast(0)
|
||||||
|
}
|
||||||
|
|
||||||
private fun setStatusBarIconAppearance() {
|
private fun setStatusBarIconAppearance() {
|
||||||
WindowCompat.getInsetsController(window, binding.root).isAppearanceLightStatusBars = false
|
WindowCompat.getInsetsController(window, binding.root).isAppearanceLightStatusBars = false
|
||||||
}
|
}
|
||||||
@@ -364,12 +382,16 @@ class CreatorChannelActivity :
|
|||||||
}.also {
|
}.also {
|
||||||
it.attach()
|
it.attach()
|
||||||
}
|
}
|
||||||
|
lastSelectedCreatorChannelTabPosition = binding.viewPager.currentItem
|
||||||
val callback = object : ViewPager2.OnPageChangeCallback() {
|
val callback = object : ViewPager2.OnPageChangeCallback() {
|
||||||
override fun onPageSelected(position: Int) {
|
override fun onPageSelected(position: Int) {
|
||||||
|
adjustCreatorChannelStickyAnchorOnTabSelected(position)
|
||||||
if (position != CreatorChannelTab.Home.ordinal) {
|
if (position != CreatorChannelTab.Home.ordinal) {
|
||||||
collapseOwnerFab(animate = false)
|
collapseOwnerFab(animate = false)
|
||||||
}
|
}
|
||||||
updateOwnerFabVisibility()
|
updateOwnerFabVisibility()
|
||||||
|
updateLiveOwnerCtaVisibility()
|
||||||
|
updateCreatorChannelLiveViewportHeight()
|
||||||
updateViewPagerHeight()
|
updateViewPagerHeight()
|
||||||
if (position == CreatorChannelTab.Live.ordinal) {
|
if (position == CreatorChannelTab.Live.ordinal) {
|
||||||
binding.viewPager.post {
|
binding.viewPager.post {
|
||||||
@@ -387,7 +409,7 @@ class CreatorChannelActivity :
|
|||||||
bindHeader(header)
|
bindHeader(header)
|
||||||
bindTitleBar(header)
|
bindTitleBar(header)
|
||||||
updateOwnerFabVisibility()
|
updateOwnerFabVisibility()
|
||||||
findLiveFragment()?.onCreatorChannelOwnerChanged(header.isOwner)
|
updateLiveOwnerCtaVisibility()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreatorChannelFollowProgressChanged(inProgress: Boolean) {
|
override fun onCreatorChannelFollowProgressChanged(inProgress: Boolean) {
|
||||||
@@ -422,28 +444,28 @@ class CreatorChannelActivity :
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreatorChannelLiveContentChanged() {
|
override fun onCreatorChannelLiveContentChanged() {
|
||||||
|
updateCreatorChannelLiveViewportHeight()
|
||||||
updateViewPagerHeight()
|
updateViewPagerHeight()
|
||||||
postCheckCreatorChannelLiveNeedsMore()
|
postCheckCreatorChannelLiveNeedsMore()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isCreatorChannelOwner(): Boolean {
|
private fun setupOwnerFabInsets() {
|
||||||
return currentHeader?.isOwner == true
|
binding.viewPager.updatePadding(bottom = OWNER_FAB_CONTENT_BOTTOM_PADDING_DP.dpToPx().toInt())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupOwnerFabInsets() {
|
private fun setupLiveOwnerCtaInsets() {
|
||||||
ViewCompat.setOnApplyWindowInsetsListener(binding.ownerFabButton) { _, insets ->
|
updateLiveOwnerCtaVisibility()
|
||||||
val navigationBottomInset = insets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom
|
}
|
||||||
val bottomMargin = OWNER_FAB_BASE_MARGIN_DP.dpToPx().toInt() + navigationBottomInset
|
|
||||||
binding.ownerFabButton.updateLayoutParams<ConstraintLayout.LayoutParams> {
|
private fun updateLiveOwnerCtaVisibility() {
|
||||||
this.bottomMargin = bottomMargin
|
val shouldShowLiveOwnerCta = shouldShowLiveOwnerCta()
|
||||||
}
|
binding.layoutCreatorChannelLiveOwnerCta.isVisible = shouldShowLiveOwnerCta
|
||||||
binding.ownerFabExpandedContainer.updateLayoutParams<ConstraintLayout.LayoutParams> {
|
binding.btnCreatorChannelLiveOwnerCta.isEnabled = true
|
||||||
this.bottomMargin = bottomMargin
|
findLiveFragment()?.onCreatorChannelLiveOwnerCtaVisibilityChanged(shouldShowLiveOwnerCta)
|
||||||
}
|
}
|
||||||
binding.viewPager.updatePadding(bottom = OWNER_FAB_CONTENT_BOTTOM_PADDING_DP.dpToPx().toInt())
|
|
||||||
insets
|
private fun shouldShowLiveOwnerCta(): Boolean {
|
||||||
}
|
return currentHeader?.isOwner == true && binding.viewPager.currentItem == CreatorChannelTab.Live.ordinal
|
||||||
ViewCompat.requestApplyInsets(binding.ownerFabButton)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun expandOwnerFab() {
|
private fun expandOwnerFab() {
|
||||||
@@ -534,6 +556,11 @@ class CreatorChannelActivity :
|
|||||||
liveRoomCreateLauncher.launch(Intent(this, LiveRoomCreateActivity::class.java))
|
liveRoomCreateLauncher.launch(Intent(this, LiveRoomCreateActivity::class.java))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun onLiveOwnerCtaClicked() {
|
||||||
|
binding.btnCreatorChannelLiveOwnerCta.isEnabled = false
|
||||||
|
onOwnerFabLiveClicked()
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreatorChannelDonationClicked() {
|
override fun onCreatorChannelDonationClicked() {
|
||||||
val header = currentHeader ?: return
|
val header = currentHeader ?: return
|
||||||
if (header.isOwner) return
|
if (header.isOwner) return
|
||||||
@@ -561,10 +588,6 @@ class CreatorChannelActivity :
|
|||||||
startAudioContentDetail(audioContentId)
|
startAudioContentDetail(audioContentId)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreatorChannelLiveStartClicked() {
|
|
||||||
onOwnerFabLiveClicked()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun findLiveFragment(): CreatorChannelLiveFragment? {
|
private fun findLiveFragment(): CreatorChannelLiveFragment? {
|
||||||
val fragmentTag = "f${CreatorChannelTab.Live.ordinal}"
|
val fragmentTag = "f${CreatorChannelTab.Live.ordinal}"
|
||||||
return supportFragmentManager.findFragmentByTag(fragmentTag) as? CreatorChannelLiveFragment
|
return supportFragmentManager.findFragmentByTag(fragmentTag) as? CreatorChannelLiveFragment
|
||||||
@@ -636,10 +659,10 @@ class CreatorChannelActivity :
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun updateViewPagerHeight() {
|
private fun updateViewPagerHeight() {
|
||||||
|
updateCreatorChannelLiveViewportHeight()
|
||||||
binding.viewPager.post {
|
binding.viewPager.post {
|
||||||
val recyclerView = binding.viewPager.getChildAt(0) as? RecyclerView ?: return@post
|
val recyclerView = binding.viewPager.getChildAt(0) as? RecyclerView ?: return@post
|
||||||
val currentPage = recyclerView.layoutManager?.findViewByPosition(binding.viewPager.currentItem) ?: return@post
|
val currentPage = recyclerView.layoutManager?.findViewByPosition(binding.viewPager.currentItem) ?: return@post
|
||||||
currentPage.minimumHeight = calculateCreatorChannelTabViewportHeight()
|
|
||||||
val widthSpec = MeasureSpec.makeMeasureSpec(binding.viewPager.width, MeasureSpec.EXACTLY)
|
val widthSpec = MeasureSpec.makeMeasureSpec(binding.viewPager.width, MeasureSpec.EXACTLY)
|
||||||
val heightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)
|
val heightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)
|
||||||
currentPage.measure(widthSpec, heightSpec)
|
currentPage.measure(widthSpec, heightSpec)
|
||||||
@@ -652,6 +675,23 @@ class CreatorChannelActivity :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun updateCreatorChannelLiveViewportHeight() {
|
||||||
|
if (binding.viewPager.currentItem != CreatorChannelTab.Live.ordinal) return
|
||||||
|
|
||||||
|
findLiveFragment()?.onCreatorChannelLiveViewportHeightChanged(
|
||||||
|
calculateCreatorChannelLiveEmptyMinHeight()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun calculateCreatorChannelLiveEmptyMinHeight(): Int {
|
||||||
|
val stickyScrollY = calculateCreatorChannelStickyScrollY()
|
||||||
|
val visibleTabViewportHeight = binding.nestedScrollView.height - binding.tabLayout.height
|
||||||
|
val scrollRangeRequiredHeight = binding.nestedScrollView.height +
|
||||||
|
stickyScrollY -
|
||||||
|
binding.headerContainer.height
|
||||||
|
return maxOf(visibleTabViewportHeight, scrollRangeRequiredHeight, 0)
|
||||||
|
}
|
||||||
|
|
||||||
private fun postCheckCreatorChannelLiveNeedsMore() {
|
private fun postCheckCreatorChannelLiveNeedsMore() {
|
||||||
binding.nestedScrollView.post {
|
binding.nestedScrollView.post {
|
||||||
checkCreatorChannelLiveNeedsMore()
|
checkCreatorChannelLiveNeedsMore()
|
||||||
@@ -672,10 +712,6 @@ class CreatorChannelActivity :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun calculateCreatorChannelTabViewportHeight(): Int {
|
|
||||||
return (binding.nestedScrollView.height - binding.tabLayout.height).coerceAtLeast(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun onScheduleClicked(schedule: CreatorChannelScheduleResponse) {
|
private fun onScheduleClicked(schedule: CreatorChannelScheduleResponse) {
|
||||||
when (schedule.type) {
|
when (schedule.type) {
|
||||||
CreatorActivityType.Audio,
|
CreatorActivityType.Audio,
|
||||||
@@ -711,6 +747,11 @@ class CreatorChannelActivity :
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
binding.btnCreatorChannelLiveOwnerCta.isEnabled = true
|
||||||
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
tabLayoutMediator?.detach()
|
tabLayoutMediator?.detach()
|
||||||
pageChangeCallback?.let { callback ->
|
pageChangeCallback?.let { callback ->
|
||||||
@@ -741,7 +782,6 @@ class CreatorChannelActivity :
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val EXTRA_CREATOR_ID: String = "extra_creator_id"
|
const val EXTRA_CREATOR_ID: String = "extra_creator_id"
|
||||||
private const val OWNER_FAB_BASE_MARGIN_DP = 14
|
|
||||||
private const val OWNER_FAB_CONTENT_BOTTOM_PADDING_DP = 96
|
private const val OWNER_FAB_CONTENT_BOTTOM_PADDING_DP = 96
|
||||||
private const val OWNER_FAB_ANIMATION_DURATION_MS = 260L
|
private const val OWNER_FAB_ANIMATION_DURATION_MS = 260L
|
||||||
private const val OWNER_FAB_SPRING_MASS = 1f
|
private const val OWNER_FAB_SPRING_MASS = 1f
|
||||||
|
|||||||
@@ -238,6 +238,45 @@
|
|||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/layout_creator_channel_live_owner_cta"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="100dp"
|
||||||
|
android:background="@color/black"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/btn_creator_channel_live_owner_cta"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="52dp"
|
||||||
|
android:layout_marginHorizontal="@dimen/spacing_14"
|
||||||
|
android:layout_marginTop="@dimen/spacing_14"
|
||||||
|
android:background="@drawable/bg_creator_channel_owner_fab"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:contentDescription="@null"
|
||||||
|
android:src="@drawable/ic_new_create_live" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="@style/Typography.Heading3"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="@dimen/spacing_8"
|
||||||
|
android:includeFontPadding="false"
|
||||||
|
android:text="@string/creator_channel_live_start_button"
|
||||||
|
android:textColor="@color/white" />
|
||||||
|
</LinearLayout>
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:id="@+id/owner_fab_dim"
|
android:id="@+id/owner_fab_dim"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
|
|||||||
@@ -932,16 +932,57 @@ class CreatorChannelActivitySourceTest {
|
|||||||
assertTrue(source.contains("override fun onCreatorChannelLiveContentChanged()"))
|
assertTrue(source.contains("override fun onCreatorChannelLiveContentChanged()"))
|
||||||
assertTrue(source.contains("postCheckCreatorChannelLiveNeedsMore()"))
|
assertTrue(source.contains("postCheckCreatorChannelLiveNeedsMore()"))
|
||||||
assertTrue(source.contains("updateViewPagerHeight()"))
|
assertTrue(source.contains("updateViewPagerHeight()"))
|
||||||
|
assertTrue(source.contains("updateCreatorChannelLiveViewportHeight()"))
|
||||||
assertTrue(source.contains("if (position == CreatorChannelTab.Live.ordinal)"))
|
assertTrue(source.contains("if (position == CreatorChannelTab.Live.ordinal)"))
|
||||||
assertTrue(source.contains("findLiveFragment()?.onCreatorChannelLiveTabSelected()"))
|
assertTrue(source.contains("findLiveFragment()?.onCreatorChannelLiveTabSelected()"))
|
||||||
assertTrue(source.contains("binding.viewPager.offscreenPageLimit = CreatorChannelTab.entries.size - 1"))
|
assertTrue(source.contains("binding.viewPager.offscreenPageLimit = CreatorChannelTab.entries.size - 1"))
|
||||||
assertTrue(source.contains("currentPage.minimumHeight = calculateCreatorChannelTabViewportHeight()"))
|
assertFalse(source.contains("currentPage.minimumHeight = calculateCreatorChannelTabViewportHeight()"))
|
||||||
assertTrue(source.contains("private fun calculateCreatorChannelTabViewportHeight(): Int"))
|
assertFalse(source.contains("private fun calculateCreatorChannelTabViewportHeight(): Int"))
|
||||||
assertTrue(fragment.contains("fun onCreatorChannelLiveScrolledToBottom()"))
|
assertTrue(fragment.contains("fun onCreatorChannelLiveScrolledToBottom()"))
|
||||||
assertTrue(fragment.contains("fun onCreatorChannelLiveTabSelected()"))
|
assertTrue(fragment.contains("fun onCreatorChannelLiveTabSelected()"))
|
||||||
|
assertTrue(fragment.contains("fun onCreatorChannelLiveViewportHeightChanged(minHeight: Int)"))
|
||||||
assertTrue(fragment.contains("fun onCreatorChannelLiveContentChanged()"))
|
assertTrue(fragment.contains("fun onCreatorChannelLiveContentChanged()"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `라이브 empty 최소 높이는 sticky anchor 이후 탭 viewport 기준으로 전달한다`() {
|
||||||
|
val source = projectFile(
|
||||||
|
"app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivity.kt"
|
||||||
|
).readText()
|
||||||
|
|
||||||
|
assertTrue(source.contains("private fun updateCreatorChannelLiveViewportHeight()"))
|
||||||
|
assertTrue(source.contains("findLiveFragment()?.onCreatorChannelLiveViewportHeightChanged"))
|
||||||
|
assertTrue(source.contains("calculateCreatorChannelLiveEmptyMinHeight()"))
|
||||||
|
assertTrue(source.contains("private fun calculateCreatorChannelLiveEmptyMinHeight(): Int"))
|
||||||
|
assertTrue(source.contains("val stickyScrollY = calculateCreatorChannelStickyScrollY()"))
|
||||||
|
assertTrue(source.contains("binding.nestedScrollView.height - binding.tabLayout.height"))
|
||||||
|
assertTrue(source.contains("val scrollRangeRequiredHeight = binding.nestedScrollView.height +"))
|
||||||
|
assertTrue(source.contains("stickyScrollY -"))
|
||||||
|
assertTrue(source.contains("binding.headerContainer.height"))
|
||||||
|
assertTrue(source.contains("return maxOf(visibleTabViewportHeight, scrollRangeRequiredHeight, 0)"))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `탭 전환은 sticky tabbar anchor 아래로 내려간 scroll 위치를 되돌리지 않고 부족할 때만 보정한다`() {
|
||||||
|
val source = projectFile(
|
||||||
|
"app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivity.kt"
|
||||||
|
).readText()
|
||||||
|
|
||||||
|
assertTrue(source.contains("private var lastSelectedCreatorChannelTabPosition: Int? = null"))
|
||||||
|
assertTrue(source.contains("lastSelectedCreatorChannelTabPosition = binding.viewPager.currentItem"))
|
||||||
|
assertTrue(source.contains("lastSelectedCreatorChannelTabPosition = position"))
|
||||||
|
assertTrue(source.contains("adjustCreatorChannelStickyAnchorOnTabSelected(position)"))
|
||||||
|
assertTrue(source.contains("private fun adjustCreatorChannelStickyAnchorOnTabSelected(position: Int)"))
|
||||||
|
assertTrue(source.contains("val previousPosition = lastSelectedCreatorChannelTabPosition"))
|
||||||
|
assertTrue(source.contains("if (previousPosition == null || previousPosition == position)"))
|
||||||
|
assertTrue(source.contains("val stickyScrollY = calculateCreatorChannelStickyScrollY()"))
|
||||||
|
assertTrue(source.contains("if (binding.nestedScrollView.scrollY < stickyScrollY)"))
|
||||||
|
assertTrue(source.contains("binding.nestedScrollView.scrollTo(0, stickyScrollY)"))
|
||||||
|
assertTrue(source.contains("private fun calculateCreatorChannelStickyScrollY(): Int"))
|
||||||
|
assertTrue(source.contains("CreatorChannelScrollState.calculateStickyTop(statusBarHeight, baseTitleBarHeight)"))
|
||||||
|
assertTrue(source.contains("return (binding.headerContainer.height - stickyTop).coerceAtLeast(0)"))
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `라이브 content 변경은 현재 scroll bottom 조건을 재평가한다`() {
|
fun `라이브 content 변경은 현재 scroll bottom 조건을 재평가한다`() {
|
||||||
val source = projectFile(
|
val source = projectFile(
|
||||||
@@ -999,18 +1040,39 @@ class CreatorChannelActivitySourceTest {
|
|||||||
val source = projectFile(
|
val source = projectFile(
|
||||||
"app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivity.kt"
|
"app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivity.kt"
|
||||||
).readText()
|
).readText()
|
||||||
val fragment = projectFile(
|
val activityLayout = projectFile("app/src/main/res/layout/activity_creator_channel.xml").readText()
|
||||||
"app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/live/CreatorChannelLiveFragment.kt"
|
|
||||||
).readText()
|
|
||||||
|
|
||||||
assertTrue(source.contains("findLiveFragment()?.onCreatorChannelOwnerChanged(header.isOwner)"))
|
assertTrue(activityLayout.contains("android:id=\"@+id/layout_creator_channel_live_owner_cta\""))
|
||||||
assertTrue(source.contains("override fun isCreatorChannelOwner(): Boolean"))
|
assertTrue(source.contains("updateLiveOwnerCtaVisibility()"))
|
||||||
|
assertTrue(
|
||||||
|
source.contains(
|
||||||
|
"currentHeader?.isOwner == true && binding.viewPager.currentItem == CreatorChannelTab.Live.ordinal"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
assertTrue(source.contains("binding.layoutCreatorChannelLiveOwnerCta.isVisible = shouldShowLiveOwnerCta"))
|
||||||
|
assertTrue(source.contains("findLiveFragment()?.onCreatorChannelLiveOwnerCtaVisibilityChanged(shouldShowLiveOwnerCta)"))
|
||||||
assertTrue(source.contains("return currentHeader?.isOwner == true"))
|
assertTrue(source.contains("return currentHeader?.isOwner == true"))
|
||||||
assertTrue(source.contains("override fun onCreatorChannelLiveStartClicked()"))
|
assertTrue(source.contains("binding.btnCreatorChannelLiveOwnerCta.setOnClickListener { onLiveOwnerCtaClicked() }"))
|
||||||
assertTrue(source.contains("onOwnerFabLiveClicked()"))
|
assertTrue(source.contains("onOwnerFabLiveClicked()"))
|
||||||
assertTrue(source.contains("liveRoomCreateLauncher.launch(Intent(this, LiveRoomCreateActivity::class.java))"))
|
assertTrue(source.contains("liveRoomCreateLauncher.launch(Intent(this, LiveRoomCreateActivity::class.java))"))
|
||||||
assertTrue(fragment.contains("fun onCreatorChannelOwnerChanged(isOwner: Boolean)"))
|
}
|
||||||
assertTrue(fragment.contains("host.onCreatorChannelLiveStartClicked()"))
|
|
||||||
|
@Test
|
||||||
|
fun `크리에이터 채널 하단 고정 UI는 BaseActivity root bottom padding과 navigation inset을 중복 적용하지 않는다`() {
|
||||||
|
val source = projectFile(
|
||||||
|
"app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivity.kt"
|
||||||
|
).readText()
|
||||||
|
|
||||||
|
assertFalse(source.contains("binding.ownerFabButton.updateLayoutParams<ConstraintLayout.LayoutParams>"))
|
||||||
|
assertFalse(source.contains("binding.ownerFabExpandedContainer.updateLayoutParams<ConstraintLayout.LayoutParams>"))
|
||||||
|
assertFalse(source.contains("binding.layoutCreatorChannelLiveOwnerCta.updateLayoutParams<ConstraintLayout.LayoutParams>"))
|
||||||
|
assertFalse(source.contains("WindowInsetsCompat.Type.navigationBars()).bottom"))
|
||||||
|
assertTrue(
|
||||||
|
source.contains(
|
||||||
|
"binding.viewPager.updatePadding(bottom = OWNER_FAB_CONTENT_BOTTOM_PADDING_DP.dpToPx().toInt())"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
assertFalse(source.contains("binding.nestedScrollView.updatePadding(bottom = liveOwnerCtaBottomPadding)"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -1644,17 +1706,16 @@ class CreatorChannelActivitySourceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `Phase 13 owner FAB source는 spring animation과 navigation inset을 적용한다`() {
|
fun `Phase 13 owner FAB source는 spring animation과 content padding을 적용한다`() {
|
||||||
val source = projectFile(
|
val source = projectFile(
|
||||||
"app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivity.kt"
|
"app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivity.kt"
|
||||||
).readText()
|
).readText()
|
||||||
|
|
||||||
assertTrue(source.contains("private var isOwnerFabAnimating: Boolean = false"))
|
assertTrue(source.contains("private var isOwnerFabAnimating: Boolean = false"))
|
||||||
assertTrue(source.contains("setupOwnerFabInsets()"))
|
assertTrue(source.contains("setupOwnerFabInsets()"))
|
||||||
assertTrue(source.contains("WindowInsetsCompat.Type.navigationBars()"))
|
assertFalse(source.contains("OWNER_FAB_BASE_MARGIN_DP.dpToPx().toInt() + navigationBottomInset"))
|
||||||
assertTrue(source.contains("OWNER_FAB_BASE_MARGIN_DP.dpToPx().toInt() + navigationBottomInset"))
|
assertFalse(source.contains("binding.ownerFabButton.updateLayoutParams<ConstraintLayout.LayoutParams>"))
|
||||||
assertTrue(source.contains("binding.ownerFabButton.updateLayoutParams<ConstraintLayout.LayoutParams>"))
|
assertFalse(source.contains("binding.ownerFabExpandedContainer.updateLayoutParams<ConstraintLayout.LayoutParams>"))
|
||||||
assertTrue(source.contains("binding.ownerFabExpandedContainer.updateLayoutParams<ConstraintLayout.LayoutParams>"))
|
|
||||||
assertTrue(
|
assertTrue(
|
||||||
source.contains(
|
source.contains(
|
||||||
"binding.viewPager.updatePadding(bottom = OWNER_FAB_CONTENT_BOTTOM_PADDING_DP.dpToPx().toInt())"
|
"binding.viewPager.updatePadding(bottom = OWNER_FAB_CONTENT_BOTTOM_PADDING_DP.dpToPx().toInt())"
|
||||||
|
|||||||
Reference in New Issue
Block a user