feat(content): 전체보기 화면 등록을 추가한다
This commit is contained in:
@@ -112,6 +112,7 @@
|
|||||||
</activity>
|
</activity>
|
||||||
<activity android:name=".main.MainActivity" />
|
<activity android:name=".main.MainActivity" />
|
||||||
<activity android:name=".v2.main.MainV2Activity" />
|
<activity android:name=".v2.main.MainV2Activity" />
|
||||||
|
<activity android:name=".v2.main.content.overview.ContentOverviewActivity" />
|
||||||
<activity android:name=".v2.creator.channel.CreatorChannelActivity" />
|
<activity android:name=".v2.creator.channel.CreatorChannelActivity" />
|
||||||
<activity android:name=".v2.live.onair.HomeOnAirLiveActivity" />
|
<activity android:name=".v2.live.onair.HomeOnAirLiveActivity" />
|
||||||
<activity
|
<activity
|
||||||
|
|||||||
@@ -207,6 +207,9 @@ import kr.co.vividnext.sodalive.v2.main.content.data.AudioRankingsApi
|
|||||||
import kr.co.vividnext.sodalive.v2.main.content.data.AudioRankingsRepository
|
import kr.co.vividnext.sodalive.v2.main.content.data.AudioRankingsRepository
|
||||||
import kr.co.vividnext.sodalive.v2.main.content.data.MainContentAllTabApi
|
import kr.co.vividnext.sodalive.v2.main.content.data.MainContentAllTabApi
|
||||||
import kr.co.vividnext.sodalive.v2.main.content.data.MainContentAllTabRepository
|
import kr.co.vividnext.sodalive.v2.main.content.data.MainContentAllTabRepository
|
||||||
|
import kr.co.vividnext.sodalive.v2.main.content.overview.ContentOverviewViewModel
|
||||||
|
import kr.co.vividnext.sodalive.v2.main.content.overview.data.ContentOverviewRepository
|
||||||
|
import kr.co.vividnext.sodalive.v2.main.content.overview.data.ContentOverviewApi
|
||||||
import kr.co.vividnext.sodalive.v2.main.home.HomeCreatorRankingViewModel
|
import kr.co.vividnext.sodalive.v2.main.home.HomeCreatorRankingViewModel
|
||||||
import kr.co.vividnext.sodalive.v2.main.home.HomeFollowingViewModel
|
import kr.co.vividnext.sodalive.v2.main.home.HomeFollowingViewModel
|
||||||
import kr.co.vividnext.sodalive.v2.main.home.HomeRecommendationViewModel
|
import kr.co.vividnext.sodalive.v2.main.home.HomeRecommendationViewModel
|
||||||
@@ -331,6 +334,7 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
|
|||||||
single { ApiBuilder().build(get(), AudioRecommendationsApi::class.java) }
|
single { ApiBuilder().build(get(), AudioRecommendationsApi::class.java) }
|
||||||
single { ApiBuilder().build(get(), AudioRankingsApi::class.java) }
|
single { ApiBuilder().build(get(), AudioRankingsApi::class.java) }
|
||||||
single { ApiBuilder().build(get(), MainContentAllTabApi::class.java) }
|
single { ApiBuilder().build(get(), MainContentAllTabApi::class.java) }
|
||||||
|
single { ApiBuilder().build(get(), ContentOverviewApi::class.java) }
|
||||||
single { ApiBuilder().build(get(), HomeCreatorRankingApi::class.java) }
|
single { ApiBuilder().build(get(), HomeCreatorRankingApi::class.java) }
|
||||||
single { ApiBuilder().build(get(), HomeFollowingApi::class.java) }
|
single { ApiBuilder().build(get(), HomeFollowingApi::class.java) }
|
||||||
single { ApiBuilder().build(get(), HomeRecommendationApi::class.java) }
|
single { ApiBuilder().build(get(), HomeRecommendationApi::class.java) }
|
||||||
@@ -436,6 +440,7 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
|
|||||||
viewModel { ChatMainViewModel(get()) }
|
viewModel { ChatMainViewModel(get()) }
|
||||||
viewModel { DmChatRoomViewModel(get()) }
|
viewModel { DmChatRoomViewModel(get()) }
|
||||||
viewModel { ContentAllTabViewModel(get()) }
|
viewModel { ContentAllTabViewModel(get()) }
|
||||||
|
viewModel { ContentOverviewViewModel(get()) }
|
||||||
viewModel { ContentMainViewModel(get()) }
|
viewModel { ContentMainViewModel(get()) }
|
||||||
viewModel { ContentRankingViewModel(get()) }
|
viewModel { ContentRankingViewModel(get()) }
|
||||||
viewModel { HomeCreatorRankingViewModel(get()) }
|
viewModel { HomeCreatorRankingViewModel(get()) }
|
||||||
@@ -504,6 +509,7 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
|
|||||||
factory { AudioRecommendationsRepository(get()) }
|
factory { AudioRecommendationsRepository(get()) }
|
||||||
factory { AudioRankingsRepository(get()) }
|
factory { AudioRankingsRepository(get()) }
|
||||||
factory { MainContentAllTabRepository(get()) }
|
factory { MainContentAllTabRepository(get()) }
|
||||||
|
factory { ContentOverviewRepository(get()) }
|
||||||
factory { HomeCreatorRankingRepository(get()) }
|
factory { HomeCreatorRankingRepository(get()) }
|
||||||
factory { HomeFollowingRepository(get()) }
|
factory { HomeFollowingRepository(get()) }
|
||||||
factory { HomeRecommendationRepository(get()) }
|
factory { HomeRecommendationRepository(get()) }
|
||||||
|
|||||||
@@ -0,0 +1,110 @@
|
|||||||
|
package kr.co.vividnext.sodalive.v2.main.content.overview
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
|
import org.junit.Assert.assertFalse
|
||||||
|
import org.junit.Assert.assertTrue
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.robolectric.RobolectricTestRunner
|
||||||
|
import org.robolectric.annotation.Config
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
@RunWith(RobolectricTestRunner::class)
|
||||||
|
@Config(application = Application::class)
|
||||||
|
class ContentOverviewActivitySourceTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `ContentOverviewActivity source has intent extra and two column grid contract`() {
|
||||||
|
val source = projectFile(
|
||||||
|
"app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/overview/ContentOverviewActivity.kt"
|
||||||
|
).readText()
|
||||||
|
|
||||||
|
assertTrue(source.contains("private const val EXTRA_CONTENT_OVERVIEW_TYPE"))
|
||||||
|
assertTrue(source.contains("fun newIntent(context: Context, type: ContentOverviewType): Intent"))
|
||||||
|
assertTrue(source.contains("putExtra(EXTRA_CONTENT_OVERVIEW_TYPE, type.name)"))
|
||||||
|
assertTrue(source.contains("CONTENT_OVERVIEW_GRID_SPAN_COUNT"))
|
||||||
|
assertTrue(source.contains("GridLayoutManager(this, CONTENT_OVERVIEW_GRID_SPAN_COUNT)"))
|
||||||
|
assertTrue(
|
||||||
|
source.contains(
|
||||||
|
"binding.rvContentOverviewItems.calculateContentGridItemWidthPx(CONTENT_OVERVIEW_GRID_SPAN_COUNT)"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
assertTrue(source.contains("viewModel.loadMore()"))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `ContentOverview layout has Figma title bar and state views`() {
|
||||||
|
val layout = projectFile("app/src/main/res/layout/activity_content_overview.xml").readText()
|
||||||
|
|
||||||
|
assertTrue(layout.contains("@+id/layout_content_overview_root"))
|
||||||
|
assertTrue(layout.contains("android:background=\"@color/black\""))
|
||||||
|
assertTrue(layout.contains("@+id/layout_content_overview_title_bar"))
|
||||||
|
assertTrue(layout.contains("android:layout_height=\"60dp\""))
|
||||||
|
assertTrue(layout.contains("@+id/iv_content_overview_back"))
|
||||||
|
assertTrue(layout.contains("@drawable/ic_new_bar_back"))
|
||||||
|
assertTrue(layout.contains("@+id/tv_content_overview_title"))
|
||||||
|
assertTrue(layout.contains("@style/Typography.Heading2"))
|
||||||
|
assertTrue(layout.contains("@+id/rv_content_overview_items"))
|
||||||
|
assertTrue(layout.contains("@+id/pb_content_overview_initial_loading"))
|
||||||
|
assertTrue(layout.contains("@+id/pb_content_overview_load_more"))
|
||||||
|
assertTrue(layout.contains("@+id/tv_content_overview_empty_error"))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `ContentOverviewActivity renders first and load more loading states visibly`() {
|
||||||
|
val source = projectFile(
|
||||||
|
"app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/overview/ContentOverviewActivity.kt"
|
||||||
|
).readText()
|
||||||
|
|
||||||
|
assertTrue(source.contains("viewModel.isLoading.observe(this)"))
|
||||||
|
assertTrue(source.contains("pbContentOverviewInitialLoading.visibility = View.VISIBLE"))
|
||||||
|
assertTrue(source.contains("pbContentOverviewInitialLoading.visibility = View.GONE"))
|
||||||
|
assertTrue(source.contains("pbContentOverviewLoadMore.visibility = View.GONE"))
|
||||||
|
assertTrue(source.contains("pbContentOverviewLoadMore.visibility = if (state.isLoadingMore)"))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `ContentOverviewActivity opens audio detail with content id`() {
|
||||||
|
val source = projectFile(
|
||||||
|
"app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/overview/ContentOverviewActivity.kt"
|
||||||
|
).readText()
|
||||||
|
|
||||||
|
assertTrue(source.contains("AudioContentDetailActivity::class.java"))
|
||||||
|
assertTrue(source.contains("if (contentId <= 0) return"))
|
||||||
|
assertTrue(source.contains("putExtra(Constants.EXTRA_AUDIO_CONTENT_ID, contentId)"))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `ContentOverviewAdapter ignores invalid content id clicks`() {
|
||||||
|
val source = projectFile(
|
||||||
|
"app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/overview/ui/ContentOverviewAdapter.kt"
|
||||||
|
).readText()
|
||||||
|
|
||||||
|
assertTrue(source.contains("if (item.contentId <= 0) return@setOnClickListener"))
|
||||||
|
assertTrue(source.contains("onContentClick(item.contentId)"))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `manifest registers ContentOverviewActivity and Phase 7 routing is not added`() {
|
||||||
|
val manifest = projectFile("app/src/main/AndroidManifest.xml").readText()
|
||||||
|
val homeSource = projectFile(
|
||||||
|
"app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/HomeMainFragment.kt"
|
||||||
|
).readText()
|
||||||
|
val contentSource = projectFile(
|
||||||
|
"app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/ContentMainFragment.kt"
|
||||||
|
).readText()
|
||||||
|
|
||||||
|
assertTrue(manifest.contains(".v2.main.content.overview.ContentOverviewActivity"))
|
||||||
|
assertFalse(homeSource.contains("viewHomeFirstAudioTitle.ivSectionTitleChevron.setOnClickListener"))
|
||||||
|
assertFalse(contentSource.contains("viewContentNewAndHotTitle.ivSectionTitleChevron.setOnClickListener"))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun projectFile(relativePath: String): File {
|
||||||
|
val userDir = requireNotNull(System.getProperty("user.dir"))
|
||||||
|
val fromRoot = File(userDir, relativePath)
|
||||||
|
if (fromRoot.exists()) return fromRoot
|
||||||
|
|
||||||
|
val projectRoot = requireNotNull(File(userDir).parentFile)
|
||||||
|
return projectRoot.resolve(relativePath)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user