Skip to content

Commit f042d3f

Browse files
authored
Merge pull request #41 from YAPP-Github/feature/NDGL-124/impl-popular-list-paging
[NDGL-124] 인기 여행 목록 페이지 paging 구현 및 에러 뷰 추가
2 parents 685d988 + 7420bfc commit f042d3f

File tree

8 files changed

+455
-118
lines changed

8 files changed

+455
-118
lines changed
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package com.yapp.ndgl.core.ui
2+
3+
import androidx.compose.foundation.Image
4+
import androidx.compose.foundation.layout.Arrangement
5+
import androidx.compose.foundation.layout.Column
6+
import androidx.compose.foundation.layout.fillMaxWidth
7+
import androidx.compose.foundation.layout.padding
8+
import androidx.compose.foundation.layout.size
9+
import androidx.compose.material3.Text
10+
import androidx.compose.runtime.Composable
11+
import androidx.compose.ui.Alignment
12+
import androidx.compose.ui.Modifier
13+
import androidx.compose.ui.res.painterResource
14+
import androidx.compose.ui.res.stringResource
15+
import androidx.compose.ui.text.style.TextAlign
16+
import androidx.compose.ui.tooling.preview.Preview
17+
import androidx.compose.ui.unit.dp
18+
import com.yapp.ndgl.core.ui.theme.NDGLTheme
19+
20+
@Composable
21+
fun CommonErrorView(
22+
modifier: Modifier = Modifier,
23+
title: String? = null,
24+
description: String? = null,
25+
) {
26+
Column(
27+
modifier = modifier
28+
.fillMaxWidth()
29+
.padding(horizontal = 24.dp, vertical = 165.dp),
30+
verticalArrangement = Arrangement.spacedBy(16.dp),
31+
horizontalAlignment = Alignment.CenterHorizontally,
32+
) {
33+
Image(
34+
painter = painterResource(R.drawable.img_empty_browser),
35+
contentDescription = null,
36+
modifier = Modifier.size(100.dp),
37+
)
38+
Column(
39+
modifier = Modifier.fillMaxWidth(),
40+
verticalArrangement = Arrangement.spacedBy(4.dp),
41+
horizontalAlignment = Alignment.CenterHorizontally,
42+
) {
43+
Text(
44+
text = title ?: stringResource(R.string.common_error_title),
45+
color = NDGLTheme.colors.black500,
46+
textAlign = TextAlign.Center,
47+
style = NDGLTheme.typography.subtitleMdSemiBold,
48+
)
49+
Text(
50+
text = description ?: stringResource(R.string.common_error_description),
51+
color = NDGLTheme.colors.black400,
52+
textAlign = TextAlign.Center,
53+
style = NDGLTheme.typography.bodyLgRegular,
54+
)
55+
}
56+
}
57+
}
58+
59+
@Preview(showBackground = true)
60+
@Composable
61+
private fun CommonErrorViewPreview() {
62+
NDGLTheme {
63+
CommonErrorView(
64+
modifier = Modifier,
65+
)
66+
}
67+
}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
<string name="common_dot_separator">•</string>
1616
<string name="common_retry">다시 시도</string>
1717
<string name="common_all">전체</string>
18+
<string name="common_err_unknown">알 수 없는 오류입니다</string>
19+
<string name="common_error_title">정보를 불러올 수 없어요</string>
20+
<string name="common_error_description">인터넷 연결 확인 후 다시 시도해 주세요</string>
1821

1922
<!-- User Guide Modal -->
2023
<string name="user_guide_modal_title">서비스 이용 전\n반드시 확인해주세요.</string>

data/travel/src/main/java/com/yapp/ndgl/data/travel/repository/TravelTemplateRepository.kt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,14 @@ import javax.inject.Singleton
1818
class TravelTemplateRepository @Inject constructor(
1919
private val travelTemplateApi: TravelTemplateApi,
2020
) {
21-
suspend fun getAllPopularTravelTemplates(): PopularTravelTemplates {
22-
return travelTemplateApi.getPopularTravelTemplates().getData()
21+
suspend fun getAllPopularTravelTemplates(page: Int = 0): PopularTravelTemplates {
22+
return travelTemplateApi.getPopularTravelTemplates(page = page).getData()
2323
}
2424

25-
suspend fun getPopularTravelTemplates(travelProgramId: Long): PopularTravelTemplates {
25+
suspend fun getPopularTravelTemplates(travelProgramId: Long, page: Int = 0): PopularTravelTemplates {
2626
return travelTemplateApi.getPopularTravelTemplates(
2727
travelProgramId = travelProgramId,
28+
page = page,
2829
).getData()
2930
}
3031

Lines changed: 43 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.yapp.ndgl.feature.home.popular
22

33
import androidx.compose.runtime.Immutable
4+
import androidx.compose.runtime.Stable
45
import com.yapp.ndgl.core.base.UiIntent
56
import com.yapp.ndgl.core.base.UiSideEffect
67
import com.yapp.ndgl.core.base.UiState
@@ -9,32 +10,50 @@ import com.yapp.ndgl.feature.home.model.TravelProgramTab
910
import kotlinx.collections.immutable.ImmutableList
1011
import kotlinx.collections.immutable.ImmutableMap
1112
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-
)
13+
14+
@Stable
15+
sealed class PopularTravelListState : UiState {
16+
data object Loading : PopularTravelListState()
17+
18+
@Immutable
19+
data class Success(
20+
val travelProgramTabs: ImmutableList<TravelProgramTab>,
21+
val allPopularTravels: ImmutableList<PopularTravelListItem>,
22+
val popularTravelsByProgram: ImmutableMap<Long, ImmutableList<PopularTravelListItem>>,
23+
val selectedTabIndex: Int = 0,
24+
) : PopularTravelListState() {
25+
val selectedProgramTravels: ImmutableList<PopularTravelListItem> by lazy {
26+
val selectTab = travelProgramTabs.getOrElse(selectedTabIndex) { TravelProgramTab.All }
27+
28+
when (selectTab) {
29+
TravelProgramTab.All -> allPopularTravels
30+
is TravelProgramTab.Custom -> popularTravelsByProgram.getOrDefault(
31+
selectTab.programId,
32+
persistentListOf(),
33+
)
34+
}
35+
}
36+
37+
sealed interface PopularTravelListItem {
38+
data class Travel(
39+
val travelContent: TravelContent,
40+
) : PopularTravelListItem
41+
42+
data class Loading(
43+
val nextPage: Int,
44+
) : PopularTravelListItem
3045
}
3146
}
47+
48+
data object Error : PopularTravelListState()
3249
}
3350

3451
sealed interface PopularTravelListIntent : UiIntent {
3552
data object ClickSearchTravelTemplate : PopularTravelListIntent
3653
data class SelectPopularTravelTab(val index: Int) : PopularTravelListIntent
3754
data class ClickTravel(val travelId: Long, val days: Int) : PopularTravelListIntent
55+
data class LoadMore(val nextPage: Int) : PopularTravelListIntent
56+
data object ClickRetry : PopularTravelListIntent
3857
}
3958

4059
sealed interface PopularTravelListSideEffect : UiSideEffect {
@@ -43,4 +62,10 @@ sealed interface PopularTravelListSideEffect : UiSideEffect {
4362
val travelId: Long,
4463
val days: Int,
4564
) : PopularTravelListSideEffect
65+
66+
data class ShowSnackBar(val type: Type) : PopularTravelListSideEffect {
67+
enum class Type {
68+
ERR_UNKNOWN,
69+
}
70+
}
4671
}

0 commit comments

Comments
 (0)