From 93fc837b7a82a039be55de3ed5004748fd996183 Mon Sep 17 00:00:00 2001 From: klaus Date: Mon, 4 Aug 2025 23:38:51 +0900 Subject: [PATCH] =?UTF-8?q?feat(ui):=20=EC=BA=90=EB=A6=AD=ED=84=B0=20?= =?UTF-8?q?=ED=83=AD=20-=20=EC=84=B9=EC=85=98=EB=B3=84=EB=A1=9C=20?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=84=B0=EA=B0=80=20=EC=9E=88=EC=9C=BC?= =?UTF-8?q?=EB=A9=B4=20=EB=B3=B4=EC=97=AC=EC=A3=BC=EA=B3=A0=20=EC=97=86?= =?UTF-8?q?=EC=9C=BC=EB=A9=B4=20UI=EB=A5=BC=20=EC=A0=9C=EA=B1=B0=ED=95=98?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chat/character/CharacterHomeResponse.kt | 10 +- .../chat/character/CharacterTabFragment.kt | 123 +++++++----------- .../chat/character/CharacterTabViewModel.kt | 33 ++++- .../res/layout/fragment_character_tab.xml | 3 + 4 files changed, 94 insertions(+), 75 deletions(-) diff --git a/app/src/main/java/kr/co/vividnext/sodalive/chat/character/CharacterHomeResponse.kt b/app/src/main/java/kr/co/vividnext/sodalive/chat/character/CharacterHomeResponse.kt index d0ac209b..ca382447 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/chat/character/CharacterHomeResponse.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/chat/character/CharacterHomeResponse.kt @@ -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, + val recentCharacters: List, + val popularCharacters: List, + val newCharacters: List, + val curationSections: List ) diff --git a/app/src/main/java/kr/co/vividnext/sodalive/chat/character/CharacterTabFragment.kt b/app/src/main/java/kr/co/vividnext/sodalive/chat/character/CharacterTabFragment.kt index 2747ef92..d54d38cb 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/chat/character/CharacterTabFragment.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/chat/character/CharacterTabFragment.kt @@ -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( override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) setupView() - loadData() viewModel.fetchData() } @@ -135,6 +133,15 @@ class CharacterTabFragment : BaseFragment( ) .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( }) 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( 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( 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( }) 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: 최근 대화한 캐릭터 클릭 처리 diff --git a/app/src/main/java/kr/co/vividnext/sodalive/chat/character/CharacterTabViewModel.kt b/app/src/main/java/kr/co/vividnext/sodalive/chat/character/CharacterTabViewModel.kt index 2f0e789b..4102106a 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/chat/character/CharacterTabViewModel.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/chat/character/CharacterTabViewModel.kt @@ -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 get() = _toastLiveData + private var _bannerListLiveData = MutableLiveData>() + val bannerListLiveData: LiveData> + get() = _bannerListLiveData + + // 최근 대화한 캐릭터 LiveData + private val _recentCharacters = MutableLiveData>(emptyList()) + val recentCharacters: LiveData> + get() = _recentCharacters + + // 인기 캐릭터 LiveData + private val _popularCharacters = MutableLiveData>(emptyList()) + val popularCharacters: LiveData> + get() = _popularCharacters + + // 신규 캐릭터 LiveData + private val _newCharacters = MutableLiveData>(emptyList()) + val newCharacters: LiveData> + get() = _newCharacters + + // 큐레이션 섹션 LiveData + private val _curationSections = MutableLiveData>(emptyList()) + val curationSections: LiveData> + 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 } }, { diff --git a/app/src/main/res/layout/fragment_character_tab.xml b/app/src/main/res/layout/fragment_character_tab.xml index fab3cba3..aa4c184a 100644 --- a/app/src/main/res/layout/fragment_character_tab.xml +++ b/app/src/main/res/layout/fragment_character_tab.xml @@ -37,6 +37,7 @@