Skip to content

Commit 3950e0d

Browse files
committed
[Feat] 검색 결과 화면 UI 작업
1 parent f34e5df commit 3950e0d

File tree

6 files changed

+119
-18
lines changed

6 files changed

+119
-18
lines changed

feature/search/src/main/java/team/ppac/search/detail/SearchDetailScreen.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ internal fun SearchDetailScreen(
7474
uiState.isLoading -> {
7575
SearchDetailLoadingContent(
7676
modifier = Modifier.fillMaxSize(),
77-
uiState = uiState
77+
isLoading = uiState.isLoading
7878
)
7979
}
8080

feature/search/src/main/java/team/ppac/search/detail/component/SearchDetailLoadingContent.kt

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,11 @@ import androidx.compose.ui.tooling.preview.Preview
2121
import androidx.compose.ui.unit.dp
2222
import team.ppac.common.android.util.showSkeleton
2323
import team.ppac.designsystem.foundation.FarmemeRadius
24-
import team.ppac.search.detail.mvi.SearchDetailUiState
2524

2625
@Composable
2726
internal fun SearchDetailLoadingContent(
2827
modifier: Modifier = Modifier,
29-
uiState: SearchDetailUiState,
28+
isLoading: Boolean,
3029
) {
3130
Column(
3231
modifier = modifier
@@ -38,7 +37,7 @@ internal fun SearchDetailLoadingContent(
3837
.height(18.dp)
3938
.padding(start = 20.dp)
4039
.clip(FarmemeRadius.Radius4.shape)
41-
.showSkeleton(isLoading = uiState.isLoading)
40+
.showSkeleton(isLoading = isLoading)
4241
)
4342
Spacer(modifier = Modifier.size(20.dp))
4443
Row(
@@ -56,23 +55,23 @@ internal fun SearchDetailLoadingContent(
5655
.fillMaxWidth()
5756
.height(210.dp)
5857
.clip(RoundedCornerShape(16.dp))
59-
.showSkeleton(isLoading = uiState.isLoading)
58+
.showSkeleton(isLoading = isLoading)
6059
)
6160
Spacer(modifier = Modifier.size(10.dp))
6261
Box(
6362
modifier = Modifier
6463
.fillMaxWidth()
6564
.height(18.dp)
6665
.clip(FarmemeRadius.Radius4.shape)
67-
.showSkeleton(isLoading = uiState.isLoading)
66+
.showSkeleton(isLoading = isLoading)
6867
)
6968
Spacer(modifier = Modifier.size(10.dp))
7069
Box(
7170
modifier = Modifier
7271
.width(80.dp)
7372
.height(18.dp)
7473
.clip(FarmemeRadius.Radius4.shape)
75-
.showSkeleton(isLoading = uiState.isLoading)
74+
.showSkeleton(isLoading = isLoading)
7675
)
7776
}
7877
}
@@ -86,7 +85,7 @@ private fun SearchDetailLoadingContentPreview() {
8685
Box(modifier = Modifier.background(Color.White)) {
8786
SearchDetailLoadingContent(
8887
modifier = Modifier.fillMaxSize(),
89-
uiState = SearchDetailUiState.INITIAL_STATE
88+
isLoading = true
9089
)
9190
}
9291
}

feature/search/src/main/java/team/ppac/search/result/SearchResultRoute.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@ internal fun SearchResultRoute(
1414
SearchResultScreen(
1515
modifier = modifier,
1616
uiState = uiState,
17-
onQueryChange = viewModel::updateSearchQuery
17+
onQueryChange = viewModel::updateSearchQuery,
18+
handleLoadStates = viewModel::handleLoadErrorStates,
19+
onRetryClick = {},
20+
onMemeClick = {},
21+
onCopyClick = { _, _ ->},
1822
)
1923
}
2024
}
Lines changed: 71 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,91 @@
11
package team.ppac.search.result
22

3+
import androidx.compose.foundation.layout.Column
4+
import androidx.compose.foundation.layout.PaddingValues
5+
import androidx.compose.foundation.layout.calculateEndPadding
6+
import androidx.compose.foundation.layout.calculateStartPadding
37
import androidx.compose.foundation.layout.fillMaxSize
8+
import androidx.compose.foundation.layout.padding
49
import androidx.compose.runtime.Composable
510
import androidx.compose.ui.Modifier
11+
import androidx.compose.ui.unit.LayoutDirection
12+
import androidx.paging.LoadStates
13+
import team.ppac.common.android.component.error.FarmemeErrorScreen
14+
import team.ppac.common.android.extension.collectPagingItemsWithHandleState
615
import team.ppac.designsystem.component.scaffold.FarmemeScaffold
16+
import team.ppac.designsystem.component.tabbar.TabBarHeight
717
import team.ppac.designsystem.component.toolbar.FarmemeSearchToolbar
18+
import team.ppac.search.detail.component.EmptyResultContent
19+
import team.ppac.search.detail.component.SearchDetailLoadingContent
20+
import team.ppac.search.detail.component.SearchDetailResultContent
821
import team.ppac.search.result.mvi.SearchResultUiState
922

1023
@Composable
1124
internal fun SearchResultScreen(
1225
modifier: Modifier = Modifier,
1326
uiState: SearchResultUiState,
27+
handleLoadStates: (LoadStates) -> Unit,
1428
onQueryChange: (String) -> Unit,
29+
onRetryClick: () -> Unit,
30+
onMemeClick: (String) -> Unit,
31+
onCopyClick: (String, String) -> Unit,
1532
) {
16-
FarmemeScaffold(
17-
modifier = modifier.fillMaxSize(),
18-
topBar = {
19-
FarmemeSearchToolbar(
20-
text = uiState.query,
21-
onTextChanged = onQueryChange
33+
val searchResults = uiState.searchResults.collectPagingItemsWithHandleState(handleLoadStates)
34+
35+
when {
36+
uiState.isError -> {
37+
FarmemeErrorScreen(
38+
modifier = Modifier
39+
.fillMaxSize()
40+
.padding(bottom = TabBarHeight),
41+
title = "정보를 불러오지 못 했어요.\n새로고침 해주세요.",
42+
onRetryClick = onRetryClick
2243
)
2344
}
24-
) {
2545

46+
else -> {
47+
FarmemeScaffold(
48+
modifier = modifier.fillMaxSize(),
49+
topBar = {
50+
FarmemeSearchToolbar(
51+
text = uiState.query,
52+
onTextChanged = onQueryChange
53+
)
54+
}
55+
) { paddingValues ->
56+
val innerPadding = PaddingValues(
57+
top = paddingValues.calculateTopPadding(),
58+
start = paddingValues.calculateStartPadding(LayoutDirection.Ltr),
59+
end = paddingValues.calculateEndPadding(LayoutDirection.Ltr),
60+
bottom = paddingValues.calculateBottomPadding() + TabBarHeight
61+
)
62+
63+
when {
64+
uiState.isLoading -> {
65+
SearchDetailLoadingContent(
66+
modifier = Modifier.fillMaxSize(),
67+
isLoading = uiState.isLoading
68+
)
69+
}
70+
71+
else -> {
72+
Column(
73+
modifier = Modifier.padding(innerPadding)
74+
) {
75+
if (uiState.totalMemeCount == 0) {
76+
EmptyResultContent()
77+
} else {
78+
SearchDetailResultContent(
79+
totalItemCount = uiState.totalMemeCount,
80+
searchResults = searchResults,
81+
onMemeClick = onMemeClick,
82+
onCopyClick = onCopyClick,
83+
)
84+
}
85+
}
86+
}
87+
}
88+
}
89+
}
2690
}
2791
}

feature/search/src/main/java/team/ppac/search/result/SearchResultViewModel.kt

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
package team.ppac.search.result
22

33
import androidx.lifecycle.SavedStateHandle
4+
import androidx.paging.LoadState
5+
import androidx.paging.LoadStates
46
import dagger.hilt.android.lifecycle.HiltViewModel
57
import team.ppac.common.android.base.BaseViewModel
8+
import team.ppac.errorhandling.FarmemeNetworkException
69
import team.ppac.search.result.mvi.SearchResultIntent
710
import team.ppac.search.result.mvi.SearchResultSideEffect
811
import team.ppac.search.result.mvi.SearchResultUiState
@@ -28,4 +31,25 @@ class SearchResultViewModel @Inject constructor(
2831
fun updateSearchQuery(query: String) {
2932
reduce { copy(query = query) }
3033
}
34+
35+
fun handleLoadErrorStates(loadStates: LoadStates) {
36+
val errorLoadState = arrayOf(
37+
loadStates.prepend,
38+
loadStates.append,
39+
loadStates.refresh
40+
).filterIsInstance(LoadState.Error::class.java).firstOrNull()
41+
42+
val exception = errorLoadState?.error
43+
if (exception != null) {
44+
when (exception) {
45+
is FarmemeNetworkException -> {
46+
updateErrorState(isError = true)
47+
}
48+
}
49+
}
50+
}
51+
52+
private fun updateErrorState(isError: Boolean) {
53+
reduce { copy(isError = isError) }
54+
}
3155
}
Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,26 @@
11
package team.ppac.search.result.mvi
22

3+
import androidx.paging.PagingData
4+
import kotlinx.coroutines.flow.Flow
5+
import kotlinx.coroutines.flow.flowOf
36
import team.ppac.common.android.base.UiState
7+
import team.ppac.search.detail.model.SearchResultUiModel
48

59
data class SearchResultUiState(
610
val isLoading: Boolean,
7-
val query: String
11+
val isError: Boolean,
12+
val query: String,
13+
val totalMemeCount: Int,
14+
val searchResults: Flow<PagingData<SearchResultUiModel>>,
815
) : UiState {
916

1017
companion object {
1118
val INITIAL_STATE = SearchResultUiState(
1219
isLoading = true,
13-
query = ""
20+
isError = false,
21+
query = "",
22+
totalMemeCount = 0,
23+
searchResults = flowOf(PagingData.empty()),
1424
)
1525
}
1626
}

0 commit comments

Comments
 (0)