Skip to content

Commit ab3b89a

Browse files
committed
feat: composable 세분화 작업
1 parent 58460c5 commit ab3b89a

File tree

2 files changed

+42
-242
lines changed

2 files changed

+42
-242
lines changed

feature/search/src/main/java/com/chan/search/ui/composables/result/SearchResultScreen.kt

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,8 @@ fun SearchResultScreen(
1111
) {
1212

1313
SearchResultScreenContent(
14-
products = state.searchResultProducts,
15-
filters = state.filter.filterChips,
16-
onToggleFilter = {
17-
onEvent(SearchContract.Event.Filter.OnFilterChipClicked(it))
18-
},
19-
onFilterClick = {
20-
onEvent(SearchContract.Event.Filter.OnFilterClick)
21-
},
14+
state = state,
15+
onEvent = onEvent,
2216
onProductClick = { productId ->
2317
onProductClick(productId)
2418
}

feature/search/src/main/java/com/chan/search/ui/composables/result/SearchResultScreenContent.kt

Lines changed: 40 additions & 234 deletions
Original file line numberDiff line numberDiff line change
@@ -1,75 +1,40 @@
11
package com.chan.search.ui.composables.result
22

33
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
114
import androidx.compose.foundation.layout.Column
12-
import androidx.compose.foundation.layout.Row
13-
import androidx.compose.foundation.layout.Spacer
145
import androidx.compose.foundation.layout.fillMaxSize
156
import androidx.compose.foundation.layout.fillMaxWidth
16-
import androidx.compose.foundation.layout.height
177
import androidx.compose.foundation.layout.padding
18-
import androidx.compose.foundation.layout.size
19-
import androidx.compose.foundation.layout.width
208
import androidx.compose.foundation.lazy.LazyColumn
219
import androidx.compose.foundation.lazy.LazyListScope
22-
import androidx.compose.foundation.lazy.items
2310
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
2811
import androidx.compose.material3.HorizontalDivider
29-
import androidx.compose.material3.Icon
30-
import androidx.compose.material3.MaterialTheme
3112
import androidx.compose.material3.Surface
3213
import androidx.compose.material3.Text
3314
import androidx.compose.runtime.Composable
3415
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
4016
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
4517
import androidx.compose.ui.unit.dp
46-
import coil.compose.AsyncImage
47-
import com.chan.android.ProductCard
4818
import com.chan.android.model.ProductModel
49-
import com.chan.android.ui.theme.LightGray
50-
import com.chan.android.ui.theme.Radius
5119
import com.chan.android.ui.theme.Spacing
5220
import com.chan.android.ui.theme.White
53-
import com.chan.android.ui.theme.appTypography
5421
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
5726

5827
@OptIn(ExperimentalFoundationApi::class)
5928
@Composable
6029
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,
6532
onProductClick: (String) -> Unit
6633
) {
67-
var selectedTabIndex by remember { mutableStateOf(0) }
68-
val tabs = listOf("상품", "후기", "콘텐츠")
6934
val lazyListState = rememberLazyListState()
7035

71-
LaunchedEffect(products) {
72-
if (products.isNotEmpty()) {
36+
LaunchedEffect(state.searchResultProducts) {
37+
if (state.searchResultProducts.isNotEmpty()) {
7338
lazyListState.scrollToItem(0)
7439
}
7540
}
@@ -79,10 +44,12 @@ fun SearchResultScreenContent(
7944
state = lazyListState
8045
) {
8146
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+
}
8653
)
8754
}
8855

@@ -92,216 +59,55 @@ fun SearchResultScreenContent(
9259
color = White
9360
) {
9461
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) },
9972
)
10073
HorizontalDivider(color = dividerColor, thickness = 1.dp)
10174
}
10275
}
10376
}
10477

105-
when (selectedTabIndex) {
78+
when (state.resultTabRow.resultSelectedTabIndex) {
10679
0 -> { // 상품
107-
item {
108-
SearchResultListHeader(products)
109-
}
110-
productGrid(
111-
products = products,
80+
productTabContent(
81+
products = state.searchResultProducts,
11282
onProductClick = onProductClick
11383
)
11484
}
11585

116-
1 -> { // 후기
117-
item { Text("후기 탭 내용") }
118-
}
119-
120-
2 -> { // 콘텐츠
121-
item { Text("콘텐츠 탭 내용") }
122-
}
86+
1 -> reviewTabContent()
87+
2 -> contentTabContent()
12388
}
12489
}
12590
}
12691

127-
private fun LazyListScope.productGrid(
92+
private fun LazyListScope.productTabContent(
12893
products: List<ProductModel>,
12994
onProductClick: (String) -> Unit
13095
) {
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)
15498
}
99+
productGrid(
100+
products = products,
101+
onProductClick = onProductClick
102+
)
155103
}
156104

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("후기 탭 내용") }
198107
}
199108

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("콘텐츠 탭 내용") }
305111
}
306112

307113
@Composable

0 commit comments

Comments
 (0)