diff --git a/core/designsystem/src/main/res/drawable/ic_alarm_black.xml b/core/designsystem/src/main/res/drawable/ic_alarm_black.xml new file mode 100644 index 00000000..7a4b701f --- /dev/null +++ b/core/designsystem/src/main/res/drawable/ic_alarm_black.xml @@ -0,0 +1,29 @@ + + + + + + diff --git a/core/designsystem/src/main/res/drawable/ic_arrow_right_black.xml b/core/designsystem/src/main/res/drawable/ic_arrow_right_black.xml new file mode 100644 index 00000000..273eb91a --- /dev/null +++ b/core/designsystem/src/main/res/drawable/ic_arrow_right_black.xml @@ -0,0 +1,13 @@ + + + diff --git a/core/designsystem/src/main/res/drawable/ic_question.xml b/core/designsystem/src/main/res/drawable/ic_question.xml index 31ec4b74..8d1667da 100644 --- a/core/designsystem/src/main/res/drawable/ic_question.xml +++ b/core/designsystem/src/main/res/drawable/ic_question.xml @@ -4,11 +4,11 @@ android:viewportWidth="20" android:viewportHeight="20"> + android:strokeColor="#1B1A2A" /> + android:fillColor="#1B1A2A" /> diff --git a/core/designsystem/src/main/res/drawable/ic_talk.xml b/core/designsystem/src/main/res/drawable/ic_talk.xml new file mode 100644 index 00000000..4adcbe30 --- /dev/null +++ b/core/designsystem/src/main/res/drawable/ic_talk.xml @@ -0,0 +1,12 @@ + + + diff --git a/core/designsystem/src/main/res/values/strings.xml b/core/designsystem/src/main/res/values/strings.xml index 8c73d806..93506708 100644 --- a/core/designsystem/src/main/res/values/strings.xml +++ b/core/designsystem/src/main/res/values/strings.xml @@ -53,10 +53,13 @@ 년생 + cm 종교 활동 지역 직업 흡연 + 몸무게 + kg 전체 나와 같은 나와 다른 @@ -91,4 +94,12 @@ 매칭 알림 푸쉬 알림 로그인 계정 + + + Profile + 나의 매칭 조각 + 가치관 Talk + 꿈과 목표, 관심사와 취향, 연애에 관련된\n내 생각을 확인하고 수정할 수 있습니다. + 가치관 Pick + 퀴즈를 통해 나의 연애 스타일을 파악해보고\n선택한 답변을 수정할 수 있습니다. \ No newline at end of file diff --git a/feature/matching/src/main/java/com/puzzle/matching/graph/detail/common/component/BasicInfoHeader.kt b/feature/matching/src/main/java/com/puzzle/matching/graph/detail/common/component/BasicInfoHeader.kt index 5c241cca..49c0a409 100644 --- a/feature/matching/src/main/java/com/puzzle/matching/graph/detail/common/component/BasicInfoHeader.kt +++ b/feature/matching/src/main/java/com/puzzle/matching/graph/detail/common/component/BasicInfoHeader.kt @@ -2,13 +2,10 @@ package com.puzzle.matching.graph.detail.common.component import androidx.compose.foundation.Image import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.width import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment @@ -25,15 +22,13 @@ internal fun BasicInfoHeader( onMoreClick: () -> Unit, modifier: Modifier = Modifier ) { - Column(modifier = modifier) { + Column(verticalArrangement = Arrangement.spacedBy(8.dp), modifier = modifier) { Text( text = selfDescription, style = PieceTheme.typography.bodyMR, color = PieceTheme.colors.black, ) - Spacer(modifier = Modifier.height(8.dp)) - Row(verticalAlignment = Alignment.CenterVertically) { Text( text = nickName, @@ -42,8 +37,6 @@ internal fun BasicInfoHeader( modifier = Modifier.weight(1f) ) - Spacer(modifier = Modifier.width(28.dp)) - Image( painter = painterResource(id = R.drawable.ic_more), contentDescription = "basic info 배경화면", diff --git a/feature/matching/src/main/java/com/puzzle/matching/graph/detail/page/BasicInfoPage.kt b/feature/matching/src/main/java/com/puzzle/matching/graph/detail/page/BasicInfoPage.kt index 71f8bfac..d3f92839 100644 --- a/feature/matching/src/main/java/com/puzzle/matching/graph/detail/page/BasicInfoPage.kt +++ b/feature/matching/src/main/java/com/puzzle/matching/graph/detail/page/BasicInfoPage.kt @@ -17,6 +17,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -52,10 +53,10 @@ internal fun BasicInfoPage( age = age, birthYear = birthYear, height = height, - religion = religion, activityRegion = activityRegion, occupation = occupation, smokeStatue = smokeStatue, + modifier = Modifier.padding(horizontal = 20.dp) ) } } @@ -67,12 +68,11 @@ private fun BasicInfoName( onMoreClick: () -> Unit, modifier: Modifier = Modifier, ) { - Column(modifier = modifier) { + Column(modifier = modifier.padding(horizontal = 20.dp)) { Text( text = stringResource(R.string.basicinfo_main_label), style = PieceTheme.typography.bodyMM, color = PieceTheme.colors.primaryDefault, - modifier = Modifier.padding(horizontal = 20.dp), ) Spacer(modifier = Modifier.weight(1f)) @@ -81,138 +81,133 @@ private fun BasicInfoName( nickName = nickName, selfDescription = selfDescription, onMoreClick = onMoreClick, - modifier = Modifier - .padding( - vertical = 20.dp, - horizontal = 20.dp - ), ) } } @Composable -private fun BasicInfoCard( +private fun ColumnScope.BasicInfoCard( age: String, birthYear: String, height: String, - religion: String, activityRegion: String, occupation: String, smokeStatue: String, modifier: Modifier = Modifier, ) { - Column( + Row( + horizontalArrangement = Arrangement.spacedBy(4.dp), modifier = modifier .fillMaxWidth() - .padding(horizontal = 20.dp, vertical = 12.dp), + .padding(top = 12.dp, bottom = 4.dp) ) { - Row( - horizontalArrangement = Arrangement.spacedBy(4.dp), - ) { - InfoItem( - title = stringResource(R.string.basicinfocard_age), - text = { - Row(verticalAlignment = Alignment.Bottom) { - Text( - text = stringResource(R.string.basicinfocard_age_particle), - style = PieceTheme.typography.bodySM, - color = PieceTheme.colors.black, - ) - - Spacer(modifier = Modifier.width(4.dp)) + InfoItem( + title = stringResource(R.string.basicinfocard_age), + text = { + Row(verticalAlignment = Alignment.CenterVertically) { + Text( + text = stringResource(R.string.basicinfocard_age_particle), + style = PieceTheme.typography.bodySM, + color = PieceTheme.colors.black, + ) - Text( - text = age, - style = PieceTheme.typography.headingSSB, - color = PieceTheme.colors.black, - ) + Spacer(modifier = Modifier.width(4.dp)) - Text( - text = stringResource(R.string.basicinfocard_age_classifier), - style = PieceTheme.typography.bodySM, - color = PieceTheme.colors.black, - ) + Text( + text = age, + style = PieceTheme.typography.headingSSB, + color = PieceTheme.colors.black, + ) - Spacer(modifier = Modifier.width(4.dp)) + Text( + text = stringResource(R.string.basicinfocard_age_classifier), + style = PieceTheme.typography.bodySM, + color = PieceTheme.colors.black, + ) - Text( - text = birthYear + stringResource(R.string.basicinfocard_age_suffix), - style = PieceTheme.typography.bodySM, - color = PieceTheme.colors.dark2, - modifier = Modifier.padding(top = 1.dp), - ) - } - }, - modifier = modifier.width(width = 144.dp), - ) + Spacer(modifier = Modifier.width(4.dp)) - InfoItem( - title = stringResource(R.string.basicinfocard_height), - text = { - Row(verticalAlignment = Alignment.Bottom) { - Text( - text = height, - style = PieceTheme.typography.headingSSB, - color = PieceTheme.colors.black, - ) + Text( + text = birthYear + stringResource(R.string.basicinfocard_age_suffix), + style = PieceTheme.typography.bodySM, + color = PieceTheme.colors.dark2, + modifier = Modifier.padding(top = 1.dp), + ) + } + }, + modifier = Modifier.size( + width = 144.dp, + height = 80.dp, + ), + ) - Text( - text = "cm", - style = PieceTheme.typography.bodySM, - color = PieceTheme.colors.black, - ) - } - }, - modifier = modifier.weight(1f), - ) + InfoItem( + title = stringResource(R.string.basicinfocard_height), + text = { + Row(verticalAlignment = Alignment.CenterVertically) { + Text( + text = height, + style = PieceTheme.typography.headingSSB, + color = PieceTheme.colors.black, + ) - InfoItem( - title = "몸무게", - text = { - Row(verticalAlignment = Alignment.Bottom) { - Text( - text = "72", - style = PieceTheme.typography.headingSSB, - color = PieceTheme.colors.black, - ) + Text( + text = "cm", + style = PieceTheme.typography.bodySM, + color = PieceTheme.colors.black, + ) + } + }, + modifier = Modifier.weight(1f), + ) - Text( - text = "kg", - style = PieceTheme.typography.bodySM, - color = PieceTheme.colors.black, - ) - } - }, - modifier = modifier.weight(1f), - ) - } + InfoItem( + title = "몸무게", + text = { + Row(verticalAlignment = Alignment.CenterVertically) { + Text( + text = "72", + style = PieceTheme.typography.headingSSB, + color = PieceTheme.colors.black, + ) - Spacer(modifier = Modifier.height(4.dp)) + Text( + text = "kg", + style = PieceTheme.typography.bodySM, + color = PieceTheme.colors.black, + ) + } + }, + modifier = Modifier.weight(1f), + ) + } - Row( - horizontalArrangement = Arrangement.spacedBy(5.5.dp), - ) { - InfoItem( - title = stringResource(R.string.basicinfocard_activityRegion), - content = activityRegion, - modifier = modifier.size( - width = 144.dp, - height = 80.dp, - ), - ) + Row( + horizontalArrangement = Arrangement.spacedBy(4.dp), + modifier = modifier + .fillMaxWidth() + .padding(bottom = 12.dp) + ) { + InfoItem( + title = stringResource(R.string.basicinfocard_activityRegion), + content = activityRegion, + modifier = Modifier.size( + width = 144.dp, + height = 80.dp, + ), + ) - InfoItem( - title = stringResource(R.string.basicinfocard_occupation), - content = occupation, - modifier = modifier.weight(1f), - ) + InfoItem( + title = stringResource(R.string.basicinfocard_occupation), + content = occupation, + modifier = Modifier.weight(1f), + ) - InfoItem( - title = stringResource(R.string.basicinfocard_smokeStatue), - content = smokeStatue, - modifier = modifier.weight(1f), - ) - } + InfoItem( + title = stringResource(R.string.basicinfocard_smokeStatue), + content = smokeStatue, + modifier = Modifier.weight(1f), + ) } } @@ -221,15 +216,20 @@ private fun InfoItem( title: String, modifier: Modifier = Modifier, content: String? = null, + backgroundColor: Color = PieceTheme.colors.white, text: @Composable ColumnScope.() -> Unit? = {}, ) { Column( + verticalArrangement = Arrangement.spacedBy( + space = 8.dp, + alignment = Alignment.CenterVertically + ), horizontalAlignment = Alignment.CenterHorizontally, modifier = modifier .height(80.dp) .clip(RoundedCornerShape(8.dp)) - .background(PieceTheme.colors.white) - .padding(vertical = 16.dp, horizontal = 12.dp), + .background(backgroundColor) + .padding(horizontal = 12.dp), ) { Text( text = title, @@ -237,8 +237,6 @@ private fun InfoItem( color = PieceTheme.colors.dark2, ) - Spacer(modifier = Modifier.height(8.dp)) - if (content != null) { Text( text = content, diff --git a/feature/profile/src/main/java/com/puzzle/profile/graph/home/ProfileScreen.kt b/feature/profile/src/main/java/com/puzzle/profile/graph/home/ProfileScreen.kt deleted file mode 100644 index 10a2f348..00000000 --- a/feature/profile/src/main/java/com/puzzle/profile/graph/home/ProfileScreen.kt +++ /dev/null @@ -1,25 +0,0 @@ -package com.puzzle.profile.graph.home - -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.unit.sp - -@Composable -internal fun ProfileRoute() { - ProfileScreen() -} - -@Composable -private fun ProfileScreen( -) { - Box( - modifier = Modifier.fillMaxSize(), - contentAlignment = Alignment.Center, - ) { - Text(text = "MyPageRoute", fontSize = 30.sp) - } -} \ No newline at end of file diff --git a/feature/profile/src/main/java/com/puzzle/profile/graph/main/MainProfileScreen.kt b/feature/profile/src/main/java/com/puzzle/profile/graph/main/MainProfileScreen.kt new file mode 100644 index 00000000..4845854f --- /dev/null +++ b/feature/profile/src/main/java/com/puzzle/profile/graph/main/MainProfileScreen.kt @@ -0,0 +1,464 @@ +package com.puzzle.profile.graph.main + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ColumnScope +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.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.lifecycle.compose.LocalLifecycleOwner +import com.airbnb.mvrx.compose.collectAsState +import com.airbnb.mvrx.compose.mavericksViewModel +import com.puzzle.common.ui.repeatOnStarted +import com.puzzle.designsystem.R +import com.puzzle.designsystem.component.PieceMainTopBar +import com.puzzle.designsystem.foundation.PieceTheme +import com.puzzle.profile.graph.main.contract.MainProfileSideEffect +import com.puzzle.profile.graph.main.contract.MainProfileState + +@Composable +internal fun MainProfileRoute( + viewModel: MainProfileViewModel = mavericksViewModel() +) { + val state by viewModel.collectAsState() + val lifecycleOwner = LocalLifecycleOwner.current + + LaunchedEffect(viewModel) { + lifecycleOwner.repeatOnStarted { + viewModel.sideEffects.collect { sideEffect -> + when (sideEffect) { + is MainProfileSideEffect.Navigate -> + viewModel.navigationHelper.navigate(sideEffect.navigationEvent) + } + } + } + } + + MainProfileScreen( + state = state, + onMyProfileClick = {}, + onValueTalkClick = {}, + onValuePickClick = {}, + ) +} + +@Composable +private fun MainProfileScreen( + state: MainProfileState, + onMyProfileClick: () -> Unit, + onValueTalkClick: () -> Unit, + onValuePickClick: () -> Unit, + modifier: Modifier = Modifier, +) { + Column( + modifier = modifier + .fillMaxSize() + .background(PieceTheme.colors.white), + ) { + PieceMainTopBar( + title = stringResource(R.string.main_profile_topbar_title), + rightComponent = { + Image( + painter = painterResource(R.drawable.ic_alarm_black), + contentDescription = "알람", + ) + }, + modifier = Modifier.padding(vertical = 14.dp, horizontal = 20.dp), + ) + + MyProfile( + nickName = state.nickName, + selfDescription = state.selfDescription, + age = state.age, + birthYear = state.birthYear, + height = state.height, + activityRegion = state.activityRegion, + occupation = state.occupation, + smokeStatue = state.smokeStatue, + weight = state.weight, + onMyProfileClick = onMyProfileClick, + modifier = Modifier.padding(horizontal = 20.dp) + ) + + HorizontalDivider( + thickness = 12.dp, + color = PieceTheme.colors.light3, + ) + + MyMatchingPiece( + onValueTalkClick = onValueTalkClick, + onValuePickClick = onValuePickClick, + modifier = Modifier.padding(horizontal = 20.dp) + ) + } +} + +@Composable +private fun MyProfile( + nickName: String, + selfDescription: String, + age: String, + birthYear: String, + height: String, + activityRegion: String, + occupation: String, + smokeStatue: String, + weight: String, + onMyProfileClick: () -> Unit, + modifier: Modifier = Modifier, +) { + Row( + modifier = modifier + .padding(top = 20.dp) + .clickable { onMyProfileClick() } + ) { + Image( + painter = painterResource(R.drawable.ic_profile_default), + contentDescription = null, + modifier = Modifier.size(80.dp), + ) + + Column( + modifier = Modifier + .padding(vertical = 9.dp) + .padding(start = 20.dp) + .align(Alignment.CenterVertically), + ) { + Text( + text = selfDescription, + style = PieceTheme.typography.bodyMR, + modifier = Modifier.padding(bottom = 6.dp), + ) + + Text( + text = nickName, + color = PieceTheme.colors.primaryDefault, + style = PieceTheme.typography.headingLSB, + ) + } + + Spacer(modifier = Modifier.weight(1f)) + + Image( + painter = painterResource(R.drawable.ic_arrow_right_black), + contentDescription = null, + modifier = Modifier + .size(30.dp) + .align(Alignment.CenterVertically), + ) + } + + BasicInfoCard( + age = age, + birthYear = birthYear, + height = height, + activityRegion = activityRegion, + occupation = occupation, + smokeStatue = smokeStatue, + weight = weight, + modifier = modifier, + ) +} + +@Composable +private fun MyMatchingPiece( + onValueTalkClick: () -> Unit, + onValuePickClick: () -> Unit, + modifier: Modifier = Modifier, +) { + Text( + text = stringResource(R.string.main_profile_my_matching_piece_title), + style = PieceTheme.typography.bodyMM, + color = PieceTheme.colors.dark2, + modifier = modifier.padding(top = 24.dp, bottom = 12.dp), + ) + + MyMatchingPieceDetail( + imageId = R.drawable.ic_talk, + title = stringResource(R.string.main_profile_value_talk_title), + content = stringResource(R.string.main_profile_value_talk_content), + onMyMatchingPieceDetailClick = onValueTalkClick, + modifier = modifier.padding(vertical = 16.dp), + ) + + HorizontalDivider( + thickness = 1.dp, + color = PieceTheme.colors.light2, + modifier = modifier.fillMaxWidth(), + ) + + MyMatchingPieceDetail( + imageId = R.drawable.ic_question, + title = stringResource(R.string.main_profile_value_pick_title), + content = stringResource(R.string.main_profile_value_pick_content), + onMyMatchingPieceDetailClick = onValuePickClick, + modifier = modifier.padding(vertical = 16.dp), + ) +} + +@Composable +private fun MyMatchingPieceDetail( + imageId: Int, + title: String, + content: String, + onMyMatchingPieceDetailClick: () -> Unit, + modifier: Modifier = Modifier, +) { + Row( + modifier = modifier.clickable { + onMyMatchingPieceDetailClick() + }, + ) { + Column( + verticalArrangement = Arrangement.spacedBy(8.dp), + modifier = Modifier.weight(1f), + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + ) { + Image( + painter = painterResource(imageId), + contentDescription = null, + colorFilter = ColorFilter.tint(PieceTheme.colors.dark1), + modifier = Modifier.size(20.dp), + ) + + Text( + text = title, + style = PieceTheme.typography.headingSSB, + color = PieceTheme.colors.dark1, + modifier = Modifier.padding(start = 8.dp), + ) + } + + Text( + text = content, + style = PieceTheme.typography.captionM, + color = PieceTheme.colors.dark3, + modifier = Modifier.padding(start = 28.dp), + ) + } + + Image( + painter = painterResource(R.drawable.ic_arrow_right_black), + contentDescription = null, + modifier = Modifier.size(24.dp), + ) + } +} + +@Composable +private fun BasicInfoCard( + age: String, + birthYear: String, + height: String, + weight: String, + activityRegion: String, + occupation: String, + smokeStatue: String, + modifier: Modifier = Modifier, +) { + Row( + horizontalArrangement = Arrangement.spacedBy(4.dp), + modifier = modifier + .fillMaxWidth() + .padding(top = 24.dp, bottom = 4.dp), + ) { + InfoItem( + title = stringResource(R.string.basicinfocard_age), + text = { + Row(verticalAlignment = Alignment.CenterVertically) { + Text( + text = stringResource(R.string.basicinfocard_age_particle), + style = PieceTheme.typography.bodySM, + color = PieceTheme.colors.black, + ) + + Spacer(modifier = Modifier.width(4.dp)) + + Text( + text = age, + style = PieceTheme.typography.headingSSB, + color = PieceTheme.colors.black, + ) + + Text( + text = stringResource(R.string.basicinfocard_age_classifier), + style = PieceTheme.typography.bodySM, + color = PieceTheme.colors.black, + ) + + Spacer(modifier = Modifier.width(4.dp)) + + Text( + text = birthYear + stringResource(R.string.basicinfocard_age_suffix), + style = PieceTheme.typography.bodySM, + color = PieceTheme.colors.dark2, + modifier = Modifier.padding(top = 1.dp), + ) + } + }, + backgroundColor = PieceTheme.colors.light3, + modifier = Modifier.size( + width = 144.dp, + height = 80.dp, + ), + ) + + InfoItem( + title = stringResource(R.string.basicinfocard_height), + text = { + Row(verticalAlignment = Alignment.CenterVertically) { + Text( + text = height, + style = PieceTheme.typography.headingSSB, + color = PieceTheme.colors.black, + ) + + Text( + text = stringResource(R.string.basicinfocard_height_unit), + style = PieceTheme.typography.bodySM, + color = PieceTheme.colors.black, + ) + } + }, + backgroundColor = PieceTheme.colors.light3, + modifier = Modifier.weight(1f), + ) + + InfoItem( + title = stringResource(R.string.basicinfocard_weight), + text = { + Row(verticalAlignment = Alignment.CenterVertically) { + Text( + text = weight, + style = PieceTheme.typography.headingSSB, + color = PieceTheme.colors.black, + ) + + Text( + text = stringResource(R.string.basicinfocard_weight_unit), + style = PieceTheme.typography.bodySM, + color = PieceTheme.colors.black, + ) + } + }, + backgroundColor = PieceTheme.colors.light3, + modifier = Modifier.weight(1f), + ) + } + + Row( + horizontalArrangement = Arrangement.spacedBy(4.dp), + modifier = modifier + .fillMaxWidth() + .padding(bottom = 32.dp), + ) { + InfoItem( + title = stringResource(R.string.basicinfocard_activityRegion), + content = activityRegion, + backgroundColor = PieceTheme.colors.light3, + modifier = Modifier.size( + width = 144.dp, + height = 80.dp, + ), + ) + + InfoItem( + title = stringResource(R.string.basicinfocard_occupation), + content = occupation, + backgroundColor = PieceTheme.colors.light3, + modifier = Modifier.weight(1f), + ) + + InfoItem( + title = stringResource(R.string.basicinfocard_smokeStatue), + content = smokeStatue, + backgroundColor = PieceTheme.colors.light3, + modifier = Modifier.weight(1f), + ) + } +} + +@Composable +private fun InfoItem( + title: String, + modifier: Modifier = Modifier, + content: String? = null, + backgroundColor: Color = PieceTheme.colors.white, + text: @Composable ColumnScope.() -> Unit? = {}, +) { + Column( + verticalArrangement = Arrangement.spacedBy( + space = 8.dp, + alignment = Alignment.CenterVertically, + ), + horizontalAlignment = Alignment.CenterHorizontally, + modifier = modifier + .height(80.dp) + .clip(RoundedCornerShape(8.dp)) + .background(backgroundColor) + .padding(horizontal = 12.dp), + ) { + Text( + text = title, + style = PieceTheme.typography.bodySM, + color = PieceTheme.colors.dark2, + ) + + if (content != null) { + Text( + text = content, + style = PieceTheme.typography.headingSSB, + color = PieceTheme.colors.black, + ) + } else { + text() + } + } +} + +@Preview +@Composable +private fun ProfileScreenPreview() { + PieceTheme { + MainProfileScreen( + state = MainProfileState( + nickName = "수줍은 수달", + selfDescription = "음악과 요리를 좋아하는", + age = "14", + birthYear = "00", + height = "100", + activityRegion = "서울 특별시", + occupation = "개발자", + smokeStatue = "흡연", + ), + onMyProfileClick = {}, + onValueTalkClick = {}, + onValuePickClick = {}, + ) + } +} \ No newline at end of file diff --git a/feature/profile/src/main/java/com/puzzle/profile/graph/main/MainProfileViewModel.kt b/feature/profile/src/main/java/com/puzzle/profile/graph/main/MainProfileViewModel.kt new file mode 100644 index 00000000..53aea0a9 --- /dev/null +++ b/feature/profile/src/main/java/com/puzzle/profile/graph/main/MainProfileViewModel.kt @@ -0,0 +1,56 @@ +package com.puzzle.profile.graph.main + +import com.airbnb.mvrx.MavericksViewModel +import com.airbnb.mvrx.MavericksViewModelFactory +import com.airbnb.mvrx.hilt.AssistedViewModelFactory +import com.airbnb.mvrx.hilt.hiltMavericksViewModelFactory +import com.puzzle.domain.model.error.ErrorHelper +import com.puzzle.navigation.NavigationHelper +import com.puzzle.profile.graph.main.contract.MainProfileIntent +import com.puzzle.profile.graph.main.contract.MainProfileSideEffect +import com.puzzle.profile.graph.main.contract.MainProfileState +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.channels.Channel.Factory.BUFFERED +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.receiveAsFlow +import kotlinx.coroutines.launch + +class MainProfileViewModel @AssistedInject constructor( + @Assisted initialState: MainProfileState, + internal val navigationHelper: NavigationHelper, + private val errorHelper: ErrorHelper, +) : MavericksViewModel(initialState) { + + private val intents = Channel(BUFFERED) + private val _sideEffects = Channel(BUFFERED) + val sideEffects = _sideEffects.receiveAsFlow() + + init { + intents.receiveAsFlow() + .onEach(::processIntent) + .launchIn(viewModelScope) + } + + internal fun onIntent(intent: MainProfileIntent) = viewModelScope.launch { + intents.send(intent) + } + + private suspend fun processIntent(intent: MainProfileIntent) { + when (intent) { + is MainProfileIntent.Navigate -> _sideEffects.send(MainProfileSideEffect.Navigate(intent.navigationEvent)) + } + } + + @AssistedFactory + interface Factory : AssistedViewModelFactory { + override fun create(state: MainProfileState): MainProfileViewModel + } + + companion object : + MavericksViewModelFactory by hiltMavericksViewModelFactory() + +} \ No newline at end of file diff --git a/feature/profile/src/main/java/com/puzzle/profile/graph/main/contract/MainProfileIntent.kt b/feature/profile/src/main/java/com/puzzle/profile/graph/main/contract/MainProfileIntent.kt new file mode 100644 index 00000000..ec881372 --- /dev/null +++ b/feature/profile/src/main/java/com/puzzle/profile/graph/main/contract/MainProfileIntent.kt @@ -0,0 +1,7 @@ +package com.puzzle.profile.graph.main.contract + +import com.puzzle.navigation.NavigationEvent + +sealed class MainProfileIntent { + data class Navigate(val navigationEvent: NavigationEvent) : MainProfileIntent() +} \ No newline at end of file diff --git a/feature/profile/src/main/java/com/puzzle/profile/graph/main/contract/MainProfileSideEffect.kt b/feature/profile/src/main/java/com/puzzle/profile/graph/main/contract/MainProfileSideEffect.kt new file mode 100644 index 00000000..8f40711a --- /dev/null +++ b/feature/profile/src/main/java/com/puzzle/profile/graph/main/contract/MainProfileSideEffect.kt @@ -0,0 +1,7 @@ +package com.puzzle.profile.graph.main.contract + +import com.puzzle.navigation.NavigationEvent + +sealed class MainProfileSideEffect { + data class Navigate(val navigationEvent: NavigationEvent) : MainProfileSideEffect() +} diff --git a/feature/profile/src/main/java/com/puzzle/profile/graph/main/contract/MainProfileState.kt b/feature/profile/src/main/java/com/puzzle/profile/graph/main/contract/MainProfileState.kt new file mode 100644 index 00000000..3da8faa3 --- /dev/null +++ b/feature/profile/src/main/java/com/puzzle/profile/graph/main/contract/MainProfileState.kt @@ -0,0 +1,15 @@ +package com.puzzle.profile.graph.main.contract + +import com.airbnb.mvrx.MavericksState + +data class MainProfileState( + val selfDescription: String = "음악과 요리를 좋아하는", + val nickName: String = "수줍은 수달", + val age: String = "25", + val birthYear: String = "00", + val height: String = "180", + val weight: String = "72", + val activityRegion: String = "서울특별시", + val occupation: String = "프리랜서", + val smokeStatue: String = "비흡연", +) : MavericksState \ No newline at end of file diff --git a/feature/profile/src/main/java/com/puzzle/profile/navigation/ProfileNavigation.kt b/feature/profile/src/main/java/com/puzzle/profile/navigation/ProfileNavigation.kt index 9786da34..74122b73 100644 --- a/feature/profile/src/main/java/com/puzzle/profile/navigation/ProfileNavigation.kt +++ b/feature/profile/src/main/java/com/puzzle/profile/navigation/ProfileNavigation.kt @@ -5,13 +5,13 @@ import androidx.navigation.compose.composable import androidx.navigation.navigation import com.puzzle.navigation.ProfileGraph import com.puzzle.navigation.ProfileGraphDest -import com.puzzle.profile.graph.home.ProfileRoute +import com.puzzle.profile.graph.main.MainProfileRoute import com.puzzle.profile.graph.register.RegisterProfileRoute fun NavGraphBuilder.profileNavGraph() { navigation(startDestination = ProfileGraphDest.ProfileRoute) { composable { - ProfileRoute() + MainProfileRoute() } composable { diff --git a/feature/setting/src/main/java/com/puzzle/setting/graph/main/SettingScreen.kt b/feature/setting/src/main/java/com/puzzle/setting/graph/main/SettingScreen.kt index b5ee10a2..a3868c22 100644 --- a/feature/setting/src/main/java/com/puzzle/setting/graph/main/SettingScreen.kt +++ b/feature/setting/src/main/java/com/puzzle/setting/graph/main/SettingScreen.kt @@ -75,7 +75,7 @@ private fun SettingScreen( ) { PieceMainTopBar( title = stringResource(R.string.setting_screen), - modifier = Modifier.padding(horizontal = 20.dp), + modifier = Modifier.padding(horizontal = 20.dp, vertical = 19.dp), ) HorizontalDivider( diff --git a/presentation/src/main/java/com/puzzle/presentation/di/ViewModelsModule.kt b/presentation/src/main/java/com/puzzle/presentation/di/ViewModelsModule.kt index ef265705..1d0d7cf1 100644 --- a/presentation/src/main/java/com/puzzle/presentation/di/ViewModelsModule.kt +++ b/presentation/src/main/java/com/puzzle/presentation/di/ViewModelsModule.kt @@ -8,6 +8,7 @@ import com.puzzle.auth.graph.signup.SignUpViewModel import com.puzzle.auth.graph.verification.VerificationViewModel import com.puzzle.matching.graph.detail.MatchingDetailViewModel import com.puzzle.matching.graph.main.MatchingViewModel +import com.puzzle.profile.graph.main.MainProfileViewModel import com.puzzle.profile.graph.register.RegisterProfileViewModel import com.puzzle.setting.graph.main.SettingViewModel import com.puzzle.setting.graph.withdraw.WithdrawViewModel @@ -50,6 +51,11 @@ interface ViewModelsModule { @ViewModelKey(RegisterProfileViewModel::class) fun registerProfileViewModelFactory(factory: RegisterProfileViewModel.Factory): AssistedViewModelFactory<*, *> + @Binds + @IntoMap + @ViewModelKey(MainProfileViewModel::class) + fun mainProfileViewModelFactory(factory: MainProfileViewModel.Factory): AssistedViewModelFactory<*, *> + @Binds @IntoMap @ViewModelKey(SettingViewModel::class)