feat(home): 팔로잉 탭 화면을 연결한다

This commit is contained in:
2026-06-25 23:34:24 +09:00
parent f009a2edb8
commit 01d0367f50
3 changed files with 467 additions and 1 deletions

View File

@@ -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
}

View File

@@ -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"

View File

@@ -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
}
}