fix(creator): 라이브 탭 하단 CTA와 sticky 전환을 보정한다

This commit is contained in:
2026-06-18 15:21:18 +09:00
parent a1e8f8edb3
commit f4af9868e6
3 changed files with 183 additions and 43 deletions

View File

@@ -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> {
this.bottomMargin = bottomMargin
} }
binding.ownerFabExpandedContainer.updateLayoutParams<ConstraintLayout.LayoutParams> {
this.bottomMargin = bottomMargin private fun updateLiveOwnerCtaVisibility() {
val shouldShowLiveOwnerCta = shouldShowLiveOwnerCta()
binding.layoutCreatorChannelLiveOwnerCta.isVisible = shouldShowLiveOwnerCta
binding.btnCreatorChannelLiveOwnerCta.isEnabled = true
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

View File

@@ -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"

View File

@@ -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())"