feat(home): 팔로잉 탭 화면을 연결한다
This commit is contained in:
@@ -14,7 +14,20 @@ import kr.co.vividnext.sodalive.common.formatUtcRelativeTimeText
|
||||
import kr.co.vividnext.sodalive.databinding.FragmentV2MainHomeBinding
|
||||
import kr.co.vividnext.sodalive.databinding.ViewSectionTitleBinding
|
||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.all.CreatorCommunityAllActivity
|
||||
import kr.co.vividnext.sodalive.chat.talk.room.ChatRoomActivity
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivity
|
||||
import kr.co.vividnext.sodalive.v2.main.chat.dm.DmChatRoomActivity
|
||||
import kr.co.vividnext.sodalive.v2.main.chat.model.ChatRoomListUiItem
|
||||
import kr.co.vividnext.sodalive.v2.main.chat.model.ChatRoomType
|
||||
import kr.co.vividnext.sodalive.v2.main.home.model.HomeFollowingChatSection
|
||||
import kr.co.vividnext.sodalive.v2.main.home.model.HomeFollowingCreatorSection
|
||||
import kr.co.vividnext.sodalive.v2.main.home.model.HomeFollowingLiveSection
|
||||
import kr.co.vividnext.sodalive.v2.main.home.model.HomeFollowingLiveUiItem
|
||||
import kr.co.vividnext.sodalive.v2.main.home.model.HomeFollowingNewsSection
|
||||
import kr.co.vividnext.sodalive.v2.main.home.model.HomeFollowingNewsUiItem
|
||||
import kr.co.vividnext.sodalive.v2.main.home.model.HomeFollowingScheduleSection
|
||||
import kr.co.vividnext.sodalive.v2.main.home.model.HomeFollowingScheduleUiItem
|
||||
import kr.co.vividnext.sodalive.v2.main.home.model.HomeFollowingUiState
|
||||
import kr.co.vividnext.sodalive.v2.main.home.model.HomeCreatorRankingUiState
|
||||
import kr.co.vividnext.sodalive.v2.main.home.model.HomeRecommendationAiCharacterSection
|
||||
import kr.co.vividnext.sodalive.v2.main.home.model.HomeRecommendationAiCharacterUiModel
|
||||
@@ -45,6 +58,11 @@ import kr.co.vividnext.sodalive.v2.main.home.ui.HomeBannerBinder
|
||||
import kr.co.vividnext.sodalive.v2.main.home.ui.HomeBusinessInfoBinder
|
||||
import kr.co.vividnext.sodalive.v2.main.home.ui.HomeCheerCreatorAdapter
|
||||
import kr.co.vividnext.sodalive.v2.main.home.ui.HomeFirstAudioAdapter
|
||||
import kr.co.vividnext.sodalive.v2.main.home.ui.HomeFollowingChatAdapter
|
||||
import kr.co.vividnext.sodalive.v2.main.home.ui.HomeFollowingCreatorAdapter
|
||||
import kr.co.vividnext.sodalive.v2.main.home.ui.HomeFollowingLiveAdapter
|
||||
import kr.co.vividnext.sodalive.v2.main.home.ui.HomeFollowingNewsAdapter
|
||||
import kr.co.vividnext.sodalive.v2.main.home.ui.HomeFollowingScheduleAdapter
|
||||
import kr.co.vividnext.sodalive.v2.main.home.ui.HomeGenreCreatorAdapter
|
||||
import kr.co.vividnext.sodalive.v2.main.home.ui.HomeLiveAdapter
|
||||
import kr.co.vividnext.sodalive.v2.main.home.ui.HomePopularCommunityAdapter
|
||||
@@ -60,6 +78,7 @@ class HomeMainFragment : BaseFragment<FragmentV2MainHomeBinding>(
|
||||
) {
|
||||
private val homeRecommendationViewModel: HomeRecommendationViewModel by viewModel()
|
||||
private val homeCreatorRankingViewModel: HomeCreatorRankingViewModel by viewModel()
|
||||
private val homeFollowingViewModel: HomeFollowingViewModel by viewModel()
|
||||
private val loadingDialog: LoadingDialog by lazy { LoadingDialog(requireActivity(), layoutInflater) }
|
||||
private val liveAdapter = HomeLiveAdapter()
|
||||
private val recentActivityCreatorAdapter = HomeRecentActivityCreatorAdapter { onRecentActivityClick(it) }
|
||||
@@ -76,10 +95,16 @@ class HomeMainFragment : BaseFragment<FragmentV2MainHomeBinding>(
|
||||
)
|
||||
private val popularCommunityAdapter = HomePopularCommunityAdapter { openPopularCommunityPost(it) }
|
||||
private val creatorRankingAdapter = CreatorRankingAdapter { openCreatorRankingProfile(it) }
|
||||
private val followingCreatorAdapter = HomeFollowingCreatorAdapter { openCreatorProfile(it.creatorId) }
|
||||
private val followingLiveAdapter = HomeFollowingLiveAdapter { onFollowingLiveClick(it) }
|
||||
private val followingChatAdapter = HomeFollowingChatAdapter { openFollowingChat(it) }
|
||||
private val followingScheduleAdapter = HomeFollowingScheduleAdapter { onFollowingScheduleClick(it) }
|
||||
private val followingNewsAdapter = HomeFollowingNewsAdapter { onFollowingNewsClick(it) }
|
||||
private var bannerBinder: HomeBannerBinder? = null
|
||||
private var onGenreFollowAllClick: (List<Long>) -> Unit = {}
|
||||
private var onCheerFollowAllClick: (List<Long>) -> Unit = {}
|
||||
private var hasLoadedCreatorRankings = false
|
||||
private var hasLoadedFollowing = false
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
@@ -97,9 +122,11 @@ class HomeMainFragment : BaseFragment<FragmentV2MainHomeBinding>(
|
||||
setUpSectionTitles()
|
||||
setUpRecommendationAdapters()
|
||||
setUpCreatorRankingAdapter()
|
||||
setUpFollowingAdapters()
|
||||
setUpBusinessInfo()
|
||||
bindHomeRecommendationObservers()
|
||||
bindHomeCreatorRankingObservers()
|
||||
bindHomeFollowingObservers()
|
||||
homeRecommendationViewModel.loadRecommendations()
|
||||
}
|
||||
|
||||
@@ -159,6 +186,29 @@ class HomeMainFragment : BaseFragment<FragmentV2MainHomeBinding>(
|
||||
}
|
||||
}
|
||||
|
||||
private fun setUpFollowingAdapters() {
|
||||
binding.rvHomeFollowingCreators.apply {
|
||||
layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false)
|
||||
adapter = followingCreatorAdapter
|
||||
}
|
||||
binding.rvHomeFollowingOnAirLives.apply {
|
||||
layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false)
|
||||
adapter = followingLiveAdapter
|
||||
}
|
||||
binding.rvHomeFollowingRecentChats.apply {
|
||||
layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false)
|
||||
adapter = followingChatAdapter
|
||||
}
|
||||
binding.rvHomeFollowingMonthlySchedules.apply {
|
||||
layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false)
|
||||
adapter = followingScheduleAdapter
|
||||
}
|
||||
binding.rvHomeFollowingRecentNews.apply {
|
||||
layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false)
|
||||
adapter = followingNewsAdapter
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindHomeCreatorRankingObservers() {
|
||||
homeCreatorRankingViewModel.rankingStateLiveData.observe(viewLifecycleOwner) { state ->
|
||||
when (state) {
|
||||
@@ -186,18 +236,51 @@ class HomeMainFragment : BaseFragment<FragmentV2MainHomeBinding>(
|
||||
HOME_TAB_RECOMMENDATION -> {
|
||||
binding.nsvHomeRecommendationContent.visibility = View.VISIBLE
|
||||
binding.rvHomeCreatorRankings.visibility = View.GONE
|
||||
binding.nsvHomeFollowingContent.visibility = View.GONE
|
||||
}
|
||||
|
||||
HOME_TAB_RANKING -> {
|
||||
binding.nsvHomeRecommendationContent.visibility = View.GONE
|
||||
binding.rvHomeCreatorRankings.visibility = View.VISIBLE
|
||||
binding.nsvHomeFollowingContent.visibility = View.GONE
|
||||
if (!hasLoadedCreatorRankings) {
|
||||
hasLoadedCreatorRankings = true
|
||||
homeCreatorRankingViewModel.loadCreatorRankings()
|
||||
}
|
||||
}
|
||||
|
||||
HOME_TAB_FOLLOWING -> Unit
|
||||
HOME_TAB_FOLLOWING -> {
|
||||
binding.nsvHomeFollowingContent.visibility = View.VISIBLE
|
||||
binding.nsvHomeRecommendationContent.visibility = View.GONE
|
||||
binding.rvHomeCreatorRankings.visibility = View.GONE
|
||||
if (!hasLoadedFollowing) {
|
||||
hasLoadedFollowing = true
|
||||
homeFollowingViewModel.loadFollowing()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindHomeFollowingObservers() {
|
||||
homeFollowingViewModel.followingStateLiveData.observe(viewLifecycleOwner) { state ->
|
||||
when (state) {
|
||||
is HomeFollowingUiState.Content -> bindHomeFollowingContent(state)
|
||||
HomeFollowingUiState.LoginRequired,
|
||||
HomeFollowingUiState.Empty,
|
||||
is HomeFollowingUiState.Error -> bindHomeFollowingEmpty()
|
||||
|
||||
HomeFollowingUiState.Loading -> Unit
|
||||
}
|
||||
}
|
||||
homeFollowingViewModel.isLoading.observe(viewLifecycleOwner) { isLoading ->
|
||||
if (isLoading) {
|
||||
loadingDialog.show(screenWidth)
|
||||
} else {
|
||||
loadingDialog.dismiss()
|
||||
}
|
||||
}
|
||||
homeFollowingViewModel.toastLiveData.observe(viewLifecycleOwner) { toastMessage ->
|
||||
toastMessage?.let(::showToast)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,6 +318,52 @@ class HomeMainFragment : BaseFragment<FragmentV2MainHomeBinding>(
|
||||
bindPopularCommunitySection(content.popularCommunityPosts)
|
||||
}
|
||||
|
||||
private fun bindHomeFollowingContent(content: HomeFollowingUiState.Content) {
|
||||
bindFollowingCreatorSection(content.followingCreators)
|
||||
bindFollowingLiveSection(content.onAirLives)
|
||||
bindFollowingChatSection(content.recentChats)
|
||||
bindFollowingScheduleSection(content.monthlySchedules)
|
||||
bindFollowingNewsSection(content.recentNews)
|
||||
}
|
||||
|
||||
private fun bindHomeFollowingEmpty() {
|
||||
binding.llHomeFollowingCreatorsSection.visibility = View.GONE
|
||||
binding.llHomeFollowingOnAirSection.visibility = View.GONE
|
||||
binding.llHomeFollowingRecentChatsSection.visibility = View.GONE
|
||||
binding.llHomeFollowingMonthlySchedulesSection.visibility = View.GONE
|
||||
binding.llHomeFollowingRecentNewsSection.visibility = View.GONE
|
||||
followingCreatorAdapter.submitItems(emptyList())
|
||||
followingLiveAdapter.submitItems(emptyList())
|
||||
followingChatAdapter.submitItems(emptyList())
|
||||
followingScheduleAdapter.submitItems(emptyList())
|
||||
followingNewsAdapter.submitItems(emptyList())
|
||||
}
|
||||
|
||||
private fun bindFollowingCreatorSection(section: HomeFollowingCreatorSection) {
|
||||
binding.llHomeFollowingCreatorsSection.visibility = section.items.toSectionVisibility()
|
||||
followingCreatorAdapter.submitItems(section.items)
|
||||
}
|
||||
|
||||
private fun bindFollowingLiveSection(section: HomeFollowingLiveSection) {
|
||||
binding.llHomeFollowingOnAirSection.visibility = section.items.toSectionVisibility()
|
||||
followingLiveAdapter.submitItems(section.items)
|
||||
}
|
||||
|
||||
private fun bindFollowingChatSection(section: HomeFollowingChatSection) {
|
||||
binding.llHomeFollowingRecentChatsSection.visibility = section.items.toSectionVisibility()
|
||||
followingChatAdapter.submitItems(section.items)
|
||||
}
|
||||
|
||||
private fun bindFollowingScheduleSection(section: HomeFollowingScheduleSection) {
|
||||
binding.llHomeFollowingMonthlySchedulesSection.visibility = section.items.toSectionVisibility()
|
||||
followingScheduleAdapter.submitItems(section.items)
|
||||
}
|
||||
|
||||
private fun bindFollowingNewsSection(section: HomeFollowingNewsSection) {
|
||||
binding.llHomeFollowingRecentNewsSection.visibility = section.items.toSectionVisibility()
|
||||
followingNewsAdapter.submitItems(section.items)
|
||||
}
|
||||
|
||||
private fun bindLiveSection(section: HomeRecommendationLiveSection) {
|
||||
binding.llHomeLiveSection.visibility = section.items.toSectionVisibility()
|
||||
liveAdapter.submitItems(section.items)
|
||||
@@ -319,6 +448,41 @@ class HomeMainFragment : BaseFragment<FragmentV2MainHomeBinding>(
|
||||
binding.viewHomePopularCommunityTitle.setTitle(
|
||||
R.string.home_recommendation_section_popular_community_posts
|
||||
)
|
||||
binding.viewHomeFollowingCreatorsTitle.setTitle(
|
||||
R.string.screen_home_following_creators_title,
|
||||
showMore = true
|
||||
)
|
||||
binding.viewHomeFollowingOnAirTitle.setTitle(
|
||||
R.string.screen_home_following_on_air,
|
||||
showMore = true
|
||||
)
|
||||
binding.viewHomeFollowingRecentChatsTitle.setTitle(
|
||||
R.string.screen_home_following_recent_chats_title,
|
||||
showMore = true
|
||||
)
|
||||
binding.viewHomeFollowingMonthlySchedulesTitle.setTitle(
|
||||
R.string.screen_home_following_monthly_schedules_title,
|
||||
showMore = true
|
||||
)
|
||||
binding.viewHomeFollowingRecentNewsTitle.setTitle(
|
||||
R.string.screen_home_following_recent_news_title,
|
||||
showMore = true
|
||||
)
|
||||
binding.viewHomeFollowingCreatorsTitle.ivSectionTitleChevron.setOnClickListener {
|
||||
onFollowingSectionMoreClick(HomeFollowingSection.CREATORS)
|
||||
}
|
||||
binding.viewHomeFollowingOnAirTitle.ivSectionTitleChevron.setOnClickListener {
|
||||
onFollowingSectionMoreClick(HomeFollowingSection.ON_AIR)
|
||||
}
|
||||
binding.viewHomeFollowingRecentChatsTitle.ivSectionTitleChevron.setOnClickListener {
|
||||
onFollowingSectionMoreClick(HomeFollowingSection.RECENT_CHATS)
|
||||
}
|
||||
binding.viewHomeFollowingMonthlySchedulesTitle.ivSectionTitleChevron.setOnClickListener {
|
||||
onFollowingSectionMoreClick(HomeFollowingSection.MONTHLY_SCHEDULES)
|
||||
}
|
||||
binding.viewHomeFollowingRecentNewsTitle.ivSectionTitleChevron.setOnClickListener {
|
||||
onFollowingSectionMoreClick(HomeFollowingSection.RECENT_NEWS)
|
||||
}
|
||||
}
|
||||
|
||||
private fun ViewSectionTitleBinding.setTitle(
|
||||
@@ -331,6 +495,21 @@ class HomeMainFragment : BaseFragment<FragmentV2MainHomeBinding>(
|
||||
|
||||
private fun onLiveClick(item: HomeRecommendationLiveUiModel) = Unit
|
||||
|
||||
private fun onFollowingSectionMoreClick(section: HomeFollowingSection) = Unit
|
||||
|
||||
private fun onFollowingLiveClick(item: HomeFollowingLiveUiItem) = Unit
|
||||
|
||||
private fun onFollowingScheduleClick(item: HomeFollowingScheduleUiItem) = Unit
|
||||
|
||||
private fun onFollowingNewsClick(item: HomeFollowingNewsUiItem) = Unit
|
||||
|
||||
private fun openFollowingChat(item: ChatRoomListUiItem) {
|
||||
when (item.chatType) {
|
||||
ChatRoomType.AI -> startActivity(ChatRoomActivity.newIntent(requireContext(), item.roomId))
|
||||
ChatRoomType.DM -> startActivity(DmChatRoomActivity.newIntentByRoomId(requireContext(), item.roomId))
|
||||
}
|
||||
}
|
||||
|
||||
private fun onBannerClick(item: HomeRecommendationBannerUiModel) {
|
||||
val route = item.toHomeRecommendationBannerRoute() ?: return
|
||||
startActivity(route.toHomeRecommendationBannerIntent(requireContext()))
|
||||
@@ -419,3 +598,11 @@ class HomeMainFragment : BaseFragment<FragmentV2MainHomeBinding>(
|
||||
const val SECTION_KEY_GENRE_CREATORS = "genreCreators"
|
||||
}
|
||||
}
|
||||
|
||||
enum class HomeFollowingSection {
|
||||
CREATORS,
|
||||
ON_AIR,
|
||||
RECENT_CHATS,
|
||||
MONTHLY_SCHEDULES,
|
||||
RECENT_NEWS
|
||||
}
|
||||
|
||||
@@ -239,6 +239,141 @@
|
||||
</LinearLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:id="@+id/nsv_home_following_content"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:fillViewport="true"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/text_tab_bar_home">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_home_following_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="@dimen/spacing_28">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_home_following_creators_section"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/spacing_12"
|
||||
android:orientation="vertical">
|
||||
|
||||
<include
|
||||
android:id="@+id/view_home_following_creators_title"
|
||||
layout="@layout/view_section_title" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rv_home_following_creators"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/spacing_14"
|
||||
android:clipToPadding="false"
|
||||
android:orientation="horizontal"
|
||||
android:paddingHorizontal="@dimen/spacing_14"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
tools:listitem="@layout/item_home_following_creator" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_home_following_on_air_section"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/spacing_48"
|
||||
android:orientation="vertical">
|
||||
|
||||
<include
|
||||
android:id="@+id/view_home_following_on_air_title"
|
||||
layout="@layout/view_section_title" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rv_home_following_on_air_lives"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/spacing_14"
|
||||
android:clipToPadding="false"
|
||||
android:orientation="horizontal"
|
||||
android:paddingHorizontal="@dimen/spacing_14"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
tools:listitem="@layout/item_home_following_live" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_home_following_recent_chats_section"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/spacing_48"
|
||||
android:orientation="vertical">
|
||||
|
||||
<include
|
||||
android:id="@+id/view_home_following_recent_chats_title"
|
||||
layout="@layout/view_section_title" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rv_home_following_recent_chats"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/spacing_14"
|
||||
android:clipToPadding="false"
|
||||
android:orientation="vertical"
|
||||
android:paddingHorizontal="@dimen/spacing_14"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
tools:listitem="@layout/item_home_following_chat" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_home_following_monthly_schedules_section"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/spacing_48"
|
||||
android:orientation="vertical">
|
||||
|
||||
<include
|
||||
android:id="@+id/view_home_following_monthly_schedules_title"
|
||||
layout="@layout/view_section_title" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rv_home_following_monthly_schedules"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/spacing_14"
|
||||
android:clipToPadding="false"
|
||||
android:orientation="vertical"
|
||||
android:paddingHorizontal="@dimen/spacing_14"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
tools:listitem="@layout/item_home_following_schedule" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_home_following_recent_news_section"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/spacing_48"
|
||||
android:orientation="vertical">
|
||||
|
||||
<include
|
||||
android:id="@+id/view_home_following_recent_news_title"
|
||||
layout="@layout/view_section_title" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rv_home_following_recent_news"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/spacing_14"
|
||||
android:clipToPadding="false"
|
||||
android:orientation="vertical"
|
||||
android:paddingHorizontal="@dimen/spacing_14"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
tools:listitem="@layout/item_home_following_news_content" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rv_home_creator_rankings"
|
||||
android:layout_width="0dp"
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
package kr.co.vividnext.sodalive.v2.main.home
|
||||
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
import java.io.File
|
||||
|
||||
class HomeFollowingFragmentSourceTest {
|
||||
|
||||
@Test
|
||||
fun `home layout exposes following content and section recycler ids`() {
|
||||
val layout = homeMainLayoutSource()
|
||||
|
||||
assertTrue(layout.contains("@+id/nsv_home_following_content"))
|
||||
assertTrue(layout.contains("@+id/rv_home_following_creators"))
|
||||
assertTrue(layout.contains("@+id/rv_home_following_on_air_lives"))
|
||||
assertTrue(layout.contains("@+id/rv_home_following_recent_chats"))
|
||||
assertTrue(layout.contains("@+id/rv_home_following_monthly_schedules"))
|
||||
assertTrue(layout.contains("@+id/rv_home_following_recent_news"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `home main fragment injects following viewmodel and wires adapters`() {
|
||||
val source = homeMainFragmentSource()
|
||||
|
||||
assertTrue(source.contains("HomeFollowingViewModel"))
|
||||
assertTrue(source.contains("private val homeFollowingViewModel: HomeFollowingViewModel by viewModel()"))
|
||||
assertTrue(source.contains("import kr.co.vividnext.sodalive.v2.main.home.ui.HomeFollowingCreatorAdapter"))
|
||||
assertTrue(source.contains("import kr.co.vividnext.sodalive.v2.main.home.ui.HomeFollowingLiveAdapter"))
|
||||
assertTrue(source.contains("import kr.co.vividnext.sodalive.v2.main.home.ui.HomeFollowingChatAdapter"))
|
||||
assertTrue(source.contains("import kr.co.vividnext.sodalive.v2.main.home.ui.HomeFollowingScheduleAdapter"))
|
||||
assertTrue(source.contains("import kr.co.vividnext.sodalive.v2.main.home.ui.HomeFollowingNewsAdapter"))
|
||||
assertTrue(source.contains("HomeFollowingCreatorAdapter"))
|
||||
assertTrue(source.contains("HomeFollowingLiveAdapter"))
|
||||
assertTrue(source.contains("HomeFollowingChatAdapter"))
|
||||
assertTrue(source.contains("HomeFollowingScheduleAdapter"))
|
||||
assertTrue(source.contains("HomeFollowingNewsAdapter"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `following tab branch shows following content and hides other home surfaces`() {
|
||||
val source = homeMainFragmentSource()
|
||||
val branch = source.substringAfter("HOME_TAB_FOLLOWING ->")
|
||||
.substringBefore("}\n }")
|
||||
|
||||
assertTrue(branch.contains("binding.nsvHomeFollowingContent.visibility = View.VISIBLE"))
|
||||
assertTrue(branch.contains("binding.nsvHomeRecommendationContent.visibility = View.GONE"))
|
||||
assertTrue(branch.contains("binding.rvHomeCreatorRankings.visibility = View.GONE"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `following tab loads following content only once`() {
|
||||
val source = homeMainFragmentSource()
|
||||
|
||||
assertTrue(source.contains("private var hasLoadedFollowing = false"))
|
||||
assertTrue(source.contains("if (!hasLoadedFollowing)"))
|
||||
assertTrue(source.contains("hasLoadedFollowing = true"))
|
||||
assertTrue(source.contains("homeFollowingViewModel.loadFollowing()"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `following section chevrons call callback without starting activity`() {
|
||||
val source = homeMainFragmentSource()
|
||||
val callback = source.substringAfter("private fun onFollowingSectionMoreClick")
|
||||
.substringBefore("\n private fun")
|
||||
|
||||
assertTrue(source.contains("onFollowingSectionMoreClick("))
|
||||
assertTrue(source.contains("binding.viewHomeFollowingCreatorsTitle"))
|
||||
assertTrue(source.contains("binding.viewHomeFollowingOnAirTitle"))
|
||||
assertTrue(source.contains("binding.viewHomeFollowingRecentChatsTitle"))
|
||||
assertTrue(source.contains("binding.viewHomeFollowingMonthlySchedulesTitle"))
|
||||
assertTrue(source.contains("binding.viewHomeFollowingRecentNewsTitle"))
|
||||
assertTrue(source.contains("setOnClickListener"))
|
||||
assertTrue(source.contains("onFollowingSectionMoreClick(HomeFollowingSection."))
|
||||
assertFalse(callback.contains("startActivity"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `following state binding clears or binds each following section`() {
|
||||
val source = homeMainFragmentSource()
|
||||
|
||||
assertTrue(source.contains("followingStateLiveData.observe(viewLifecycleOwner)"))
|
||||
assertTrue(source.contains("is HomeFollowingUiState.Content -> bindHomeFollowingContent(state)"))
|
||||
assertTrue(source.contains("HomeFollowingUiState.LoginRequired,"))
|
||||
assertTrue(source.contains("HomeFollowingUiState.Empty,"))
|
||||
assertTrue(source.contains("is HomeFollowingUiState.Error -> bindHomeFollowingEmpty()"))
|
||||
assertTrue(source.contains("followingCreatorAdapter.submitItems(emptyList())"))
|
||||
assertTrue(source.contains("followingLiveAdapter.submitItems(emptyList())"))
|
||||
assertTrue(source.contains("followingChatAdapter.submitItems(emptyList())"))
|
||||
assertTrue(source.contains("followingScheduleAdapter.submitItems(emptyList())"))
|
||||
assertTrue(source.contains("followingNewsAdapter.submitItems(emptyList())"))
|
||||
assertTrue(source.contains("bindFollowingCreatorSection(content.followingCreators)"))
|
||||
assertTrue(source.contains("bindFollowingLiveSection(content.onAirLives)"))
|
||||
assertTrue(source.contains("bindFollowingChatSection(content.recentChats)"))
|
||||
assertTrue(source.contains("bindFollowingScheduleSection(content.monthlySchedules)"))
|
||||
assertTrue(source.contains("bindFollowingNewsSection(content.recentNews)"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `following adapters bind figma required item fields`() {
|
||||
val liveAdapter = projectFile(
|
||||
"app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/ui/HomeFollowingLiveAdapter.kt"
|
||||
).readText()
|
||||
val liveLayout = projectFile("app/src/main/res/layout/item_home_following_live.xml").readText()
|
||||
val scheduleAdapter = projectFile(
|
||||
"app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/ui/HomeFollowingScheduleAdapter.kt"
|
||||
).readText()
|
||||
val scheduleLayout = projectFile("app/src/main/res/layout/item_home_following_schedule.xml").readText()
|
||||
val newsAdapter = projectFile(
|
||||
"app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/ui/HomeFollowingNewsAdapter.kt"
|
||||
).readText()
|
||||
val newsLayout = projectFile("app/src/main/res/layout/item_home_following_news_content.xml").readText()
|
||||
|
||||
assertTrue(liveLayout.contains("@+id/tv_home_following_live_started_at"))
|
||||
assertTrue(liveAdapter.contains("startedAtText.text"))
|
||||
assertTrue(liveAdapter.contains("item.startedAtUtc"))
|
||||
|
||||
assertTrue(scheduleLayout.contains("@+id/iv_home_following_schedule_creator_profile"))
|
||||
assertTrue(scheduleLayout.contains("@+id/tv_home_following_schedule_type"))
|
||||
assertTrue(scheduleAdapter.contains("profileImage.loadHomeCreatorProfileImage(item.creatorProfileImageUrl)"))
|
||||
assertTrue(scheduleAdapter.contains("typeText.setText(item.typeLabelResId)"))
|
||||
assertTrue(scheduleAdapter.contains("item.isOnAir"))
|
||||
assertTrue(scheduleAdapter.contains("R.string.screen_home_following_on_air"))
|
||||
|
||||
assertTrue(newsLayout.contains("@+id/tv_home_following_news_label"))
|
||||
assertTrue(newsLayout.contains("@+id/tv_home_following_news_title"))
|
||||
assertTrue(newsAdapter.contains("labelText.setText(content.labelResId)"))
|
||||
assertTrue(newsAdapter.contains("titleText.text = content.title"))
|
||||
assertTrue(newsAdapter.contains("createdAtText.text = content.visibleFromText"))
|
||||
}
|
||||
|
||||
private fun homeMainFragmentSource(): String {
|
||||
return projectFile("app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/HomeMainFragment.kt").readText()
|
||||
}
|
||||
|
||||
private fun homeMainLayoutSource(): String {
|
||||
return projectFile("app/src/main/res/layout/fragment_v2_main_home.xml").readText()
|
||||
}
|
||||
|
||||
private fun projectFile(relativePath: String): File {
|
||||
val candidates = listOf(File(relativePath), File("../$relativePath"))
|
||||
return candidates.first { it.exists() }.canonicalFile
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user