feat(content): 추천 섹션 전체 탭 이동을 연결한다
This commit is contained in:
@@ -47,11 +47,13 @@ import kr.co.vividnext.sodalive.mypage.MyPageFragment
|
||||
import kr.co.vividnext.sodalive.settings.event.EventDetailActivity
|
||||
import kr.co.vividnext.sodalive.settings.notification.NotificationSettingsDialog
|
||||
import kr.co.vividnext.sodalive.user.login.LoginActivity
|
||||
import kr.co.vividnext.sodalive.v2.common.data.ContentSort
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivity
|
||||
import kr.co.vividnext.sodalive.v2.main.chat.ChatMainFragment
|
||||
import kr.co.vividnext.sodalive.v2.main.chat.dm.DmChatRoomActivity
|
||||
import kr.co.vividnext.sodalive.v2.main.chat.model.ChatRoomFilter
|
||||
import kr.co.vividnext.sodalive.v2.main.content.ContentMainFragment
|
||||
import kr.co.vividnext.sodalive.v2.main.content.data.MainContentAllType
|
||||
import kr.co.vividnext.sodalive.v2.main.home.HomeMainFragment
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.collect
|
||||
@@ -168,6 +170,16 @@ class MainV2Activity : BaseActivity<ActivityMainV2Binding>(ActivityMainV2Binding
|
||||
selectChatTabWithLoginGuard()
|
||||
}
|
||||
|
||||
fun openContentAllTab(type: MainContentAllType, sort: ContentSort = ContentSort.LATEST) {
|
||||
if (viewModel.currentTab.value != MainV2Tab.CONTENT) {
|
||||
viewModel.clickTab(MainV2Tab.CONTENT)
|
||||
changeFragment(MainV2Tab.CONTENT)
|
||||
}
|
||||
|
||||
(supportFragmentManager.findFragmentByTag(MainV2Tab.CONTENT.toString()) as? ContentMainFragment)
|
||||
?.selectAllTab(type, sort)
|
||||
}
|
||||
|
||||
private fun consumeInitialChatFilter(): ChatRoomFilter? {
|
||||
return intent.getStringExtra(EXTRA_CHAT_FILTER)
|
||||
?.let { runCatching { ChatRoomFilter.valueOf(it) }.getOrNull() }
|
||||
|
||||
@@ -26,6 +26,7 @@ import kr.co.vividnext.sodalive.home.SeriesPublishedDaysOfWeek
|
||||
import kr.co.vividnext.sodalive.v2.common.data.ContentSort
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.model.toLabelResId
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.ui.CreatorChannelSortPopup
|
||||
import kr.co.vividnext.sodalive.v2.main.MainV2Activity
|
||||
import kr.co.vividnext.sodalive.v2.main.ensureMainV2NavigationAllowed
|
||||
import kr.co.vividnext.sodalive.v2.main.content.data.AudioRankingType
|
||||
import kr.co.vividnext.sodalive.v2.main.content.data.MainContentAllType
|
||||
@@ -101,6 +102,7 @@ class ContentMainFragment : BaseFragment<FragmentV2MainContentBinding>(
|
||||
private var hasSelectedAllTab = false
|
||||
private var currentContentTab = CONTENT_TAB_RECOMMENDATION
|
||||
private var currentAllTabState: MainContentAllTabUiState? = null
|
||||
private var pendingAllTabSelection: ContentAllTabSelection? = null
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
@@ -114,6 +116,7 @@ class ContentMainFragment : BaseFragment<FragmentV2MainContentBinding>(
|
||||
setUpAdapters()
|
||||
bindObservers()
|
||||
contentMainViewModel.loadRecommendations()
|
||||
applyPendingAllTabSelection()
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
@@ -124,6 +127,22 @@ class ContentMainFragment : BaseFragment<FragmentV2MainContentBinding>(
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
fun selectAllTab(type: MainContentAllType, sort: ContentSort = ContentSort.LATEST) {
|
||||
pendingAllTabSelection = ContentAllTabSelection(type, sort)
|
||||
if (view != null) {
|
||||
applyPendingAllTabSelection()
|
||||
}
|
||||
}
|
||||
|
||||
private fun applyPendingAllTabSelection() {
|
||||
val selection = pendingAllTabSelection ?: return
|
||||
pendingAllTabSelection = null
|
||||
hasSelectedAllTab = true
|
||||
binding.textTabBarContent.root.selectTab(CONTENT_TAB_ALL)
|
||||
showContentTab(CONTENT_TAB_ALL)
|
||||
contentAllTabViewModel.selectTypeAndSort(selection.type, selection.sort)
|
||||
}
|
||||
|
||||
private fun setUpTextTabs() {
|
||||
binding.textTabBarContent.root.setMenus(
|
||||
listOf(
|
||||
@@ -529,6 +548,18 @@ class ContentMainFragment : BaseFragment<FragmentV2MainContentBinding>(
|
||||
)
|
||||
binding.viewContentMostCommentedAudioTitle.setTitle(R.string.content_recommendation_section_most_commented_audio)
|
||||
binding.viewContentRecommendedAudioTitle.setTitle(R.string.content_recommendation_section_recommended_audio)
|
||||
binding.viewContentOriginalSeriesTitle.ivSectionTitleChevron.setOnClickListener {
|
||||
openContentAllTab(MainContentAllType.ORIGINAL, ContentSort.LATEST)
|
||||
}
|
||||
binding.viewContentLatestAudioTitle.ivSectionTitleChevron.setOnClickListener {
|
||||
openContentAllTab(MainContentAllType.AUDIO, ContentSort.LATEST)
|
||||
}
|
||||
binding.viewContentFreeAudioTitle.ivSectionTitleChevron.setOnClickListener {
|
||||
openContentAllTab(MainContentAllType.FREE, ContentSort.POPULAR)
|
||||
}
|
||||
binding.viewContentPointAudioTitle.ivSectionTitleChevron.setOnClickListener {
|
||||
openContentAllTab(MainContentAllType.POINT, ContentSort.POPULAR)
|
||||
}
|
||||
}
|
||||
|
||||
private fun ViewSectionTitleBinding.setTitle(
|
||||
@@ -546,6 +577,12 @@ class ContentMainFragment : BaseFragment<FragmentV2MainContentBinding>(
|
||||
}
|
||||
}
|
||||
|
||||
private fun openContentAllTab(type: MainContentAllType, sort: ContentSort) {
|
||||
ensureMainV2NavigationAllowed {
|
||||
(activity as? MainV2Activity)?.openContentAllTab(type, sort)
|
||||
}
|
||||
}
|
||||
|
||||
private fun openAudioContentDetail(item: ContentAudioCardUiModel) {
|
||||
openAudioContentDetail(item.audioContentId, item.showAdultBadge)
|
||||
}
|
||||
@@ -644,4 +681,9 @@ class ContentMainFragment : BaseFragment<FragmentV2MainContentBinding>(
|
||||
private const val CONTENT_TAB_RANKING = 1
|
||||
private const val CONTENT_TAB_ALL = 2
|
||||
}
|
||||
|
||||
private data class ContentAllTabSelection(
|
||||
val type: MainContentAllType,
|
||||
val sort: ContentSort
|
||||
)
|
||||
}
|
||||
|
||||
@@ -73,6 +73,24 @@ class MainV2ActivitySourceTest {
|
||||
assertTrue(navigationSource.contains("R.id.menu_main_v2_chat -> selectChatTabWithLoginGuard()"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `MainV2Activity는 콘텐츠 전체 탭 type sort 진입 contract를 제공한다`() {
|
||||
val source = projectFile("app/src/main/java/kr/co/vividnext/sodalive/v2/main/MainV2Activity.kt").readText()
|
||||
|
||||
assertTrue(source.contains("import kr.co.vividnext.sodalive.v2.common.data.ContentSort"))
|
||||
assertTrue(source.contains("import kr.co.vividnext.sodalive.v2.main.content.data.MainContentAllType"))
|
||||
assertTrue(source.contains("fun openContentAllTab(type: MainContentAllType, sort: ContentSort = ContentSort.LATEST)"))
|
||||
|
||||
val openContentSource = source.substringFrom("fun openContentAllTab(type: MainContentAllType")
|
||||
assertTrue(openContentSource.contains("if (viewModel.currentTab.value != MainV2Tab.CONTENT)"))
|
||||
assertTrue(openContentSource.contains("viewModel.clickTab(MainV2Tab.CONTENT)"))
|
||||
assertTrue(openContentSource.contains("changeFragment(MainV2Tab.CONTENT)"))
|
||||
assertTrue(openContentSource.contains("supportFragmentManager.findFragmentByTag(MainV2Tab.CONTENT.toString())"))
|
||||
assertTrue(openContentSource.contains("as? ContentMainFragment"))
|
||||
assertTrue(openContentSource.contains("?.selectAllTab(type, sort)"))
|
||||
assertBefore(openContentSource, "changeFragment(MainV2Tab.CONTENT)", "?.selectAllTab(type, sort)")
|
||||
}
|
||||
|
||||
private fun assertBefore(source: String, expectedBefore: String, expectedAfter: String) {
|
||||
val beforeIndex = source.indexOf(expectedBefore)
|
||||
val afterIndex = source.indexOf(expectedAfter, beforeIndex)
|
||||
|
||||
@@ -335,6 +335,50 @@ class ContentMainFragmentSourceTest {
|
||||
assertFalse(source.contains("viewContentNewAndHotTitle.ivSectionTitleChevron.setOnClickListener"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `content 전체 탭 외부 선택 source는 pending 처리와 중복 초기 로드 방지를 포함한다`() {
|
||||
val source = projectFile(
|
||||
"app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/ContentMainFragment.kt"
|
||||
).readText()
|
||||
|
||||
assertSourceContains(source, "fun selectAllTab(type: MainContentAllType, sort: ContentSort = ContentSort.LATEST)")
|
||||
assertSourceContains(source, "private var pendingAllTabSelection: ContentAllTabSelection? = null")
|
||||
assertSourceContains(source, "pendingAllTabSelection = ContentAllTabSelection(type, sort)")
|
||||
assertSourceContains(source, "if (view != null)")
|
||||
assertSourceContains(source, "applyPendingAllTabSelection()")
|
||||
assertSourceContains(source, "private fun applyPendingAllTabSelection()")
|
||||
assertSourceContains(source, "hasSelectedAllTab = true")
|
||||
assertSourceContains(source, "binding.textTabBarContent.root.selectTab(CONTENT_TAB_ALL)")
|
||||
assertSourceContains(source, "showContentTab(CONTENT_TAB_ALL)")
|
||||
assertSourceContains(source, "contentAllTabViewModel.selectTypeAndSort(selection.type, selection.sort)")
|
||||
assertTrue(
|
||||
"전체 탭 selectTab listener가 loadInitial을 일으키지 않도록 hasSelectedAllTab을 먼저 설정해야 한다.",
|
||||
source.indexOf("hasSelectedAllTab = true") <
|
||||
source.indexOf("binding.textTabBarContent.root.selectTab(CONTENT_TAB_ALL)")
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `content 추천 기존 전체보기 chevron은 MainV2Activity 전체 탭 routing을 호출한다`() {
|
||||
val source = projectFile(
|
||||
"app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/ContentMainFragment.kt"
|
||||
).readText()
|
||||
|
||||
assertSourceContains(source, "import kr.co.vividnext.sodalive.v2.main.MainV2Activity")
|
||||
assertSourceContains(source, "private fun openContentAllTab(type: MainContentAllType, sort: ContentSort)")
|
||||
assertSourceContains(source, "ensureMainV2NavigationAllowed")
|
||||
assertSourceContains(source, "(activity as? MainV2Activity)?.openContentAllTab(type, sort)")
|
||||
assertSourceContains(source, "binding.viewContentOriginalSeriesTitle.ivSectionTitleChevron.setOnClickListener")
|
||||
assertSourceContains(source, "openContentAllTab(MainContentAllType.ORIGINAL, ContentSort.LATEST)")
|
||||
assertSourceContains(source, "binding.viewContentLatestAudioTitle.ivSectionTitleChevron.setOnClickListener")
|
||||
assertSourceContains(source, "openContentAllTab(MainContentAllType.AUDIO, ContentSort.LATEST)")
|
||||
assertSourceContains(source, "binding.viewContentFreeAudioTitle.ivSectionTitleChevron.setOnClickListener")
|
||||
assertSourceContains(source, "openContentAllTab(MainContentAllType.FREE, ContentSort.POPULAR)")
|
||||
assertSourceContains(source, "binding.viewContentPointAudioTitle.ivSectionTitleChevron.setOnClickListener")
|
||||
assertSourceContains(source, "openContentAllTab(MainContentAllType.POINT, ContentSort.POPULAR)")
|
||||
assertFalse(source.contains("viewContentNewAndHotTitle.ivSectionTitleChevron.setOnClickListener"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Phase 4~5 adapter source는 grouping과 badge comment 정책을 포함한다`() {
|
||||
val cardView = projectFile(
|
||||
|
||||
Reference in New Issue
Block a user