feat(creator): 채널 홈 탭 고정 스크롤을 연결한다
This commit is contained in:
@@ -2,6 +2,7 @@ package kr.co.vividnext.sodalive.v2.creator.channel
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.Color
|
||||
import android.graphics.Typeface
|
||||
import android.view.Gravity
|
||||
import android.view.View
|
||||
@@ -30,6 +31,7 @@ import kr.co.vividnext.sodalive.v2.creator.channel.data.CreatorChannelAudioConte
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.data.CreatorChannelScheduleResponse
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.model.CreatorChannelHeaderUiModel
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.model.CreatorChannelHomeUiState
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.model.CreatorChannelScrollState
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.model.CreatorChannelTab
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.model.CreatorChannelTitleBarState
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.ui.CreatorChannelHomeSectionAdapter
|
||||
@@ -44,6 +46,8 @@ class CreatorChannelHomeActivity : BaseActivity<ActivityCreatorChannelHomeBindin
|
||||
private val sectionAdapter = CreatorChannelHomeSectionAdapter(::onScheduleClicked, ::onAudioContentClicked)
|
||||
private var creatorId: Long = 0L
|
||||
private var currentHeader: CreatorChannelHeaderUiModel? = null
|
||||
private var statusBarHeight: Int = 0
|
||||
private val baseTitleBarHeight: Int by lazy { 60.dpToPx().toInt() }
|
||||
|
||||
override val shouldApplySystemBarTopInset: Boolean = false
|
||||
|
||||
@@ -57,6 +61,7 @@ class CreatorChannelHomeActivity : BaseActivity<ActivityCreatorChannelHomeBindin
|
||||
setupRecyclerView()
|
||||
setStatusBarIconAppearance()
|
||||
setTitleBarTopInset()
|
||||
setupScrollListener()
|
||||
setupClickListeners()
|
||||
observeViewModel()
|
||||
viewModel.loadHome(creatorId)
|
||||
@@ -194,15 +199,44 @@ class CreatorChannelHomeActivity : BaseActivity<ActivityCreatorChannelHomeBindin
|
||||
}
|
||||
|
||||
private fun setTitleBarTopInset() {
|
||||
val baseTitleBarHeight = 60.dpToPx().toInt()
|
||||
ViewCompat.setOnApplyWindowInsetsListener(binding.titleBarContainer) { view, insets ->
|
||||
val topInset = insets.getInsets(WindowInsetsCompat.Type.systemBars()).top
|
||||
statusBarHeight = topInset
|
||||
view.updatePadding(top = topInset)
|
||||
view.updateLayoutParams {
|
||||
height = baseTitleBarHeight + topInset
|
||||
}
|
||||
updateScrollState(binding.nestedScrollView.scrollY)
|
||||
insets
|
||||
}
|
||||
ViewCompat.requestApplyInsets(binding.titleBarContainer)
|
||||
}
|
||||
|
||||
private fun setupScrollListener() {
|
||||
binding.nestedScrollView.setOnScrollChangeListener { _, _, scrollY, _, _ ->
|
||||
updateScrollState(scrollY)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateScrollState(scrollY: Int) {
|
||||
val stickyTop = CreatorChannelScrollState.calculateStickyTop(statusBarHeight, baseTitleBarHeight)
|
||||
val headerHeight = binding.headerContainer.height
|
||||
if (headerHeight <= 0) return
|
||||
|
||||
val tabTranslationY = (scrollY - (headerHeight - stickyTop)).coerceAtLeast(0)
|
||||
binding.horizontalTabScrollView.translationY = tabTranslationY.toFloat()
|
||||
|
||||
val tabBarTop = headerHeight - scrollY + tabTranslationY
|
||||
val profileVisibleHeight = (headerHeight - scrollY).coerceIn(0, headerHeight)
|
||||
val shouldUseBlackTitleBar = CreatorChannelScrollState.shouldUseBlackTitleBar(
|
||||
titleBarBottom = stickyTop,
|
||||
tabBarTop = tabBarTop,
|
||||
profileImageVisibleHeight = profileVisibleHeight,
|
||||
profileImageTotalHeight = headerHeight
|
||||
)
|
||||
binding.titleBarContainer.setBackgroundColor(
|
||||
if (shouldUseBlackTitleBar) Color.BLACK else Color.TRANSPARENT
|
||||
)
|
||||
}
|
||||
|
||||
private fun setStatusBarIconAppearance() {
|
||||
|
||||
@@ -119,6 +119,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="52dp"
|
||||
android:background="@color/black"
|
||||
android:elevation="1dp"
|
||||
android:fillViewport="false"
|
||||
android:overScrollMode="never"
|
||||
android:scrollbars="none">
|
||||
|
||||
@@ -60,6 +60,7 @@ class CreatorChannelHomeActivitySourceTest {
|
||||
|
||||
assertTrue(layout.contains("<HorizontalScrollView"))
|
||||
assertTrue(layout.contains("@+id/horizontal_tab_scroll_view"))
|
||||
assertTrue(layout.contains("android:elevation=\"1dp\""))
|
||||
assertTrue(layout.contains("@+id/tab_container"))
|
||||
assertTrue(layout.contains("@+id/rv_home_sections"))
|
||||
assertTrue(layout.contains("android:drawableStart=\"@drawable/ic_new_talk\""))
|
||||
@@ -96,6 +97,23 @@ class CreatorChannelHomeActivitySourceTest {
|
||||
assertTrue(baseActivity.contains("if (shouldApplySystemBarTopInset) systemBars.top else 0"))
|
||||
assertTrue(source.contains("override val shouldApplySystemBarTopInset: Boolean = false"))
|
||||
assertTrue(source.contains("setTitleBarTopInset"))
|
||||
assertTrue(source.contains("ViewCompat.requestApplyInsets(binding.titleBarContainer)"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `scroll source는 tab sticky와 title bar black 전환을 연결한다`() {
|
||||
val source = projectFile(
|
||||
"app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeActivity.kt"
|
||||
).readText()
|
||||
|
||||
assertTrue(source.contains("setupScrollListener"))
|
||||
assertTrue(source.contains("binding.nestedScrollView.setOnScrollChangeListener"))
|
||||
assertTrue(source.contains("CreatorChannelScrollState.calculateStickyTop"))
|
||||
assertTrue(source.contains("binding.horizontalTabScrollView.translationY"))
|
||||
assertTrue(source.contains("CreatorChannelScrollState.shouldUseBlackTitleBar"))
|
||||
assertTrue(source.contains("binding.titleBarContainer.setBackgroundColor"))
|
||||
assertTrue(source.contains("Color.BLACK"))
|
||||
assertTrue(source.contains("Color.TRANSPARENT"))
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user