|
|
|
|
@@ -3,11 +3,9 @@ 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
|
|
|
|
|
import android.view.View.MeasureSpec
|
|
|
|
|
import android.widget.LinearLayout
|
|
|
|
|
import android.widget.TextView
|
|
|
|
|
import android.widget.Toast
|
|
|
|
|
import androidx.core.view.ViewCompat
|
|
|
|
|
import androidx.core.view.WindowCompat
|
|
|
|
|
@@ -15,7 +13,9 @@ 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 androidx.recyclerview.widget.RecyclerView
|
|
|
|
|
import androidx.viewpager2.widget.ViewPager2
|
|
|
|
|
import com.google.android.material.tabs.TabLayoutMediator
|
|
|
|
|
import kr.co.vividnext.sodalive.R
|
|
|
|
|
import kr.co.vividnext.sodalive.audio_content.detail.AudioContentDetailActivity
|
|
|
|
|
import kr.co.vividnext.sodalive.base.BaseActivity
|
|
|
|
|
@@ -31,25 +31,22 @@ import kr.co.vividnext.sodalive.v2.common.CreatorActivityType
|
|
|
|
|
import kr.co.vividnext.sodalive.v2.creator.channel.data.CreatorChannelAudioContentResponse
|
|
|
|
|
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
|
|
|
|
|
import kr.co.vividnext.sodalive.v2.main.chat.dm.DmChatRoomActivity
|
|
|
|
|
import org.koin.androidx.viewmodel.ext.android.viewModel
|
|
|
|
|
|
|
|
|
|
class CreatorChannelActivity : BaseActivity<ActivityCreatorChannelBinding>(
|
|
|
|
|
ActivityCreatorChannelBinding::inflate
|
|
|
|
|
) {
|
|
|
|
|
class CreatorChannelActivity :
|
|
|
|
|
BaseActivity<ActivityCreatorChannelBinding>(ActivityCreatorChannelBinding::inflate),
|
|
|
|
|
CreatorChannelHomeFragment.Host {
|
|
|
|
|
|
|
|
|
|
private val viewModel: CreatorChannelHomeViewModel by viewModel()
|
|
|
|
|
private val sectionAdapter = CreatorChannelHomeSectionAdapter(::onScheduleClicked, ::onAudioContentClicked)
|
|
|
|
|
private var creatorId: Long = 0L
|
|
|
|
|
private var currentHeader: CreatorChannelHeaderUiModel? = null
|
|
|
|
|
private var selectedTab: CreatorChannelTab = CreatorChannelTab.Home
|
|
|
|
|
private var homeActionDelegate: CreatorChannelHomeFragment.HomeActionDelegate? = null
|
|
|
|
|
private var isFollowInProgress: Boolean = false
|
|
|
|
|
private var statusBarHeight: Int = 0
|
|
|
|
|
private var tabLayoutMediator: TabLayoutMediator? = null
|
|
|
|
|
private var pageChangeCallback: ViewPager2.OnPageChangeCallback? = null
|
|
|
|
|
private val baseTitleBarHeight: Int by lazy { 60.dpToPx().toInt() }
|
|
|
|
|
|
|
|
|
|
override val shouldApplySystemBarTopInset: Boolean = false
|
|
|
|
|
@@ -61,18 +58,11 @@ class CreatorChannelActivity : BaseActivity<ActivityCreatorChannelBinding>(
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setupRecyclerView()
|
|
|
|
|
setupTabsAndPager()
|
|
|
|
|
setStatusBarIconAppearance()
|
|
|
|
|
setTitleBarTopInset()
|
|
|
|
|
setupScrollListener()
|
|
|
|
|
setupClickListeners()
|
|
|
|
|
observeViewModel()
|
|
|
|
|
viewModel.loadHome(creatorId)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private fun setupRecyclerView() {
|
|
|
|
|
binding.rvHomeSections.layoutManager = LinearLayoutManager(this)
|
|
|
|
|
binding.rvHomeSections.adapter = sectionAdapter
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private fun setupClickListeners() {
|
|
|
|
|
@@ -81,47 +71,13 @@ class CreatorChannelActivity : BaseActivity<ActivityCreatorChannelBinding>(
|
|
|
|
|
binding.layoutFollowCapsule.setOnClickListener { onFollowActionClicked() }
|
|
|
|
|
binding.ivBell.setOnClickListener { onFollowActionClicked() }
|
|
|
|
|
binding.tvChatButton.setOnClickListener {
|
|
|
|
|
currentHeader?.characterId?.let { characterId -> viewModel.createChatRoom(characterId) }
|
|
|
|
|
currentHeader?.characterId?.let { characterId -> homeActionDelegate?.createChatRoom(characterId) }
|
|
|
|
|
}
|
|
|
|
|
binding.tvDmButton.setOnClickListener {
|
|
|
|
|
startActivity(DmChatRoomActivity.newIntentByCreatorId(this, creatorId))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private fun observeViewModel() {
|
|
|
|
|
viewModel.homeStateLiveData.observe(this) { state ->
|
|
|
|
|
when (state) {
|
|
|
|
|
is CreatorChannelHomeUiState.Content -> bindContent(state)
|
|
|
|
|
is CreatorChannelHomeUiState.Error -> Unit
|
|
|
|
|
CreatorChannelHomeUiState.Empty -> Unit
|
|
|
|
|
CreatorChannelHomeUiState.Loading -> Unit
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
viewModel.chatRoomIdLiveData.observe(this) { event ->
|
|
|
|
|
event.consume()?.let { chatRoomId ->
|
|
|
|
|
startActivity(ChatRoomActivity.newIntent(this, chatRoomId))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
viewModel.toastLiveData.observe(this) { event ->
|
|
|
|
|
event.consume()?.let {
|
|
|
|
|
val message = it.message ?: it.resId?.let(::getString)
|
|
|
|
|
message?.let { text -> Toast.makeText(applicationContext, text, Toast.LENGTH_LONG).show() }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
viewModel.isFollowInProgressLiveData.observe(this) { inProgress ->
|
|
|
|
|
isFollowInProgress = inProgress
|
|
|
|
|
currentHeader?.let(::bindTitleBar)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private fun bindContent(content: CreatorChannelHomeUiState.Content) {
|
|
|
|
|
currentHeader = content.header
|
|
|
|
|
bindHeader(content.header)
|
|
|
|
|
bindTitleBar(content.header)
|
|
|
|
|
bindTabs(content.tabs)
|
|
|
|
|
sectionAdapter.submitItems(content.sections)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private fun bindHeader(header: CreatorChannelHeaderUiModel) {
|
|
|
|
|
binding.tvNickname.text = header.nickname
|
|
|
|
|
binding.tvFollowerCount.text = getString(
|
|
|
|
|
@@ -166,54 +122,11 @@ class CreatorChannelActivity : BaseActivity<ActivityCreatorChannelBinding>(
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private fun bindTabs(tabs: List<CreatorChannelTab>) {
|
|
|
|
|
binding.tabContainer.removeAllViews()
|
|
|
|
|
tabs.forEach { tab ->
|
|
|
|
|
binding.tabContainer.addView(createTabView(tab, isSelected = tab == selectedTab))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private fun createTabView(tab: CreatorChannelTab, isSelected: Boolean): LinearLayout {
|
|
|
|
|
val tabText = TextView(this).apply {
|
|
|
|
|
text = getString(tab.labelResId)
|
|
|
|
|
gravity = Gravity.CENTER
|
|
|
|
|
setTextColor(getColor(if (isSelected) R.color.white else R.color.gray_500))
|
|
|
|
|
setTypeface(null, Typeface.NORMAL)
|
|
|
|
|
layoutParams = LinearLayout.LayoutParams(
|
|
|
|
|
LinearLayout.LayoutParams.MATCH_PARENT,
|
|
|
|
|
0,
|
|
|
|
|
1f
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
tabText.textSize = 16f
|
|
|
|
|
val indicator = View(this).apply {
|
|
|
|
|
layoutParams = LinearLayout.LayoutParams(
|
|
|
|
|
LinearLayout.LayoutParams.MATCH_PARENT,
|
|
|
|
|
3.dpToPx().toInt()
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
indicator.setBackgroundColor(getColor(R.color.soda_400))
|
|
|
|
|
indicator.isVisible = isSelected
|
|
|
|
|
return LinearLayout(this).apply {
|
|
|
|
|
orientation = LinearLayout.VERTICAL
|
|
|
|
|
gravity = Gravity.CENTER
|
|
|
|
|
layoutParams = LinearLayout.LayoutParams(
|
|
|
|
|
LinearLayout.LayoutParams.WRAP_CONTENT,
|
|
|
|
|
LinearLayout.LayoutParams.MATCH_PARENT
|
|
|
|
|
).apply {
|
|
|
|
|
width = 110.dpToPx().toInt()
|
|
|
|
|
}
|
|
|
|
|
addView(tabText)
|
|
|
|
|
addView(indicator)
|
|
|
|
|
setOnClickListener { onTabClicked(tab) }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private fun onFollowActionClicked() {
|
|
|
|
|
if (isFollowInProgress) return
|
|
|
|
|
val header = currentHeader ?: return
|
|
|
|
|
if (!header.isFollow) {
|
|
|
|
|
viewModel.follow(follow = true, notify = true)
|
|
|
|
|
homeActionDelegate?.follow(follow = true, notify = true)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -222,20 +135,13 @@ class CreatorChannelActivity : BaseActivity<ActivityCreatorChannelBinding>(
|
|
|
|
|
|
|
|
|
|
private fun showFollowNotifyFragment() {
|
|
|
|
|
val notifyFragment = CreatorFollowNotifyFragment(
|
|
|
|
|
onClickNotifyAll = { viewModel.follow(follow = true, notify = true) },
|
|
|
|
|
onClickNotifyNone = { viewModel.follow(follow = true, notify = false) },
|
|
|
|
|
onClickUnFollow = { viewModel.follow(follow = false, notify = false) }
|
|
|
|
|
onClickNotifyAll = { homeActionDelegate?.follow(follow = true, notify = true) },
|
|
|
|
|
onClickNotifyNone = { homeActionDelegate?.follow(follow = true, notify = false) },
|
|
|
|
|
onClickUnFollow = { homeActionDelegate?.follow(follow = false, notify = false) }
|
|
|
|
|
)
|
|
|
|
|
notifyFragment.show(supportFragmentManager, CreatorFollowNotifyFragment::class.java.simpleName)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private fun onTabClicked(tab: CreatorChannelTab) {
|
|
|
|
|
if (tab != CreatorChannelTab.Home) return
|
|
|
|
|
selectedTab = CreatorChannelTab.Home
|
|
|
|
|
val content = viewModel.homeStateLiveData.value as? CreatorChannelHomeUiState.Content ?: return
|
|
|
|
|
bindTabs(content.tabs)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private fun setTitleBarTopInset() {
|
|
|
|
|
ViewCompat.setOnApplyWindowInsetsListener(binding.titleBarContainer) { view, insets ->
|
|
|
|
|
val topInset = insets.getInsets(WindowInsetsCompat.Type.systemBars()).top
|
|
|
|
|
@@ -262,7 +168,7 @@ class CreatorChannelActivity : BaseActivity<ActivityCreatorChannelBinding>(
|
|
|
|
|
if (headerHeight <= 0) return
|
|
|
|
|
|
|
|
|
|
val tabTranslationY = (scrollY - (headerHeight - stickyTop)).coerceAtLeast(0)
|
|
|
|
|
binding.horizontalTabScrollView.translationY = tabTranslationY.toFloat()
|
|
|
|
|
binding.tabLayout.translationY = tabTranslationY.toFloat()
|
|
|
|
|
|
|
|
|
|
val tabBarTop = headerHeight - scrollY + tabTranslationY
|
|
|
|
|
val profileVisibleHeight = (headerHeight - scrollY).coerceIn(0, headerHeight)
|
|
|
|
|
@@ -293,6 +199,73 @@ class CreatorChannelActivity : BaseActivity<ActivityCreatorChannelBinding>(
|
|
|
|
|
Toast.makeText(applicationContext, getString(R.string.creator_channel_more_ready), Toast.LENGTH_SHORT).show()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private fun setupTabsAndPager() {
|
|
|
|
|
binding.viewPager.adapter = CreatorChannelPagerAdapter(this, creatorId)
|
|
|
|
|
binding.viewPager.isUserInputEnabled = true
|
|
|
|
|
binding.viewPager.offscreenPageLimit = CreatorChannelTab.entries.size - 1
|
|
|
|
|
tabLayoutMediator = TabLayoutMediator(binding.tabLayout, binding.viewPager) { tab, position ->
|
|
|
|
|
tab.text = getString(CreatorChannelTab.entries[position].labelResId)
|
|
|
|
|
}.also {
|
|
|
|
|
it.attach()
|
|
|
|
|
}
|
|
|
|
|
val callback = object : ViewPager2.OnPageChangeCallback() {
|
|
|
|
|
override fun onPageSelected(position: Int) {
|
|
|
|
|
updateViewPagerHeight()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
pageChangeCallback = callback
|
|
|
|
|
binding.viewPager.registerOnPageChangeCallback(callback)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override fun onCreatorChannelHeaderChanged(header: CreatorChannelHeaderUiModel) {
|
|
|
|
|
currentHeader = header
|
|
|
|
|
bindHeader(header)
|
|
|
|
|
bindTitleBar(header)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override fun onCreatorChannelFollowProgressChanged(inProgress: Boolean) {
|
|
|
|
|
isFollowInProgress = inProgress
|
|
|
|
|
currentHeader?.let(::bindTitleBar)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override fun onCreatorChannelChatRoomCreated(chatRoomId: Long) {
|
|
|
|
|
startActivity(ChatRoomActivity.newIntent(this, chatRoomId))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override fun onCreatorChannelScheduleClicked(schedule: CreatorChannelScheduleResponse) {
|
|
|
|
|
onScheduleClicked(schedule)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override fun onCreatorChannelAudioContentClicked(audioContent: CreatorChannelAudioContentResponse) {
|
|
|
|
|
onAudioContentClicked(audioContent)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override fun onCreatorChannelHomeActionDelegateReady(
|
|
|
|
|
delegate: CreatorChannelHomeFragment.HomeActionDelegate?
|
|
|
|
|
) {
|
|
|
|
|
homeActionDelegate = delegate
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override fun onCreatorChannelHomeContentChanged() {
|
|
|
|
|
updateViewPagerHeight()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private fun updateViewPagerHeight() {
|
|
|
|
|
binding.viewPager.post {
|
|
|
|
|
val recyclerView = binding.viewPager.getChildAt(0) as? RecyclerView ?: return@post
|
|
|
|
|
val currentPage = recyclerView.layoutManager?.findViewByPosition(binding.viewPager.currentItem) ?: return@post
|
|
|
|
|
val widthSpec = MeasureSpec.makeMeasureSpec(binding.viewPager.width, MeasureSpec.EXACTLY)
|
|
|
|
|
val heightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)
|
|
|
|
|
currentPage.measure(widthSpec, heightSpec)
|
|
|
|
|
val measuredHeight = currentPage.measuredHeight
|
|
|
|
|
if (measuredHeight <= 0 || binding.viewPager.layoutParams.height == measuredHeight) return@post
|
|
|
|
|
|
|
|
|
|
binding.viewPager.updateLayoutParams {
|
|
|
|
|
height = measuredHeight
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private fun onScheduleClicked(schedule: CreatorChannelScheduleResponse) {
|
|
|
|
|
when (schedule.type) {
|
|
|
|
|
CreatorActivityType.Audio,
|
|
|
|
|
@@ -330,6 +303,15 @@ class CreatorChannelActivity : BaseActivity<ActivityCreatorChannelBinding>(
|
|
|
|
|
detailFragment.show(supportFragmentManager, detailFragment.tag)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override fun onDestroy() {
|
|
|
|
|
tabLayoutMediator?.detach()
|
|
|
|
|
pageChangeCallback?.let { callback ->
|
|
|
|
|
binding.viewPager.unregisterOnPageChangeCallback(callback)
|
|
|
|
|
}
|
|
|
|
|
pageChangeCallback = null
|
|
|
|
|
super.onDestroy()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
companion object {
|
|
|
|
|
const val EXTRA_CREATOR_ID: String = "extra_creator_id"
|
|
|
|
|
|
|
|
|
|
|