Skip to content

Commit 2ea9d87

Browse files
authored
Merge pull request #28 from YAPP-Github/feature/NDGL-107/impl-follow-travel
[NDGL-107] 인기 여행 따라가기 페이지 구현
2 parents f742ef9 + 814799c commit 2ea9d87

13 files changed

Lines changed: 396 additions & 29 deletions

File tree

core/ui/src/main/res/values/strings.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
<string name="add_memo">메모 추가</string>
1515
<string name="common_dot_separator">•</string>
1616
<string name="common_retry">다시 시도</string>
17+
<string name="common_all">전체</string>
1718

1819
<!-- Transport Segment -->
1920
<string name="transport_segment_format">약 %1$s • %2$s</string>

feature/home/src/main/java/com/yapp/ndgl/feature/home/main/HomeContract.kt

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ import com.yapp.ndgl.core.base.UiIntent
66
import com.yapp.ndgl.core.base.UiSideEffect
77
import com.yapp.ndgl.core.base.UiState
88
import com.yapp.ndgl.data.travel.model.PlaceCategory
9-
import com.yapp.ndgl.data.travel.model.ProgramType
109
import com.yapp.ndgl.feature.home.model.TravelContent
10+
import com.yapp.ndgl.feature.home.model.TravelProgramTab
1111
import java.time.LocalDate
1212

1313
@Stable
@@ -60,25 +60,17 @@ data class HomeState(
6060
popularTravelsByProgram[selectedTab.programId] ?: emptyList()
6161
}
6262
}
63-
64-
sealed interface TravelProgramTab {
65-
data object All : TravelProgramTab
66-
67-
data class Custom(
68-
val programId: Long,
69-
val name: String,
70-
val type: ProgramType,
71-
) : TravelProgramTab
72-
}
7363
}
7464

7565
sealed interface HomeIntent : UiIntent {
7666
data object ClickSearchTravelTemplate : HomeIntent
7767
data class SelectPopularTravelTab(val index: Int) : HomeIntent
7868
data class ClickTravel(val travelId: Long) : HomeIntent
69+
data object ClickTravelMore : HomeIntent
7970
}
8071

8172
sealed interface HomeSideEffect : UiSideEffect {
8273
data object NavigateToSearchTravelTemplate : HomeSideEffect
8374
data class NavigateToFollowTravel(val travelId: Long, val days: Int) : HomeSideEffect
75+
data object NavigateToTravelMore : HomeSideEffect
8476
}

feature/home/src/main/java/com/yapp/ndgl/feature/home/main/HomeScreen.kt

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,15 @@ import com.yapp.ndgl.core.ui.theme.NDGLTheme
2222
import com.yapp.ndgl.data.travel.model.PlaceCategory
2323
import com.yapp.ndgl.data.travel.model.ProgramType
2424
import com.yapp.ndgl.feature.home.model.TravelContent
25+
import com.yapp.ndgl.feature.home.model.TravelProgramTab
2526
import java.time.LocalDate
2627

