1
1
package com.chan.search.ui.composables.result
2
2
3
3
import androidx.compose.foundation.ExperimentalFoundationApi
4
- import androidx.compose.foundation.background
5
- import androidx.compose.foundation.border
6
- import androidx.compose.foundation.clickable
7
- import androidx.compose.foundation.horizontalScroll
8
- import androidx.compose.foundation.interaction.MutableInteractionSource
9
- import androidx.compose.foundation.layout.Arrangement
10
- import androidx.compose.foundation.layout.Box
11
4
import androidx.compose.foundation.layout.Column
12
- import androidx.compose.foundation.layout.Row
13
- import androidx.compose.foundation.layout.Spacer
14
5
import androidx.compose.foundation.layout.fillMaxSize
15
6
import androidx.compose.foundation.layout.fillMaxWidth
16
- import androidx.compose.foundation.layout.height
17
7
import androidx.compose.foundation.layout.padding
18
- import androidx.compose.foundation.layout.size
19
- import androidx.compose.foundation.layout.width
20
8
import androidx.compose.foundation.lazy.LazyColumn
21
9
import androidx.compose.foundation.lazy.LazyListScope
22
- import androidx.compose.foundation.lazy.items
23
10
import androidx.compose.foundation.lazy.rememberLazyListState
24
- import androidx.compose.foundation.rememberScrollState
25
- import androidx.compose.foundation.shape.RoundedCornerShape
26
- import androidx.compose.material.icons.Icons
27
- import androidx.compose.material.icons.filled.ArrowDropDown
28
11
import androidx.compose.material3.HorizontalDivider
29
- import androidx.compose.material3.Icon
30
- import androidx.compose.material3.MaterialTheme
31
12
import androidx.compose.material3.Surface
32
13
import androidx.compose.material3.Text
33
14
import androidx.compose.runtime.Composable
34
15
import androidx.compose.runtime.LaunchedEffect
35
- import androidx.compose.runtime.getValue
36
- import androidx.compose.runtime.mutableStateOf
37
- import androidx.compose.runtime.remember
38
- import androidx.compose.runtime.setValue
39
- import androidx.compose.ui.Alignment
40
16
import androidx.compose.ui.Modifier
41
- import androidx.compose.ui.draw.clip
42
- import androidx.compose.ui.graphics.Color
43
- import androidx.compose.ui.platform.LocalDensity
44
- import androidx.compose.ui.text.font.FontWeight
45
17
import androidx.compose.ui.unit.dp
46
- import coil.compose.AsyncImage
47
- import com.chan.android.ProductCard
48
18
import com.chan.android.model.ProductModel
49
- import com.chan.android.ui.theme.LightGray
50
- import com.chan.android.ui.theme.Radius
51
19
import com.chan.android.ui.theme.Spacing
52
20
import com.chan.android.ui.theme.White
53
- import com.chan.android.ui.theme.appTypography
54
21
import com.chan.android.ui.theme.dividerColor
55
- import com.chan.search.ui.model.FilterChipType
56
- import com.chan.search.ui.model.SearchResultFilterChipModel
22
+ import com.chan.search.ui.composables.result.composables.FilterChipRow
23
+ import com.chan.search.ui.composables.result.composables.TabRow
24
+ import com.chan.search.ui.composables.result.composables.productGrid
25
+ import com.chan.search.ui.contract.SearchContract
57
26
58
27
@OptIn(ExperimentalFoundationApi ::class )
59
28
@Composable
60
29
fun SearchResultScreenContent (
61
- products : List <ProductModel >,
62
- filters : List <SearchResultFilterChipModel >,
63
- onToggleFilter : (SearchResultFilterChipModel ) -> Unit ,
64
- onFilterClick : () -> Unit ,
30
+ state : SearchContract .State ,
31
+ onEvent : (SearchContract .Event ) -> Unit ,
65
32
onProductClick : (String ) -> Unit
66
33
) {
67
- var selectedTabIndex by remember { mutableStateOf(0 ) }
68
- val tabs = listOf (" 상품" , " 후기" , " 콘텐츠" )
69
34
val lazyListState = rememberLazyListState()
70
35
71
- LaunchedEffect (products ) {
72
- if (products .isNotEmpty()) {
36
+ LaunchedEffect (state.searchResultProducts ) {
37
+ if (state.searchResultProducts .isNotEmpty()) {
73
38
lazyListState.scrollToItem(0 )
74
39
}
75
40
}
@@ -79,10 +44,12 @@ fun SearchResultScreenContent(
79
44
state = lazyListState
80
45
) {
81
46
item {
82
- SearchResultTabRow (
83
- tabs = tabs,
84
- selectedTabIndex = selectedTabIndex,
85
- onTabSelected = { selectedTabIndex = it }
47
+ TabRow (
48
+ tabs = state.resultTabRow.tabs,
49
+ selectedTabIndex = state.resultTabRow.resultSelectedTabIndex,
50
+ onTabSelected = { selectedTabIndex ->
51
+ onEvent(SearchContract .Event .TabRow .OnResultTabSelected (selectedTabIndex))
52
+ }
86
53
)
87
54
}
88
55
@@ -92,216 +59,55 @@ fun SearchResultScreenContent(
92
59
color = White
93
60
) {
94
61
Column {
95
- FilterChipsRow (
96
- filters = filters,
97
- onToggleFilter = onToggleFilter,
98
- onFilterClick = onFilterClick,
62
+ FilterChipRow (
63
+ filters = state.filter.filterChips,
64
+ onToggleFilter = {
65
+ onEvent(
66
+ SearchContract .Event .Filter .OnFilterChipClicked (
67
+ it
68
+ )
69
+ )
70
+ },
71
+ onFilterClick = { onEvent(SearchContract .Event .Filter .OnFilterClick ) },
99
72
)
100
73
HorizontalDivider (color = dividerColor, thickness = 1 .dp)
101
74
}
102
75
}
103
76
}
104
77
105
- when (selectedTabIndex ) {
78
+ when (state.resultTabRow.resultSelectedTabIndex ) {
106
79
0 -> { // 상품
107
- item {
108
- SearchResultListHeader (products)
109
- }
110
- productGrid(
111
- products = products,
80
+ productTabContent(
81
+ products = state.searchResultProducts,
112
82
onProductClick = onProductClick
113
83
)
114
84
}
115
85
116
- 1 -> { // 후기
117
- item { Text (" 후기 탭 내용" ) }
118
- }
119
-
120
- 2 -> { // 콘텐츠
121
- item { Text (" 콘텐츠 탭 내용" ) }
122
- }
86
+ 1 -> reviewTabContent()
87
+ 2 -> contentTabContent()
123
88
}
124
89
}
125
90
}
126
91
127
- private fun LazyListScope.productGrid (
92
+ private fun LazyListScope.productTabContent (
128
93
products : List <ProductModel >,
129
94
onProductClick : (String ) -> Unit
130
95
) {
131
- val chunkedProducts = products.chunked(2 )
132
- items(
133
- items = chunkedProducts,
134
- key = { row -> row.joinToString { it.productId } }
135
- ) { productRow ->
136
- Row (
137
- modifier = Modifier .fillMaxWidth(),
138
- horizontalArrangement = Arrangement .spacedBy(Spacing .spacing2)
139
- ) {
140
- productRow.forEach { product ->
141
- Box (modifier = Modifier .weight(1f )) {
142
- ProductCard (
143
- product = product,
144
- onClick = { onProductClick(product.productId) },
145
- onLikeClick = {},
146
- onCartClick = {}
147
- )
148
- }
149
- }
150
- if (productRow.size == 1 ) {
151
- Spacer (modifier = Modifier .weight(1f ))
152
- }
153
- }
96
+ item {
97
+ SearchResultListHeader (products)
154
98
}
99
+ productGrid(
100
+ products = products,
101
+ onProductClick = onProductClick
102
+ )
155
103
}
156
104
157
- @Composable
158
- fun CustomTab (
159
- title : String ,
160
- isSelected : Boolean ,
161
- onClick : () -> Unit ,
162
- modifier : Modifier = Modifier
163
- ) {
164
- var textWidth by remember { mutableStateOf(0 .dp) }
165
- val density = LocalDensity .current
166
-
167
- Box (
168
- modifier = modifier
169
- .clickable(
170
- interactionSource = remember { MutableInteractionSource () },
171
- indication = null ,
172
- onClick = onClick
173
- )
174
- .padding(horizontal = Spacing .spacing4)
175
- ) {
176
- Text (
177
- text = title,
178
- color = if (isSelected) Color .Black else Color .Gray ,
179
- style = MaterialTheme .appTypography.tab.copy(
180
- fontWeight = if (isSelected) FontWeight .Bold else FontWeight .Normal
181
- ),
182
- onTextLayout = { textLayoutResult ->
183
- textWidth = with (density) { textLayoutResult.size.width.toDp() }
184
- },
185
- modifier = Modifier
186
- .padding(vertical = Spacing .spacing4)
187
- .align(Alignment .Center )
188
- )
189
-
190
- Box (
191
- modifier = Modifier
192
- .width(textWidth)
193
- .height(2 .dp)
194
- .background(if (isSelected) Color .Black else Color .Transparent )
195
- .align(Alignment .BottomCenter )
196
- )
197
- }
105
+ private fun LazyListScope.reviewTabContent () {
106
+ item { Text (" 후기 탭 내용" ) }
198
107
}
199
108
200
- @Composable
201
- private fun SearchResultTabRow (
202
- tabs : List <String >,
203
- selectedTabIndex : Int ,
204
- onTabSelected : (Int ) -> Unit
205
- ) {
206
- Column (modifier = Modifier .background(Color .White )) {
207
- Row (
208
- modifier = Modifier .fillMaxWidth()
209
- ) {
210
- tabs.forEachIndexed { index, title ->
211
- CustomTab (
212
- title = title,
213
- isSelected = index == selectedTabIndex,
214
- onClick = { onTabSelected(index) },
215
- modifier = Modifier .weight(1f )
216
- )
217
- }
218
- }
219
- HorizontalDivider (color = dividerColor, thickness = 1 .dp)
220
- }
221
- }
222
-
223
- @Composable
224
- private fun FilterChipsRow (
225
- filters : List <SearchResultFilterChipModel >,
226
- onToggleFilter : (SearchResultFilterChipModel ) -> Unit ,
227
- onFilterClick : () -> Unit ,
228
- modifier : Modifier = Modifier ,
229
- ) {
230
- Box (modifier = modifier.fillMaxWidth()) {
231
- Row (
232
- modifier = Modifier
233
- .horizontalScroll(rememberScrollState())
234
- .padding(horizontal = Spacing .spacing4, vertical = Spacing .spacing2),
235
- horizontalArrangement = Arrangement .spacedBy(Spacing .spacing2),
236
- verticalAlignment = Alignment .CenterVertically
237
- ) {
238
- filters.forEach { filter ->
239
- FilterChip (
240
- filter = filter,
241
- onToggleFilter = onToggleFilter,
242
- onFilterClick = onFilterClick,
243
- )
244
- }
245
- }
246
- }
247
- }
248
-
249
- @Composable
250
- private fun FilterChip (
251
- filter : SearchResultFilterChipModel ,
252
- onToggleFilter : (SearchResultFilterChipModel ) -> Unit ,
253
- onFilterClick : () -> Unit ,
254
- ) {
255
- val interactionSource = remember { MutableInteractionSource () }
256
- val containerColor = if (filter.isSelected) Color .Black else Color .White
257
- val textColor = if (filter.isSelected) Color .White else Color .DarkGray
258
-
259
- Box (
260
- modifier = Modifier
261
- .background(color = containerColor, shape = RoundedCornerShape (Radius .radius6))
262
- .clip(RoundedCornerShape (Radius .radius6))
263
- .border(width = 1 .dp, color = LightGray , shape = RoundedCornerShape (Radius .radius6))
264
- .clickable(
265
- interactionSource = interactionSource,
266
- indication = null ,
267
- onClick = {
268
- when (filter.chipType) {
269
- FilterChipType .TOGGLE -> onToggleFilter(filter)
270
- FilterChipType .DROP_DOWN -> onFilterClick()
271
- }
272
- }
273
- )
274
- .padding(horizontal = Spacing .spacing3, vertical = Spacing .spacing2)
275
- ) {
276
- Row (verticalAlignment = Alignment .CenterVertically ) {
277
- when (filter.chipType) {
278
- FilterChipType .TOGGLE -> {
279
- AsyncImage (
280
- model = filter.image,
281
- contentDescription = filter.text,
282
- modifier = Modifier
283
- .size(Spacing .spacing5)
284
- .padding(end = Spacing .spacing1)
285
- )
286
- Text (text = filter.text, color = textColor)
287
- }
288
-
289
- FilterChipType .DROP_DOWN -> {
290
- Text (
291
- text = filter.text,
292
- color = textColor,
293
- modifier = Modifier .padding(end = Spacing .spacing1)
294
- )
295
- Icon (
296
- imageVector = Icons .Default .ArrowDropDown ,
297
- contentDescription = " Dropdown" ,
298
- tint = textColor,
299
- modifier = Modifier .size(Spacing .spacing4)
300
- )
301
- }
302
- }
303
- }
304
- }
109
+ private fun LazyListScope.contentTabContent () {
110
+ item { Text (" 콘텐츠 탭 내용" ) }
305
111
}
306
112
307
113
@Composable
0 commit comments