diff --git a/core/common-ui/src/main/java/com/puzzle/common/ui/CollapsingHeaderNestedScrollConnection.kt b/core/common-ui/src/main/java/com/puzzle/common/ui/CollapsingHeaderNestedScrollConnection.kt
new file mode 100644
index 00000000..e80acf7d
--- /dev/null
+++ b/core/common-ui/src/main/java/com/puzzle/common/ui/CollapsingHeaderNestedScrollConnection.kt
@@ -0,0 +1,37 @@
+package com.puzzle.common.ui
+
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableIntStateOf
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
+import androidx.compose.ui.input.nestedscroll.NestedScrollSource
+
+class CollapsingHeaderNestedScrollConnection(
+ val headerHeight: Int
+) : NestedScrollConnection {
+
+ // 헤더 offset(픽셀 단위), 0이면 펼침, -headerHeight이면 완전 접힘
+ var headerOffset: Int by mutableIntStateOf(0)
+ private set
+
+ // 스크롤 이벤트가 오기 전, 먼저 얼마나 소모할지 계산
+ override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
+ // y축 델타(수직 스크롤 양)
+ val delta = available.y.toInt()
+
+ // 새 offset = 기존 offset + 스크롤 델타
+ val newOffset = headerOffset + delta
+ val previousOffset = headerOffset
+
+ // -headerHeight ~ 0 사이로 제한
+ // -> 최소 -105: 완전히 접힘, 최대 0: 완전히 펼침
+ headerOffset = newOffset.coerceIn(-headerHeight, 0)
+
+ // 소비(consumed)된 스크롤 양 = (바뀐 offset - 기존 offset)
+ val consumed = headerOffset - previousOffset
+
+ // x축은 소비 안 함(0f), y축은 consumed만큼 소비했다고 반환
+ return Offset(0f, consumed.toFloat())
+ }
+}
diff --git a/core/designsystem/src/main/java/com/puzzle/designsystem/component/Button.kt b/core/designsystem/src/main/java/com/puzzle/designsystem/component/Button.kt
index 980816cd..18eb1887 100644
--- a/core/designsystem/src/main/java/com/puzzle/designsystem/component/Button.kt
+++ b/core/designsystem/src/main/java/com/puzzle/designsystem/component/Button.kt
@@ -90,8 +90,8 @@ fun PieceSubButton(
colors = ButtonDefaults.buttonColors(
containerColor = PieceTheme.colors.primaryLight,
contentColor = PieceTheme.colors.primaryDefault,
- disabledContainerColor = PieceTheme.colors.light1,
- disabledContentColor = PieceTheme.colors.white,
+ disabledContainerColor = PieceTheme.colors.light3,
+ disabledContentColor = PieceTheme.colors.dark2,
),
modifier = modifier.height(52.dp),
) {
diff --git a/core/designsystem/src/main/java/com/puzzle/designsystem/component/TopBar.kt b/core/designsystem/src/main/java/com/puzzle/designsystem/component/TopBar.kt
index 4d933dc7..6588ede2 100644
--- a/core/designsystem/src/main/java/com/puzzle/designsystem/component/TopBar.kt
+++ b/core/designsystem/src/main/java/com/puzzle/designsystem/component/TopBar.kt
@@ -209,4 +209,4 @@ fun PreviewPieceSubCloseTopBar() {
.padding(vertical = 20.dp),
)
}
-}
\ No newline at end of file
+}
diff --git a/core/designsystem/src/main/res/drawable/ic_image_default.xml b/core/designsystem/src/main/res/drawable/ic_image_default.xml
index 50fc3426..cb580b72 100644
--- a/core/designsystem/src/main/res/drawable/ic_image_default.xml
+++ b/core/designsystem/src/main/res/drawable/ic_image_default.xml
@@ -4,27 +4,31 @@
android:height="120dp"
android:viewportWidth="120"
android:viewportHeight="120">
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
diff --git a/core/designsystem/src/main/res/drawable/ic_profile_image.xml b/core/designsystem/src/main/res/drawable/ic_profile_image.xml
new file mode 100644
index 00000000..edf42ce9
--- /dev/null
+++ b/core/designsystem/src/main/res/drawable/ic_profile_image.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/core/designsystem/src/main/res/drawable/ic_question.xml b/core/designsystem/src/main/res/drawable/ic_question.xml
new file mode 100644
index 00000000..31ec4b74
--- /dev/null
+++ b/core/designsystem/src/main/res/drawable/ic_question.xml
@@ -0,0 +1,14 @@
+
+
+
+
diff --git a/core/designsystem/src/main/res/values/strings.xml b/core/designsystem/src/main/res/values/strings.xml
index 0b807c26..c5f0d6cf 100644
--- a/core/designsystem/src/main/res/values/strings.xml
+++ b/core/designsystem/src/main/res/values/strings.xml
@@ -21,4 +21,9 @@
활동 지역
직업
흡연
+ 전체
+ 나와 같은
+ 나와 다른
+ 매칭 거절하기
+ 나와 같은
\ No newline at end of file
diff --git a/feature/matching/src/main/java/com/puzzle/matching/MatchingScreen.kt b/feature/matching/src/main/java/com/puzzle/matching/MatchingScreen.kt
index bfed3102..9db06406 100644
--- a/feature/matching/src/main/java/com/puzzle/matching/MatchingScreen.kt
+++ b/feature/matching/src/main/java/com/puzzle/matching/MatchingScreen.kt
@@ -36,12 +36,12 @@ import androidx.compose.ui.unit.dp
import com.airbnb.mvrx.compose.collectAsState
import com.airbnb.mvrx.compose.mavericksViewModel
import com.puzzle.common.ui.verticalScrollbar
+import com.puzzle.designsystem.R
import com.puzzle.designsystem.component.PieceMainTopBar
import com.puzzle.designsystem.component.PieceSolidButton
import com.puzzle.designsystem.foundation.PieceTheme
import com.puzzle.matching.contract.MatchingIntent
import com.puzzle.matching.contract.MatchingState
-import com.puzzle.designsystem.R
@Composable
internal fun MatchingRoute(
diff --git a/feature/matching/src/main/java/com/puzzle/matching/detail/MatchingDetailRoute.kt b/feature/matching/src/main/java/com/puzzle/matching/detail/MatchingDetailRoute.kt
index c60bebed..e618f25c 100644
--- a/feature/matching/src/main/java/com/puzzle/matching/detail/MatchingDetailRoute.kt
+++ b/feature/matching/src/main/java/com/puzzle/matching/detail/MatchingDetailRoute.kt
@@ -58,6 +58,9 @@ internal fun MatchingDetailRoute(
onPreviousPageClick = { viewModel.onIntent(MatchingDetailIntent.OnPreviousPageClick) },
onNextPageClick = { viewModel.onIntent(MatchingDetailIntent.OnNextPageClick) },
onMoreClick = { viewModel.onIntent(MatchingDetailIntent.OnMoreClick) },
+ onDeclineClick = { },
+ onAcceptClick = { },
+ onShowPicturesClick = { },
)
}
@@ -68,6 +71,9 @@ private fun MatchingDetailScreen(
onPreviousPageClick: () -> Unit,
onNextPageClick: () -> Unit,
onMoreClick: () -> Unit,
+ onDeclineClick: () -> Unit,
+ onShowPicturesClick: () -> Unit,
+ onAcceptClick: () -> Unit,
modifier: Modifier = Modifier,
) {
var showDialog by remember { mutableStateOf(false) }
@@ -163,6 +169,7 @@ private fun MatchingDetailScreen(
MatchingDetailContent(
state = state,
onMoreClick = onMoreClick,
+ onDeclineClick = onDeclineClick,
modifier = Modifier
.fillMaxSize()
.padding(top = topBarHeight, bottom = bottomBarHeight),
@@ -171,9 +178,7 @@ private fun MatchingDetailScreen(
PieceSubCloseTopBar(
title = state.currentPage.title,
onCloseClick = onCloseClick,
- showCloseButton = if (showDialog && dialogType == DialogType.PROFILE_IMAGE_DETAIL) {
- false
- } else true,
+ showCloseButton = !(showDialog && dialogType == DialogType.PROFILE_IMAGE_DETAIL),
modifier = Modifier
.fillMaxWidth()
.height(topBarHeight)
@@ -196,10 +201,12 @@ private fun MatchingDetailScreen(
onShowPicturesClick = {
dialogType = DialogType.PROFILE_IMAGE_DETAIL
showDialog = true
+ onShowPicturesClick()
},
onAcceptClick = {
dialogType = DialogType.ACCEPT_MATCHING
showDialog = true
+ onAcceptClick()
},
modifier = Modifier
.fillMaxWidth()
@@ -221,8 +228,8 @@ private fun BackgroundImage(modifier: Modifier = Modifier) {
Image(
painter = painterResource(id = R.drawable.matchingdetail_bg),
contentDescription = "basic info 배경화면",
- modifier = Modifier.matchParentSize(),
contentScale = ContentScale.Crop,
+ modifier = Modifier.matchParentSize(),
)
}
}
@@ -231,11 +238,12 @@ private fun BackgroundImage(modifier: Modifier = Modifier) {
private fun MatchingDetailContent(
state: MatchingDetailState,
onMoreClick: () -> Unit,
+ onDeclineClick: () -> Unit,
modifier: Modifier = Modifier,
) {
Box(modifier = modifier.fillMaxSize()) {
when (state.currentPage) {
- MatchingDetailState.MatchingDetailPage.BasicInfoState -> {
+ MatchingDetailState.MatchingDetailPage.BasicInfoState ->
BasicInfoBody(
nickName = state.nickName,
selfDescription = state.selfDescription,
@@ -247,24 +255,24 @@ private fun MatchingDetailContent(
occupation = state.occupation,
smokeStatue = state.smokeStatue,
onMoreClick = onMoreClick,
- modifier = Modifier.padding(horizontal = 20.dp)
+ modifier = Modifier.padding(horizontal = 20.dp),
)
- }
- MatchingDetailState.MatchingDetailPage.ValueTalkState -> {
+ MatchingDetailState.MatchingDetailPage.ValueTalkState ->
ValueTalkBody(
nickName = state.nickName,
selfDescription = state.selfDescription,
talkCards = state.talkCards,
- onMoreClick = onMoreClick
+ onMoreClick = onMoreClick,
)
- }
- MatchingDetailState.MatchingDetailPage.ValuePickState -> {
+ MatchingDetailState.MatchingDetailPage.ValuePickState ->
ValuePickBody(
- pickCards = state.pickCards
+ nickName = state.nickName,
+ selfDescription = state.selfDescription,
+ pickCards = state.pickCards,
+ onDeclineClick = onDeclineClick,
)
- }
}
}
}
@@ -284,7 +292,7 @@ private fun MatchingDetailBottomBar(
) {
if (currentPage == MatchingDetailPage.ValuePickState) {
Image(
- painter = painterResource(id = R.drawable.ic_profile_image_temp),
+ painter = painterResource(id = R.drawable.ic_profile_image),
contentDescription = "이전 페이지 버튼",
modifier = Modifier
.size(52.dp)
@@ -346,6 +354,9 @@ private fun MatchingDetailScreenPreview() {
{},
{},
{},
+ {},
+ {},
+ {},
)
}
}
diff --git a/feature/matching/src/main/java/com/puzzle/matching/detail/component/ValueTalkHeader.kt b/feature/matching/src/main/java/com/puzzle/matching/detail/component/BasicInfoHeader.kt
similarity index 90%
rename from feature/matching/src/main/java/com/puzzle/matching/detail/component/ValueTalkHeader.kt
rename to feature/matching/src/main/java/com/puzzle/matching/detail/component/BasicInfoHeader.kt
index 52bdd91a..b04660fe 100644
--- a/feature/matching/src/main/java/com/puzzle/matching/detail/component/ValueTalkHeader.kt
+++ b/feature/matching/src/main/java/com/puzzle/matching/detail/component/BasicInfoHeader.kt
@@ -14,18 +14,17 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
+import com.puzzle.designsystem.R
import com.puzzle.designsystem.foundation.PieceTheme
@Composable
-internal fun ValueTalkHeader(
+internal fun BasicInfoHeader(
nickName: String,
selfDescription: String,
onMoreClick: () -> Unit,
modifier: Modifier = Modifier
) {
- Column(
- modifier = modifier,
- ) {
+ Column(modifier = modifier) {
Text(
text = selfDescription,
style = PieceTheme.typography.bodyMR,
@@ -45,7 +44,7 @@ internal fun ValueTalkHeader(
Spacer(modifier = Modifier.width(28.dp))
Image(
- painter = painterResource(id = com.puzzle.designsystem.R.drawable.ic_more),
+ painter = painterResource(id = R.drawable.ic_more),
contentDescription = "basic info 배경화면",
modifier = Modifier
.size(32.dp)
diff --git a/feature/matching/src/main/java/com/puzzle/matching/detail/content/BasicInfoBody.kt b/feature/matching/src/main/java/com/puzzle/matching/detail/content/BasicInfoBody.kt
index c4fe34d7..082701fd 100644
--- a/feature/matching/src/main/java/com/puzzle/matching/detail/content/BasicInfoBody.kt
+++ b/feature/matching/src/main/java/com/puzzle/matching/detail/content/BasicInfoBody.kt
@@ -21,7 +21,7 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.puzzle.designsystem.R
import com.puzzle.designsystem.foundation.PieceTheme
-import com.puzzle.matching.detail.component.ValueTalkHeader
+import com.puzzle.matching.detail.component.BasicInfoHeader
@Composable
internal fun BasicInfoBody(
@@ -64,7 +64,7 @@ private fun BasicInfoName(
nickName: String,
selfDescription: String,
onMoreClick: () -> Unit,
- modifier: Modifier = Modifier
+ modifier: Modifier = Modifier,
) {
Column(modifier = modifier) {
Text(
@@ -75,7 +75,7 @@ private fun BasicInfoName(
Spacer(modifier = Modifier.weight(1f))
- ValueTalkHeader(
+ BasicInfoHeader(
nickName = nickName,
selfDescription = selfDescription,
onMoreClick = onMoreClick,
@@ -194,11 +194,11 @@ private fun InfoItem(
text: @Composable () -> Unit? = {},
) {
Column(
+ horizontalAlignment = Alignment.CenterHorizontally,
modifier = modifier
.clip(RoundedCornerShape(8.dp))
.background(PieceTheme.colors.white)
.padding(vertical = 16.dp, horizontal = 12.dp),
- horizontalAlignment = Alignment.CenterHorizontally,
) {
Text(
text = title,
diff --git a/feature/matching/src/main/java/com/puzzle/matching/detail/content/ValuePickBody.kt b/feature/matching/src/main/java/com/puzzle/matching/detail/content/ValuePickBody.kt
index 563485c9..a7885903 100644
--- a/feature/matching/src/main/java/com/puzzle/matching/detail/content/ValuePickBody.kt
+++ b/feature/matching/src/main/java/com/puzzle/matching/detail/content/ValuePickBody.kt
@@ -1,75 +1,355 @@
package com.puzzle.matching.detail.content
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.lazy.itemsIndexed
+import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Tab
import androidx.compose.material3.TabRow
+import androidx.compose.material3.TabRowDefaults
+import androidx.compose.material3.TabRowDefaults.tabIndicatorOffset
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.derivedStateOf
+import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
+import androidx.compose.runtime.saveable.rememberSaveable
+import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.input.nestedscroll.nestedScroll
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
+import com.puzzle.common.ui.CollapsingHeaderNestedScrollConnection
+import com.puzzle.designsystem.R
+import com.puzzle.designsystem.component.PieceSubButton
import com.puzzle.designsystem.foundation.PieceTheme
import com.puzzle.domain.model.pick.ValuePick
+import com.puzzle.matching.detail.component.BasicInfoHeader
@Composable
internal fun ValuePickBody(
+ nickName: String,
+ selfDescription: String,
pickCards: List,
+ onDeclineClick: () -> Unit,
modifier: Modifier = Modifier,
) {
- val tabIndex = remember { mutableIntStateOf(0) }
+ val density = LocalDensity.current
- val tabTitles = listOf("전체", "나와 같은", "나와 다른")
+ val valuePickHeaderHeight = 104.dp
- Column(modifier = modifier.fillMaxSize()) {
- TabRow(
- selectedTabIndex = tabIndex.intValue,
- modifier = Modifier.fillMaxWidth(),
- ) {
- tabTitles.forEachIndexed { index, title ->
- Tab(
- selected = (tabIndex.intValue == index),
- onClick = { tabIndex.intValue = index },
- text = { Text(text = title) },
- )
+ val valuePickHeaderHeightPx = with(density) { valuePickHeaderHeight.roundToPx() }
+
+ val connection = remember(valuePickHeaderHeightPx) {
+ CollapsingHeaderNestedScrollConnection(valuePickHeaderHeightPx)
+ }
+
+ val spaceHeight by remember(density) {
+ derivedStateOf {
+ with(density) {
+ (valuePickHeaderHeightPx + connection.headerOffset).toDp()
}
}
+ }
+
+ val tabIndex = rememberSaveable { mutableIntStateOf(0) }
+
+ val tabTitles = listOf(
+ stringResource(R.string.valuepick_all),
+ stringResource(R.string.valuepick_same),
+ stringResource(R.string.valuepick_different),
+ )
+
+ Box(modifier = modifier.nestedScroll(connection)) {
+ Column {
+ Spacer(Modifier.height(spaceHeight))
- when (tabIndex.intValue) {
- 0 -> TabContent("전체 탭의 내용 예시...")
- 1 -> TabContent("나만 탭의 내용 예시...")
- 2 -> TabContent("너만 탭의 내용 예시...")
+ Column(
+ modifier = modifier.fillMaxSize(),
+ ) {
+ ValuePickTabRow(
+ tabIndex = tabIndex.intValue,
+ tabTitles = tabTitles,
+ onTabClick = { tabIndex.intValue = it.toInt() },
+ )
+
+ ValuePickTabContent(
+ tabIndex = tabIndex.intValue,
+ pickCards = pickCards,
+ onDeclineClick = onDeclineClick,
+ )
+ }
}
+
+ BasicInfoHeader(
+ nickName = nickName,
+ selfDescription = selfDescription,
+ onMoreClick = { },
+ modifier = Modifier
+ .offset { IntOffset(0, connection.headerOffset) }
+ .background(PieceTheme.colors.white)
+ .height(valuePickHeaderHeight)
+ .padding(
+ vertical = 20.dp,
+ horizontal = 20.dp
+ ),
+ )
+
+ Spacer(
+ modifier = Modifier
+ .height(1.dp)
+ .fillMaxWidth()
+ .background(PieceTheme.colors.light2)
+ .align(Alignment.TopCenter),
+ )
+ }
+}
+
+@Composable
+private fun ValuePickTabContent(
+ tabIndex: Int,
+ pickCards: List,
+ onDeclineClick: () -> Unit,
+) {
+ when (tabIndex) {
+ 0 ->
+ ValuePickCards(
+ pickCards = pickCards,
+ onDeclineClick = onDeclineClick,
+ )
+
+ 1 ->
+ ValuePickCards(
+ pickCards = pickCards.filter { it.isSimilarToMe },
+ onDeclineClick = onDeclineClick,
+ )
+
+ 2 ->
+ ValuePickCards(
+ pickCards = pickCards.filterNot { it.isSimilarToMe },
+ onDeclineClick = onDeclineClick,
+ )
}
}
@Composable
-private fun TabContent(contentText: String) {
+private fun ValuePickCards(
+ pickCards: List,
+ onDeclineClick: () -> Unit,
+) {
LazyColumn(
modifier = Modifier
.fillMaxSize()
- .padding(16.dp),
+ .background(PieceTheme.colors.light3)
+ .padding(horizontal = 20.dp),
) {
- items(15) { index ->
+ itemsIndexed(pickCards) { idx, item ->
+ Spacer(Modifier.height(20.dp))
+
+ ValuePickCard(
+ valuePick = item,
+ )
+ }
+
+ item {
+ Spacer(Modifier.height(60.dp))
+
Text(
- text = "$contentText 아이템 $index",
- modifier = Modifier.padding(vertical = 8.dp),
+ text = stringResource(R.string.valuepick_refuse),
+ style = PieceTheme.typography.bodyMM.copy(
+ textDecoration = TextDecoration.Underline
+ ),
+ color = PieceTheme.colors.dark3,
+ textAlign = TextAlign.Center,
+ modifier = Modifier
+ .fillMaxWidth()
+ .clickable {
+ onDeclineClick()
+ },
)
+
+ Spacer(Modifier.height(60.dp))
}
}
}
+@Composable
+private fun ValuePickTabRow(
+ tabIndex: Int,
+ onTabClick: (Int) -> Unit,
+ tabTitles: List
+) {
+ TabRow(
+ containerColor = PieceTheme.colors.white,
+ selectedTabIndex = tabIndex,
+ indicator = { tabPositions ->
+ if (tabIndex < tabPositions.size) {
+ TabRowDefaults.SecondaryIndicator(
+ color = PieceTheme.colors.black,
+ modifier = Modifier.tabIndicatorOffset(tabPositions[tabIndex]),
+ )
+ }
+ },
+ divider = {},
+ modifier = Modifier
+ .fillMaxWidth()
+ .height(48.dp),
+ ) {
+ tabTitles.forEachIndexed { index, title ->
+ Tab(
+ selected = (tabIndex == index),
+ onClick = { onTabClick(index) },
+ text = {
+ Text(
+ text = title,
+ style = PieceTheme.typography.bodyMM,
+ )
+ },
+ selectedContentColor = PieceTheme.colors.black,
+ unselectedContentColor = PieceTheme.colors.dark3,
+ )
+ }
+ }
+}
+
+@Composable
+private fun ValuePickCard(
+ valuePick: ValuePick,
+ modifier: Modifier = Modifier,
+) {
+ Column(
+ modifier = modifier
+ .clip(RoundedCornerShape(12.dp))
+ .background(PieceTheme.colors.white)
+ .padding(
+ horizontal = 20.dp,
+ vertical = 24.dp,
+ )
+ ) {
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ modifier = Modifier
+ .fillMaxWidth()
+ .height(28.dp),
+ ) {
+ Image(
+ painter = painterResource(id = R.drawable.ic_question),
+ contentDescription = "basic info 배경화면",
+ modifier = Modifier
+ .size(20.dp),
+ )
+
+ Spacer(modifier = modifier.width(6.dp))
+
+ Text(
+ text = valuePick.category,
+ style = PieceTheme.typography.bodySSB,
+ color = PieceTheme.colors.primaryDefault,
+ )
+
+ Spacer(modifier = modifier.weight(1f))
+
+ if (valuePick.isSimilarToMe) {
+ Text(
+ text = stringResource(R.string.valuepick_similar),
+ style = PieceTheme.typography.captionM,
+ color = PieceTheme.colors.subDefault,
+ textAlign = TextAlign.Center,
+ modifier = Modifier
+ .clip(RoundedCornerShape(23.dp))
+ .background(PieceTheme.colors.subLight)
+ .padding(vertical = 6.dp, horizontal = 12.dp),
+ )
+ }
+ }
+
+ Spacer(modifier = Modifier.height(12.dp))
+
+ Text(
+ text = valuePick.question,
+ style = PieceTheme.typography.headingMSB,
+ color = PieceTheme.colors.dark1,
+ )
+
+ Spacer(modifier = Modifier.height(24.dp))
+
+ PieceSubButton(
+ label = valuePick.option1,
+ onClick = {},
+ enabled = true,
+ modifier = Modifier.fillMaxWidth(),
+ )
+
+ Spacer(modifier = Modifier.height(8.dp))
+
+ PieceSubButton(
+ label = valuePick.option2,
+ onClick = {},
+ enabled = false,
+ modifier = Modifier.fillMaxWidth(),
+ )
+ }
+}
+
@Preview
@Composable
private fun ProfileValuePickBodyPreview() {
PieceTheme {
ValuePickBody(
- pickCards = emptyList()
+ nickName = "nickName",
+ selfDescription = "selfDescription",
+ pickCards = listOf(
+ ValuePick(
+ category = "음주",
+ question = "사귀는 사람과 함께 술을 마시는 것을 좋아하나요?",
+ option1 = "함께 술을 즐기고 싶어요",
+ option2 = "같이 술을 즐길 수 없어도 괜찮아요",
+ isSimilarToMe = true,
+ ),
+ ValuePick(
+ category = "만남 빈도",
+ question = "주말에 얼마나 자주 데이트를 하고싶나요?",
+ option1 = "주말에는 최대한 같이 있고 싶어요",
+ option2 = "하루 정도는 각자 보내고 싶어요",
+ isSimilarToMe = false,
+ ),
+ ValuePick(
+ category = "연락 빈도",
+ question = "연인 사이에 얼마나 자주 연락하는게 좋은가요?",
+ option1 = "바빠도 최대한 자주 연락하고 싶어요",
+ option2 = "연락은 생각날 때만 종종 해도 괜찮아요",
+ isSimilarToMe = true,
+ ),
+ ValuePick(
+ category = "연락 방식",
+ question = "연락할 때 어떤 방법을 더 좋아하나요?",
+ option1 = "전화보다는 문자나 카톡이 좋아요",
+ option2 = "문자나 카톡보다는 전화가 좋아요",
+ isSimilarToMe = false,
+ )
+ ),
+ onDeclineClick = {},
)
}
}
diff --git a/feature/matching/src/main/java/com/puzzle/matching/detail/content/ValueTalkBody.kt b/feature/matching/src/main/java/com/puzzle/matching/detail/content/ValueTalkBody.kt
index 61132413..569eba1b 100644
--- a/feature/matching/src/main/java/com/puzzle/matching/detail/content/ValueTalkBody.kt
+++ b/feature/matching/src/main/java/com/puzzle/matching/detail/content/ValueTalkBody.kt
@@ -18,25 +18,21 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
-import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
-import androidx.compose.ui.geometry.Offset
-import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
-import androidx.compose.ui.input.nestedscroll.NestedScrollSource
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
+import com.puzzle.common.ui.CollapsingHeaderNestedScrollConnection
import com.puzzle.designsystem.R
import com.puzzle.designsystem.foundation.PieceTheme
import com.puzzle.domain.model.value.ValueTalk
-import com.puzzle.matching.detail.component.ValueTalkHeader
+import com.puzzle.matching.detail.component.BasicInfoHeader
@Composable
internal fun ValueTalkBody(
@@ -48,7 +44,7 @@ internal fun ValueTalkBody(
) {
val density = LocalDensity.current
// 1) 고정 헤더 높이(105.dp)
- val valueTalkHeaderHeight = 105.dp
+ val valueTalkHeaderHeight = 104.dp
val valueTalkHeaderHeightPx = with(density) { valueTalkHeaderHeight.roundToPx() }
// 2) 헤더가 얼마나 접혔는지(offset)를 관리해주는 NestedScrollConnection
@@ -71,44 +67,31 @@ internal fun ValueTalkBody(
// 4) Box에 nestedScroll(connection)을 달아, 스크롤 이벤트가
// CollapsingHeaderNestedScrollConnection으로 전달되도록 함
- Box(modifier = modifier.nestedScroll(connection)) {
+ Box(
+ modifier = modifier.nestedScroll(connection)
+ ) {
// 5) Column: Spacer + LazyColumn을 세로로 배치
// 헤더가 접힐수록 Spacer의 높이가 줄어들고, 그만큼 리스트가 위로 올라옴
Column {
// 5-1) 헤더 높이만큼 Spacer를 줘서 리스트가 '헤더 아래'에서 시작
// 헤더 offset이 변하면, spaceHeight가 변해 리스트도 따라 위로 올라감
- Spacer(Modifier.height(spaceHeight))
-
- LazyColumn(
- modifier = Modifier
- .fillMaxSize()
- .background(PieceTheme.colors.light3)
- .padding(horizontal = 20.dp),
- ) {
- itemsIndexed(talkCards) { idx, item ->
- Spacer(Modifier.height(20.dp))
-
- ValueTalkCard(
- item = item,
- idx = idx,
- )
- }
-
- item {
- Spacer(Modifier.height(60.dp))
- }
- }
+ Spacer(
+ Modifier.height(spaceHeight)
+ )
+
+ ValueTalkCards(talkCards)
}
// 6) 실제 헤더 뷰
// offset을 통해 y축 이동 (headerOffset이 음수면 위로 올라가며 사라짐)
- ValueTalkHeader(
+ BasicInfoHeader(
nickName = nickName,
selfDescription = selfDescription,
onMoreClick = onMoreClick,
modifier = Modifier
.offset { IntOffset(0, connection.headerOffset) }
.background(PieceTheme.colors.white)
+ .height(valueTalkHeaderHeight)
.padding(
vertical = 20.dp,
horizontal = 20.dp
@@ -125,32 +108,26 @@ internal fun ValueTalkBody(
}
}
-private class CollapsingHeaderNestedScrollConnection(
- val headerHeight: Int
-) : NestedScrollConnection {
-
- // 헤더 offset(픽셀 단위), 0이면 펼침, -headerHeight이면 완전 접힘
- var headerOffset: Int by mutableIntStateOf(0)
- private set
-
- // 스크롤 이벤트가 오기 전, 먼저 얼마나 소모할지 계산
- override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
- // y축 델타(수직 스크롤 양)
- val delta = available.y.toInt()
-
- // 새 offset = 기존 offset + 스크롤 델타
- val newOffset = headerOffset + delta
- val previousOffset = headerOffset
-
- // -headerHeight ~ 0 사이로 제한
- // -> 최소 -105: 완전히 접힘, 최대 0: 완전히 펼침
- headerOffset = newOffset.coerceIn(-headerHeight, 0)
+@Composable
+private fun ValueTalkCards(talkCards: List) {
+ LazyColumn(
+ modifier = Modifier
+ .fillMaxSize()
+ .background(PieceTheme.colors.light3)
+ .padding(horizontal = 20.dp),
+ ) {
+ itemsIndexed(talkCards) { idx, item ->
+ Spacer(Modifier.height(20.dp))
- // 소비(consumed)된 스크롤 양 = (바뀐 offset - 기존 offset)
- val consumed = headerOffset - previousOffset
+ ValueTalkCard(
+ item = item,
+ idx = idx,
+ )
+ }
- // x축은 소비 안 함(0f), y축은 consumed만큼 소비했다고 반환
- return Offset(0f, consumed.toFloat())
+ item {
+ Spacer(Modifier.height(60.dp))
+ }
}
}
@@ -192,7 +169,8 @@ private fun ValueTalkCard(
Image(
painter = painterResource(id = icons[idxInRange]),
contentDescription = "basic info 배경화면",
- modifier = Modifier.size(60.dp),
+ modifier = Modifier
+ .size(60.dp),
)
Spacer(modifier = Modifier.height(24.dp))
@@ -212,7 +190,6 @@ private fun ValueTalkCard(
}
}
-
@Preview
@Composable
private fun ProfileValueTalkBodyPreview() {