2728
@Composable
2829
internal fun HomeRoute(
2930
viewModel: HomeViewModel = hiltViewModel(),
3031
navigateToTemplateSearch: () -> Unit,
3132
navigateToFollowTravel: (Long, Int) -> Unit,
33+
navigateToPopularTravelList: () -> Unit,
3234
) {
3335
val state by viewModel.collectAsState()
3436

@@ -43,12 +45,16 @@ internal fun HomeRoute(
4345
onTravelClick = { travelId ->
4446
viewModel.onIntent(HomeIntent.ClickTravel(travelId))
4547
},
48+
onTravelMoreClick = {
49+
viewModel.onIntent(HomeIntent.ClickTravelMore)
50+
},
4651
)
4752

4853
viewModel.collectSideEffect { sideEffect ->
4954
when (sideEffect) {
5055
HomeSideEffect.NavigateToSearchTravelTemplate -> navigateToTemplateSearch()
5156
is HomeSideEffect.NavigateToFollowTravel -> navigateToFollowTravel(sideEffect.travelId, sideEffect.days)
57+
HomeSideEffect.NavigateToTravelMore -> navigateToPopularTravelList()
5258
}
5359
}
5460
}
@@ -59,6 +65,7 @@ private fun HomeScreen(
5965
onSearchClick: () -> Unit,
6066
onTabSelected: (Int) -> Unit,
6167
onTravelClick: (Long) -> Unit,
68+
onTravelMoreClick: () -> Unit,
6269
) {
6370
Scaffold(
6471
topBar = {
@@ -104,6 +111,7 @@ private fun HomeScreen(
104111
travels = state.filteredPopularTravels,
105112
onTabSelected = onTabSelected,
106113
onTravelClick = onTravelClick,
114+
onTravelMoreClick = onTravelMoreClick,
107115
)
108116
}
109117
}
@@ -176,18 +184,18 @@ private fun HomeScreenPreview() {
176184
),
177185
),
178186
travelProgramTabs = listOf(
179-
HomeState.TravelProgramTab.All,
180-
HomeState.TravelProgramTab.Custom(
187+
TravelProgramTab.All,
188+
TravelProgramTab.Custom(
181189
programId = 1,
182190
name = "빠니보틀",
183191
type = ProgramType.YOUTUBE,
184192
),
185-
HomeState.TravelProgramTab.Custom(
193+
TravelProgramTab.Custom(
186194
programId = 2,
187195
name = "곽튜브",
188196
type = ProgramType.YOUTUBE,
189197
),
190-
HomeState.TravelProgramTab.Custom(
198+
TravelProgramTab.Custom(
191199
programId = 3,
192200
name = "콩콩팡팡",
193201
type = ProgramType.TV,
@@ -198,6 +206,7 @@ private fun HomeScreenPreview() {
198206
onSearchClick = {},
199207
onTabSelected = {},
200208
onTravelClick = {},
209+
onTravelMoreClick = {},
201210
)
202211
}
203212
}

feature/home/src/main/java/com/yapp/ndgl/feature/home/main/HomeViewModel.kt

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import com.yapp.ndgl.data.travel.repository.TravelProgramRepository
1010
import com.yapp.ndgl.data.travel.repository.TravelTemplateRepository
1111
import com.yapp.ndgl.data.travel.repository.UserTravelRepository
1212
import com.yapp.ndgl.feature.home.model.TravelContent
13+
import com.yapp.ndgl.feature.home.model.TravelProgramTab
1314
import dagger.hilt.android.lifecycle.HiltViewModel
1415
import kotlinx.coroutines.async
1516
import kotlinx.coroutines.awaitAll
@@ -124,10 +125,10 @@ class HomeViewModel @Inject constructor(
124125
}
125126

126127
val tabs = buildList {
127-
add(HomeState.TravelProgramTab.All)
128+
add(TravelProgramTab.All)
128129
programs.forEach { program ->
129130
add(
130-
HomeState.TravelProgramTab.Custom(
131+
TravelProgramTab.Custom(
131132
programId = program.id,
132133
name = program.name,
133134
type = program.type,
@@ -190,6 +191,7 @@ class HomeViewModel @Inject constructor(
190191
}
191192

192193
is HomeIntent.ClickTravel -> postNavigateToTravelTemplate(travelId = intent.travelId)
194+
HomeIntent.ClickTravelMore -> postNavigateToTravelMore()
193195
}
194196
}
195197

@@ -201,6 +203,10 @@ class HomeViewModel @Inject constructor(
201203
postSideEffect(HomeSideEffect.NavigateToFollowTravel(travelId = travelId, days = 1))
202204
}
203205

206+
private fun postNavigateToTravelMore() {
207+
postSideEffect(HomeSideEffect.NavigateToTravelMore)
208+
}
209+
204210
companion object {
205211
private const val MAX_POPULAR_TRAVEL_COUNT = 9
206212
}

feature/home/src/main/java/com/yapp/ndgl/feature/home/main/PopularTravelSection.kt

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,21 @@ import com.yapp.ndgl.data.travel.model.ProgramType
2424
import com.yapp.ndgl.feature.home.R
2525
import com.yapp.ndgl.feature.home.component.TravelTemplate
2626
import com.yapp.ndgl.feature.home.model.TravelContent
27+
import com.yapp.ndgl.feature.home.model.TravelProgramTab
2728
import com.yapp.ndgl.feature.home.util.toIconRes
2829
import kotlinx.collections.immutable.toPersistentList
30+
import com.yapp.ndgl.core.ui.R as CoreR
2931

3032
private const val COLUMN_ITEM_COUNT = 3
3133

3234
@Composable
3335
internal fun PopularTravelSection(
34-
tabs: List<HomeState.TravelProgramTab>,
36+
tabs: List<TravelProgramTab>,
3537
selectedTabIndex: Int,
3638
travels: List<TravelContent>,
3739
onTabSelected: (Int) -> Unit,
3840
onTravelClick: (Long) -> Unit,
41+
onTravelMoreClick: () -> Unit,
3942
) {
4043
Column(
4144
modifier = Modifier.fillMaxWidth(),
@@ -61,7 +64,7 @@ internal fun PopularTravelSection(
6164
NDGLOutlinedButton(
6265
status = NDGLOutlinedButtonAttr.Status.ACTIVE,
6366
label = stringResource(R.string.home_popular_travel_more_button),
64-
onClick = {},
67+
onClick = onTravelMoreClick,
6568
modifier = Modifier
6669
.fillMaxWidth()
6770
.padding(horizontal = 24.dp),
@@ -71,7 +74,7 @@ internal fun PopularTravelSection(
7174

7275
@Composable
7376
private fun HorizontalCardSection(
74-
tabs: List<HomeState.TravelProgramTab>,
77+
tabs: List<TravelProgramTab>,
7578
selectedTabIndex: Int,
7679
travels: List<TravelContent>,
7780
onTabSelected: (Int) -> Unit,
@@ -87,11 +90,12 @@ private fun HorizontalCardSection(
8790
NDGLChipTab(
8891
tabs = tabs.map { tab ->
8992
when (tab) {
90-
HomeState.TravelProgramTab.All -> NDGLChipTabAttr.Tab(
93+
TravelProgramTab.All -> NDGLChipTabAttr.Tab(
9194
tag = "All",
92-
name = "전체",
95+
name = stringResource(CoreR.string.common_all),
9396
)
94-
is HomeState.TravelProgramTab.Custom -> NDGLChipTabAttr.Tab(
97+
98+
is TravelProgramTab.Custom -> NDGLChipTabAttr.Tab(
9599
tag = tab.programId.toString(),
96100
name = tab.name,
97101
leadingIcon = tab.type.toIconRes(),
@@ -185,13 +189,13 @@ private fun PopularTravelSectionPreview() {
185189
NDGLTheme {
186190
PopularTravelSection(
187191
tabs = listOf(
188-
HomeState.TravelProgramTab.All,
189-
HomeState.TravelProgramTab.Custom(
192+
TravelProgramTab.All,
193+
TravelProgramTab.Custom(
190194
programId = 1,
191195
name = "빠니보틀",
192196
type = ProgramType.YOUTUBE,
193197
),
194-
HomeState.TravelProgramTab.Custom(
198+
TravelProgramTab.Custom(
195199
programId = 2,
196200
name = "곽튜브",
197201
type = ProgramType.TV,
@@ -201,6 +205,7 @@ private fun PopularTravelSectionPreview() {
201205
travels = sampleTravels,
202206
onTabSelected = {},
203207
onTravelClick = {},
208+
onTravelMoreClick = {},
204209
)
205210
}
206211
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.yapp.ndgl.feature.home.model
2+
3+
import com.yapp.ndgl.data.travel.model.ProgramType
4+
5+
sealed interface TravelProgramTab {
6+
data object All : TravelProgramTab
7+
8+
data class Custom(
9+
val programId: Long,
10+
val name: String,
11+
val type: ProgramType,
12+
) : TravelProgramTab
13+
}

feature/home/src/main/java/com/yapp/ndgl/feature/home/navigation/HomeEntry.kt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.yapp.ndgl.feature.home.navigation
33
import androidx.navigation3.runtime.EntryProviderScope
44
import androidx.navigation3.runtime.NavKey
55
import com.yapp.ndgl.feature.home.main.HomeRoute
6+
import com.yapp.ndgl.feature.home.popular.PopularTravelListRoute
67
import com.yapp.ndgl.feature.home.search.TemplateSearchRoute
78
import com.yapp.ndgl.navigation.Navigator
89
import com.yapp.ndgl.navigation.Route
@@ -18,6 +19,9 @@ fun EntryProviderScope<NavKey>.homeEntry(
1819
navigateToFollowTravel = { travelId, days ->
1920
navigator.navigate(Route.FollowTravel(travelId = travelId, days = days))
2021
},
22+
navigateToPopularTravelList = {
23+
navigator.navigate(Route.PopularTravelList)
24+
},
2125
)
2226
}
2327
entry<Route.TemplateSearch> {
@@ -30,4 +34,17 @@ fun EntryProviderScope<NavKey>.homeEntry(
3034
},
3135
)
3236
}
37+
entry<Route.PopularTravelList> {
38+
PopularTravelListRoute(
39+
goBack = {
40+
navigator.goBack()
41+
},
42+
navigateToTemplateSearch = {
43+
navigator.navigate(Route.TemplateSearch)
44+
},
45+
navigateToFollowTravel = { travelId, days ->
46+
navigator.navigate(Route.FollowTravel(travelId = travelId, days = days))
47+
},
48+
)
49+
}
3350
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package com.yapp.ndgl.feature.home.popular
2+
3+
import androidx.compose.runtime.Immutable
4+
import com.yapp.ndgl.core.base.UiIntent
5+
import com.yapp.ndgl.core.base.UiSideEffect
6+
import com.yapp.ndgl.core.base.UiState
7+
import com.yapp.ndgl.feature.home.model.TravelContent
8+
import com.yapp.ndgl.feature.home.model.TravelProgramTab
9+
import kotlinx.collections.immutable.ImmutableList
10+
import kotlinx.collections.immutable.ImmutableMap
11+
import kotlinx.collections.immutable.persistentListOf
12+
import kotlinx.collections.immutable.persistentMapOf
13+
14+
@Immutable
15+
data class PopularTravelListState(
16+
val travelProgramTabs: ImmutableList<TravelProgramTab> = persistentListOf(),
17+
val selectedTabIndex: Int = 0,
18+
val allPopularTravels: ImmutableList<TravelContent> = persistentListOf(),
19+
val popularTravelsByProgram: ImmutableMap<Long, ImmutableList<TravelContent>> = persistentMapOf(),
20+
) : UiState {
21+
val selectedProgramTravels: ImmutableList<TravelContent> by lazy {
22+
val selectTab = travelProgramTabs.getOrElse(selectedTabIndex) { TravelProgramTab.All }
23+
24+
when (selectTab) {
25+
TravelProgramTab.All -> allPopularTravels
26+
is TravelProgramTab.Custom -> popularTravelsByProgram.getOrDefault(
27+
selectTab.programId,
28+
persistentListOf(),
29+
)
30+
}
31+
}
32+
}
33+
34+
sealed interface PopularTravelListIntent : UiIntent {
35+
data object ClickSearchTravelTemplate : PopularTravelListIntent
36+
data class SelectPopularTravelTab(val index: Int) : PopularTravelListIntent
37+
data class ClickTravel(val travelId: Long) : PopularTravelListIntent
38+
}
39+
40+
sealed interface PopularTravelListSideEffect : UiSideEffect {
41+
data object NavigateToSearchTravelTemplate : PopularTravelListSideEffect
42+
data class NavigateToFollowTravel(
43+
val travelId: Long,
44+
val days: Int,
45+
) : PopularTravelListSideEffect
46+
}

0 commit comments

Comments
 (0)