feat(creator): 채널 홈 Activity 진입점을 추가한다
This commit is contained in:
@@ -31,6 +31,8 @@ abstract class BaseActivity<T : ViewBinding>(
|
||||
lateinit var binding: T
|
||||
private set
|
||||
|
||||
protected open val shouldApplySystemBarTopInset: Boolean = true
|
||||
|
||||
val screenWidth: Int by lazy {
|
||||
resources.displayMetrics.widthPixels
|
||||
}
|
||||
@@ -81,7 +83,7 @@ abstract class BaseActivity<T : ViewBinding>(
|
||||
|
||||
// 루트는 좌/우/하만 처리(상단은 Toolbar에 위임). IME가 등장하면 하단 패딩을 IME 높이까지 확장
|
||||
val left = max(systemBars.left, ime.left)
|
||||
val top = systemBars.top
|
||||
val top = if (shouldApplySystemBarTopInset) systemBars.top else 0
|
||||
val right = max(systemBars.right, ime.right)
|
||||
val bottom = max(systemBars.bottom, ime.bottom)
|
||||
v.setPadding(left, top, right, bottom)
|
||||
|
||||
@@ -0,0 +1,261 @@
|
||||
package kr.co.vividnext.sodalive.v2.creator.channel
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.Typeface
|
||||
import android.view.Gravity
|
||||
import android.view.View
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.core.view.updatePadding
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.core.view.WindowCompat
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.audio_content.detail.AudioContentDetailActivity
|
||||
import kr.co.vividnext.sodalive.base.BaseActivity
|
||||
import kr.co.vividnext.sodalive.chat.talk.room.ChatRoomActivity
|
||||
import kr.co.vividnext.sodalive.common.Constants
|
||||
import kr.co.vividnext.sodalive.databinding.ActivityCreatorChannelHomeBinding
|
||||
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||
import kr.co.vividnext.sodalive.extensions.loadUrl
|
||||
import kr.co.vividnext.sodalive.extensions.moneyFormat
|
||||
import kr.co.vividnext.sodalive.live.room.detail.LiveRoomDetailFragment
|
||||
import kr.co.vividnext.sodalive.v2.common.CreatorActivityType
|
||||
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.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 CreatorChannelHomeActivity : BaseActivity<ActivityCreatorChannelHomeBinding>(
|
||||
ActivityCreatorChannelHomeBinding::inflate
|
||||
) {
|
||||
|
||||
private val viewModel: CreatorChannelHomeViewModel by viewModel()
|
||||
private val sectionAdapter = CreatorChannelHomeSectionAdapter(::onScheduleClicked)
|
||||
private var creatorId: Long = 0L
|
||||
private var currentHeader: CreatorChannelHeaderUiModel? = null
|
||||
|
||||
override val shouldApplySystemBarTopInset: Boolean = false
|
||||
|
||||
override fun setupView() {
|
||||
creatorId = intent.getLongExtra(EXTRA_CREATOR_ID, 0L)
|
||||
if (creatorId <= 0L) {
|
||||
finish()
|
||||
return
|
||||
}
|
||||
|
||||
setupRecyclerView()
|
||||
setStatusBarIconAppearance()
|
||||
setTitleBarTopInset()
|
||||
setupClickListeners()
|
||||
observeViewModel()
|
||||
viewModel.loadHome(creatorId)
|
||||
}
|
||||
|
||||
private fun setupRecyclerView() {
|
||||
binding.rvHomeSections.layoutManager = LinearLayoutManager(this)
|
||||
binding.rvHomeSections.adapter = sectionAdapter
|
||||
}
|
||||
|
||||
private fun setupClickListeners() {
|
||||
binding.ivBack.setOnClickListener { finish() }
|
||||
binding.ivMore.setOnClickListener { onMoreClicked() }
|
||||
binding.tvChatButton.setOnClickListener {
|
||||
currentHeader?.characterId?.let { characterId -> viewModel.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() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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(
|
||||
R.string.creator_channel_follower_count,
|
||||
header.followerCount.moneyFormat()
|
||||
)
|
||||
binding.ivHeaderImage.loadUrl(header.profileImageUrl) {
|
||||
placeholder(R.drawable.ic_placeholder_profile)
|
||||
error(R.drawable.ic_placeholder_profile)
|
||||
}
|
||||
updateActionButtonLayout(
|
||||
isChatVisible = header.isAiChatAvailable && header.characterId != null,
|
||||
isDmVisible = header.isDmAvailable
|
||||
)
|
||||
}
|
||||
|
||||
private fun bindTitleBar(header: CreatorChannelHeaderUiModel) {
|
||||
val titleBarState = CreatorChannelTitleBarState.from(
|
||||
isFollow = header.isFollow,
|
||||
isNotify = header.isNotify,
|
||||
isInProgress = false
|
||||
)
|
||||
binding.ivFollow.setImageResource(titleBarState.followIconResId)
|
||||
binding.layoutFollowCapsule.isEnabled = titleBarState.isActionEnabled
|
||||
binding.layoutFollowCapsule.setBackgroundResource(
|
||||
if (header.isFollow) {
|
||||
R.drawable.bg_creator_channel_following_capsule
|
||||
} else {
|
||||
R.drawable.bg_creator_channel_follow_capsule
|
||||
}
|
||||
)
|
||||
binding.layoutFollowCapsule.updateLayoutParams<LinearLayout.LayoutParams> {
|
||||
width = if (header.isFollow) 36.dpToPx().toInt() else LinearLayout.LayoutParams.WRAP_CONTENT
|
||||
}
|
||||
binding.tvFollowLabel.isVisible = !header.isFollow
|
||||
titleBarState.bellIconResId?.let {
|
||||
binding.ivBell.setImageResource(it)
|
||||
binding.ivBell.visibility = View.VISIBLE
|
||||
} ?: run {
|
||||
binding.ivBell.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindTabs(tabs: List<CreatorChannelTab>) {
|
||||
binding.tabContainer.removeAllViews()
|
||||
tabs.forEachIndexed { index, tab ->
|
||||
binding.tabContainer.addView(createTabView(tab, isSelected = index == 0))
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setTitleBarTopInset() {
|
||||
val baseTitleBarHeight = 60.dpToPx().toInt()
|
||||
ViewCompat.setOnApplyWindowInsetsListener(binding.titleBarContainer) { view, insets ->
|
||||
val topInset = insets.getInsets(WindowInsetsCompat.Type.systemBars()).top
|
||||
view.updatePadding(top = topInset)
|
||||
view.updateLayoutParams {
|
||||
height = baseTitleBarHeight + topInset
|
||||
}
|
||||
insets
|
||||
}
|
||||
}
|
||||
|
||||
private fun setStatusBarIconAppearance() {
|
||||
WindowCompat.getInsetsController(window, binding.root).isAppearanceLightStatusBars = false
|
||||
}
|
||||
|
||||
private fun updateActionButtonLayout(isChatVisible: Boolean, isDmVisible: Boolean) {
|
||||
binding.tvChatButton.isVisible = isChatVisible
|
||||
binding.tvDmButton.isVisible = isDmVisible
|
||||
(binding.tvDmButton.layoutParams as LinearLayout.LayoutParams).apply {
|
||||
marginStart = if (isChatVisible && isDmVisible) 6.dpToPx().toInt() else 0
|
||||
}.also(binding.tvDmButton::setLayoutParams)
|
||||
}
|
||||
|
||||
private fun onMoreClicked() {
|
||||
Toast.makeText(applicationContext, getString(R.string.creator_channel_more_ready), Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
private fun onScheduleClicked(schedule: CreatorChannelScheduleResponse) {
|
||||
when (schedule.type) {
|
||||
CreatorActivityType.Audio,
|
||||
CreatorActivityType.LiveReplay -> startActivity(
|
||||
Intent(this, AudioContentDetailActivity::class.java).apply {
|
||||
putExtra(Constants.EXTRA_AUDIO_CONTENT_ID, schedule.targetId)
|
||||
}
|
||||
)
|
||||
|
||||
CreatorActivityType.Live -> showLiveRoomDetail(schedule.targetId)
|
||||
|
||||
CreatorActivityType.Community -> Unit
|
||||
}
|
||||
}
|
||||
|
||||
private fun showLiveRoomDetail(roomId: Long) {
|
||||
val detailFragment = LiveRoomDetailFragment(
|
||||
roomId,
|
||||
onClickParticipant = {},
|
||||
onClickReservation = {},
|
||||
onClickModify = {},
|
||||
onClickStart = {},
|
||||
onClickCancel = {}
|
||||
)
|
||||
if (detailFragment.isAdded) return
|
||||
|
||||
detailFragment.show(supportFragmentManager, detailFragment.tag)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val EXTRA_CREATOR_ID: String = "extra_creator_id"
|
||||
|
||||
fun newIntent(context: Context, creatorId: Long): Intent {
|
||||
return Intent(context, CreatorChannelHomeActivity::class.java).apply {
|
||||
putExtra(EXTRA_CREATOR_ID, creatorId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user