feat(ui): 캐릭터 탭
- 섹션별로 데이터가 있으면 보여주고 없으면 UI를 제거하도록 로직 추가
This commit is contained in:
@@ -1,5 +1,13 @@
|
||||
package kr.co.vividnext.sodalive.chat.character
|
||||
|
||||
import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentBannerResponse
|
||||
import kr.co.vividnext.sodalive.chat.character.curation.CurationSection
|
||||
import kr.co.vividnext.sodalive.chat.character.recent.RecentCharacter
|
||||
|
||||
data class CharacterHomeResponse(
|
||||
val id: Long
|
||||
val banners: List<GetAudioContentBannerResponse>,
|
||||
val recentCharacters: List<RecentCharacter>,
|
||||
val popularCharacters: List<Character>,
|
||||
val newCharacters: List<Character>,
|
||||
val curationSections: List<CurationSection>
|
||||
)
|
||||
|
||||
@@ -19,7 +19,6 @@ import kr.co.vividnext.sodalive.audio_content.main.AudioContentBannerType
|
||||
import kr.co.vividnext.sodalive.audio_content.main.banner.AudioContentMainBannerAdapter
|
||||
import kr.co.vividnext.sodalive.audio_content.series.detail.SeriesDetailActivity
|
||||
import kr.co.vividnext.sodalive.base.BaseFragment
|
||||
import kr.co.vividnext.sodalive.chat.character.curation.CurationSection
|
||||
import kr.co.vividnext.sodalive.chat.character.curation.CurationSectionAdapter
|
||||
import kr.co.vividnext.sodalive.chat.character.recent.RecentCharacter
|
||||
import kr.co.vividnext.sodalive.chat.character.recent.RecentCharacterAdapter
|
||||
@@ -48,7 +47,6 @@ class CharacterTabFragment : BaseFragment<FragmentCharacterTabBinding>(
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
setupView()
|
||||
loadData()
|
||||
|
||||
viewModel.fetchData()
|
||||
}
|
||||
@@ -135,6 +133,15 @@ class CharacterTabFragment : BaseFragment<FragmentCharacterTabBinding>(
|
||||
)
|
||||
.setIndicatorSliderWidth(10f.dpToPx().toInt(), 10f.dpToPx().toInt())
|
||||
.setIndicatorHeight(10f.dpToPx().toInt())
|
||||
|
||||
viewModel.bannerListLiveData.observe(viewLifecycleOwner) {
|
||||
if (it.isNotEmpty()) {
|
||||
binding.llBanner.visibility = View.VISIBLE
|
||||
binding.bannerSlider.refreshData(it)
|
||||
} else {
|
||||
binding.llBanner.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupRecentCharactersRecyclerView() {
|
||||
@@ -180,6 +187,17 @@ class CharacterTabFragment : BaseFragment<FragmentCharacterTabBinding>(
|
||||
})
|
||||
|
||||
recyclerView.adapter = recentCharacterAdapter
|
||||
|
||||
// 최근 대화한 캐릭터 LiveData 구독
|
||||
viewModel.recentCharacters.observe(viewLifecycleOwner) {
|
||||
if (it.isNotEmpty()) {
|
||||
binding.llLatestCharacters.visibility = View.VISIBLE
|
||||
recentCharacterAdapter.updateCharacters(it)
|
||||
binding.tvLatestCharacterCount.text = it.size.toString()
|
||||
} else {
|
||||
binding.llLatestCharacters.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupPopularCharactersRecyclerView() {
|
||||
@@ -230,6 +248,16 @@ class CharacterTabFragment : BaseFragment<FragmentCharacterTabBinding>(
|
||||
|
||||
binding.tvPopularCharacterAll.setOnClickListener {
|
||||
}
|
||||
|
||||
// 인기 캐릭터 LiveData 구독
|
||||
viewModel.popularCharacters.observe(viewLifecycleOwner) {
|
||||
if (it.isNotEmpty()) {
|
||||
binding.llPopularCharacters.visibility = View.VISIBLE
|
||||
popularCharacterAdapter.updateCharacters(it)
|
||||
} else {
|
||||
binding.llPopularCharacters.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupNewCharactersRecyclerView() {
|
||||
@@ -280,6 +308,16 @@ class CharacterTabFragment : BaseFragment<FragmentCharacterTabBinding>(
|
||||
|
||||
binding.tvNewCharacterAll.setOnClickListener {
|
||||
}
|
||||
|
||||
// 신규 캐릭터 LiveData 구독
|
||||
viewModel.newCharacters.observe(viewLifecycleOwner) {
|
||||
if (it.isNotEmpty()) {
|
||||
binding.llNewCharacters.visibility = View.VISIBLE
|
||||
newCharacterAdapter.updateCharacters(it)
|
||||
} else {
|
||||
binding.llNewCharacters.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupCurationSectionsRecyclerView() {
|
||||
@@ -326,79 +364,18 @@ class CharacterTabFragment : BaseFragment<FragmentCharacterTabBinding>(
|
||||
})
|
||||
|
||||
recyclerView.adapter = curationSectionAdapter
|
||||
|
||||
// 큐레이션 섹션 LiveData 구독
|
||||
viewModel.curationSections.observe(viewLifecycleOwner) {
|
||||
if (it.isNotEmpty()) {
|
||||
recyclerView.visibility = View.VISIBLE
|
||||
curationSectionAdapter.updateSections(it)
|
||||
} else {
|
||||
recyclerView.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadData() {
|
||||
// TODO: 실제 데이터 로딩 로직 구현
|
||||
loadRecentCharacters()
|
||||
loadPopularCharacters()
|
||||
loadNewCharacters()
|
||||
loadCurationSections()
|
||||
}
|
||||
|
||||
private fun loadRecentCharacters() {
|
||||
// TODO: 서버에서 최근 대화한 캐릭터 데이터 로드
|
||||
val recentCharacters = listOf(
|
||||
RecentCharacter("1", "Yubin...", ""),
|
||||
RecentCharacter("2", "Yubin...", ""),
|
||||
RecentCharacter("3", "Yubin...", ""),
|
||||
RecentCharacter("4", "Yubin...", ""),
|
||||
RecentCharacter("5", "Yubin...", "")
|
||||
)
|
||||
|
||||
recentCharacterAdapter.updateCharacters(recentCharacters)
|
||||
binding.tvLatestCharacterCount.text = recentCharacters.size.toString()
|
||||
}
|
||||
|
||||
private fun loadPopularCharacters() {
|
||||
// TODO: 서버에서 인기 캐릭터 데이터 로드
|
||||
val popularCharacters = listOf(
|
||||
Character("1", "캐릭터 이름", "캐릭터 한줄 소개인데 2줄까", ""),
|
||||
Character("2", "캐릭터 이름", "캐릭터 한줄 소개인데 2줄까", ""),
|
||||
Character("3", "캐릭터 이름", "#태그#태그#태그", ""),
|
||||
Character("4", "캐릭터 이름", "캐릭터 한줄 소개인데 2줄까", ""),
|
||||
Character("5", "캐릭터 이름", "캐릭터 한줄 소개인데 2줄까", "")
|
||||
)
|
||||
|
||||
popularCharacterAdapter.updateCharacters(popularCharacters)
|
||||
}
|
||||
|
||||
private fun loadNewCharacters() {
|
||||
// TODO: 서버에서 신규 캐릭터 데이터 로드
|
||||
val newCharacters = listOf(
|
||||
Character("1", "캐릭터 이름", "캐릭터 한줄 소개인데 2줄까", ""),
|
||||
Character("2", "하이퍼나이프", "캐릭터 한줄 소개인데 2줄까", ""),
|
||||
Character("3", "내일", "#태그#태그", "")
|
||||
)
|
||||
|
||||
newCharacterAdapter.updateCharacters(newCharacters)
|
||||
}
|
||||
|
||||
private fun loadCurationSections() {
|
||||
// TODO: 서버에서 큐레이션 섹션 데이터 로드
|
||||
val curationSections = listOf(
|
||||
CurationSection(
|
||||
"1",
|
||||
"큐레이션",
|
||||
listOf(
|
||||
Character("1", "캐릭터 이름", "캐릭터 한줄 소개인데 2줄까", ""),
|
||||
Character("2", "하이퍼나이프", "캐릭터 한줄 소개인데 2줄까", ""),
|
||||
Character("3", "내일", "#태그#태그", "")
|
||||
)
|
||||
),
|
||||
CurationSection(
|
||||
"2",
|
||||
"큐레이션",
|
||||
listOf(
|
||||
Character("4", "캐릭터 이름", "캐릭터 한줄 소개인데 2줄까", ""),
|
||||
Character("5", "하이퍼나이프", "캐릭터 한줄 소개인데 2줄까", ""),
|
||||
Character("6", "내일", "#태그#태그", "")
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
curationSectionAdapter.updateSections(curationSections)
|
||||
}
|
||||
|
||||
private fun onRecentCharacterClick(character: RecentCharacter) {
|
||||
// TODO: 최근 대화한 캐릭터 클릭 처리
|
||||
|
||||
@@ -5,7 +5,10 @@ import androidx.lifecycle.MutableLiveData
|
||||
import com.orhanobut.logger.Logger
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentBannerResponse
|
||||
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||
import kr.co.vividnext.sodalive.chat.character.curation.CurationSection
|
||||
import kr.co.vividnext.sodalive.chat.character.recent.RecentCharacter
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
|
||||
class CharacterTabViewModel(
|
||||
@@ -19,6 +22,30 @@ class CharacterTabViewModel(
|
||||
val toastLiveData: LiveData<String?>
|
||||
get() = _toastLiveData
|
||||
|
||||
private var _bannerListLiveData = MutableLiveData<List<GetAudioContentBannerResponse>>()
|
||||
val bannerListLiveData: LiveData<List<GetAudioContentBannerResponse>>
|
||||
get() = _bannerListLiveData
|
||||
|
||||
// 최근 대화한 캐릭터 LiveData
|
||||
private val _recentCharacters = MutableLiveData<List<RecentCharacter>>(emptyList())
|
||||
val recentCharacters: LiveData<List<RecentCharacter>>
|
||||
get() = _recentCharacters
|
||||
|
||||
// 인기 캐릭터 LiveData
|
||||
private val _popularCharacters = MutableLiveData<List<Character>>(emptyList())
|
||||
val popularCharacters: LiveData<List<Character>>
|
||||
get() = _popularCharacters
|
||||
|
||||
// 신규 캐릭터 LiveData
|
||||
private val _newCharacters = MutableLiveData<List<Character>>(emptyList())
|
||||
val newCharacters: LiveData<List<Character>>
|
||||
get() = _newCharacters
|
||||
|
||||
// 큐레이션 섹션 LiveData
|
||||
private val _curationSections = MutableLiveData<List<CurationSection>>(emptyList())
|
||||
val curationSections: LiveData<List<CurationSection>>
|
||||
get() = _curationSections
|
||||
|
||||
fun fetchData() {
|
||||
_isLoading.value = true
|
||||
|
||||
@@ -31,7 +58,11 @@ class CharacterTabViewModel(
|
||||
_isLoading.value = false
|
||||
val data = it.data
|
||||
if (it.success && data != null) {
|
||||
|
||||
_bannerListLiveData.value = data.banners
|
||||
_recentCharacters.value = data.recentCharacters
|
||||
_popularCharacters.value = data.popularCharacters
|
||||
_newCharacters.value = data.newCharacters
|
||||
_curationSections.value = data.curationSections
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
|
||||
<!-- 최근 대화한 캐릭터 섹션 -->
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_latest_characters"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="48dp"
|
||||
@@ -83,6 +84,7 @@
|
||||
|
||||
<!-- 인기 캐릭터 섹션 -->
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_popular_characters"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="48dp"
|
||||
@@ -127,6 +129,7 @@
|
||||
|
||||
<!-- 신규 캐릭터 섹션 -->
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_new_characters"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="48dp"
|
||||
|
||||
Reference in New Issue
Block a user