From e14d74f39e885ad3c1923bdaa5c0ce30bed620a9 Mon Sep 17 00:00:00 2001 From: arinming Date: Wed, 7 Feb 2024 18:29:35 +0900 Subject: [PATCH 1/9] =?UTF-8?q?FEAT:=20nav=20=EA=B2=BD=EB=A1=9C=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95=20(#101)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/navigation/NavGraph.kt | 14 +++++- .../presentation/navigation/NavRoutes.kt | 2 + .../ui/home/profile/MyProfileScreen.kt | 5 +- .../ui/profile/detail/ProfileDetailScreen.kt | 12 ++--- .../ui/profile/edit/ProfileEditScreen.kt | 50 +++++++++++++++++++ presentation/src/main/res/values/strings.xml | 7 +++ 6 files changed, 79 insertions(+), 11 deletions(-) create mode 100644 presentation/src/main/java/com/kusitms/presentation/ui/profile/edit/ProfileEditScreen.kt diff --git a/presentation/src/main/java/com/kusitms/presentation/navigation/NavGraph.kt b/presentation/src/main/java/com/kusitms/presentation/navigation/NavGraph.kt index 84e61ea..f321cd2 100644 --- a/presentation/src/main/java/com/kusitms/presentation/navigation/NavGraph.kt +++ b/presentation/src/main/java/com/kusitms/presentation/navigation/NavGraph.kt @@ -62,6 +62,7 @@ import com.kusitms.presentation.ui.notice.NoticeScreen import com.kusitms.presentation.ui.notice.detail.NoticeDetailScreen import com.kusitms.presentation.ui.notice.search.NoticeSearchScreen import com.kusitms.presentation.ui.profile.ProfileScreen +import com.kusitms.presentation.ui.profile.edit.ProfileEditScreen import com.kusitms.presentation.ui.profile.search.ProfileSearchScreen import com.kusitms.presentation.ui.setting.SettingMember import com.kusitms.presentation.ui.setting.SettingNonMember @@ -271,7 +272,10 @@ fun MainNavigation() { arguments = NavRoutes.MyProfileDetail.navArguments ) { MyProfileScreen( - onBack = { navController.navigateUp() } + onBack = { navController.navigateUp() }, + onClickModify = { + navController.navigate(NavRoutes.ProfileEdit.route) + } ) } @@ -362,7 +366,10 @@ fun MainNavigation() { arguments = NavRoutes.ProfileDetail.navArguments ) { ProfileDetailScreen( - onBack = { navController.navigateUp() } + onBack = { navController.navigateUp() }, + onClickModify = { + navController.navigate(NavRoutes.ProfileEdit.route) + } ) } @@ -381,6 +388,9 @@ fun MainNavigation() { ) } + kusitmsComposableWithAnimation(NavRoutes.ProfileEdit.route) { + ProfileEditScreen() + } kusitmsComposableWithAnimation(NavRoutes.ImageViewer.route) { diff --git a/presentation/src/main/java/com/kusitms/presentation/navigation/NavRoutes.kt b/presentation/src/main/java/com/kusitms/presentation/navigation/NavRoutes.kt index d4a7c04..6f15302 100644 --- a/presentation/src/main/java/com/kusitms/presentation/navigation/NavRoutes.kt +++ b/presentation/src/main/java/com/kusitms/presentation/navigation/NavRoutes.kt @@ -95,5 +95,7 @@ sealed class NavRoutes( fun createRoute(memberId: Int) = "ProfileDetail/${memberId}" } + object ProfileEdit : NavRoutes(route = "ProfileEdit") + object ImageViewer : NavRoutes("ImageViewer") } diff --git a/presentation/src/main/java/com/kusitms/presentation/ui/home/profile/MyProfileScreen.kt b/presentation/src/main/java/com/kusitms/presentation/ui/home/profile/MyProfileScreen.kt index ced8102..1ba7b6e 100644 --- a/presentation/src/main/java/com/kusitms/presentation/ui/home/profile/MyProfileScreen.kt +++ b/presentation/src/main/java/com/kusitms/presentation/ui/home/profile/MyProfileScreen.kt @@ -30,6 +30,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi fun MyProfileScreen( viewModel: MyProfileViewModel = hiltViewModel(), onBack: () -> Unit, + onClickModify: () -> Unit ) { val infoUser = viewModel.infoProfile val detailMemberInfo by viewModel.detailMemberInfo.collectAsStateWithLifecycle() @@ -44,7 +45,9 @@ fun MyProfileScreen( text = stringResource(id = R.string.profile_detail_edit), style = KusitmsTypo.current.Text_Medium, color = KusitmsColorPalette.current.Main400, - modifier = Modifier.clickable { /* 수정 */ } + modifier = Modifier.clickable { + onClickModify() + } ) } LazyColumn( diff --git a/presentation/src/main/java/com/kusitms/presentation/ui/profile/detail/ProfileDetailScreen.kt b/presentation/src/main/java/com/kusitms/presentation/ui/profile/detail/ProfileDetailScreen.kt index 3bf7520..84f39c6 100644 --- a/presentation/src/main/java/com/kusitms/presentation/ui/profile/detail/ProfileDetailScreen.kt +++ b/presentation/src/main/java/com/kusitms/presentation/ui/profile/detail/ProfileDetailScreen.kt @@ -27,6 +27,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi fun ProfileDetailScreen( viewModel: ProfileDetailViewModel = hiltViewModel(), onBack: () -> Unit, + onClickModify: () -> Unit ) { val profile by viewModel.profile.collectAsStateWithLifecycle() val isMember = viewModel.infoProfile @@ -47,14 +48,9 @@ fun ProfileDetailScreen( text = stringResource(id = R.string.profile_detail_edit), style = KusitmsTypo.current.Text_Medium, color = KusitmsColorPalette.current.Main400, - modifier = Modifier.clickable { /* 수정 */ } - ) - } else { - Text( - text = stringResource(id = R.string.profile_detail_block), - style = KusitmsTypo.current.Text_Medium, - color = KusitmsColorPalette.current.Grey400, - modifier = Modifier.clickable { /* 차단 */ } + modifier = Modifier.clickable { + onClickModify() + } ) } } diff --git a/presentation/src/main/java/com/kusitms/presentation/ui/profile/edit/ProfileEditScreen.kt b/presentation/src/main/java/com/kusitms/presentation/ui/profile/edit/ProfileEditScreen.kt new file mode 100644 index 0000000..7a6011b --- /dev/null +++ b/presentation/src/main/java/com/kusitms/presentation/ui/profile/edit/ProfileEditScreen.kt @@ -0,0 +1,50 @@ +package com.kusitms.presentation.ui.profile.edit + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import com.kusitms.presentation.R +import com.kusitms.presentation.common.ui.KusitsmTopBarBackTextWithIcon +import com.kusitms.presentation.common.ui.theme.KusitmsColorPalette +import com.kusitms.presentation.common.ui.theme.KusitmsTypo + +@Composable +fun ProfileEditScreen( +) { + Column { + KusitsmTopBarBackTextWithIcon( + text = stringResource(id = R.string.profile_edit_toolbar), + onBackClick = {}, + ) { + Text( + text = stringResource(id = R.string.profile_edit_modify), + style = KusitmsTypo.current.Text_Medium, + color = KusitmsColorPalette.current.Main400, + modifier = Modifier.clickable { + + } + ) + } + LazyColumn( + modifier = Modifier + .fillMaxSize() + .background(KusitmsColorPalette.current.Grey900) + ) { + + } + } + +} + +@Preview(showBackground = true, showSystemUi = true) +@Composable +fun ProfileEditScreenPreview() { + ProfileEditScreen() +} diff --git a/presentation/src/main/res/values/strings.xml b/presentation/src/main/res/values/strings.xml index 219146f..edd50c5 100644 --- a/presentation/src/main/res/values/strings.xml +++ b/presentation/src/main/res/values/strings.xml @@ -229,6 +229,13 @@ 궁금한 학회원 프로필을\n검색해보세요 + + 프로필 설정 + 수정 + + + + 출석 공지 From fb7d909dcbf6c15e4fc3cd431babecbbcff2bf50 Mon Sep 17 00:00:00 2001 From: arinming Date: Wed, 7 Feb 2024 19:13:35 +0900 Subject: [PATCH 2/9] =?UTF-8?q?FEAT:=20=ED=94=84=EB=A1=9C=ED=95=84=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95=20=ED=95=84=ED=84=B0=20=EB=B2=84=ED=8A=BC=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=20(#101)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/profile/edit/ProfileEditUiState.kt | 5 + .../profile/edit/ProfileEditViewModel.kt | 28 ++++ .../model/profile/edit/ProfileFilterList.kt | 11 ++ .../presentation/navigation/NavGraph.kt | 5 +- .../ui/profile/edit/ProfileEditScreen.kt | 129 +++++++++++++++++- presentation/src/main/res/values/strings.xml | 3 + 6 files changed, 177 insertions(+), 4 deletions(-) create mode 100644 presentation/src/main/java/com/kusitms/presentation/model/profile/edit/ProfileEditUiState.kt create mode 100644 presentation/src/main/java/com/kusitms/presentation/model/profile/edit/ProfileEditViewModel.kt create mode 100644 presentation/src/main/java/com/kusitms/presentation/model/profile/edit/ProfileFilterList.kt diff --git a/presentation/src/main/java/com/kusitms/presentation/model/profile/edit/ProfileEditUiState.kt b/presentation/src/main/java/com/kusitms/presentation/model/profile/edit/ProfileEditUiState.kt new file mode 100644 index 0000000..323d980 --- /dev/null +++ b/presentation/src/main/java/com/kusitms/presentation/model/profile/edit/ProfileEditUiState.kt @@ -0,0 +1,5 @@ +package com.kusitms.presentation.model.profile.edit + +data class ProfileEditUiState( + val currentSelectedProfileFilter: String = "", +) diff --git a/presentation/src/main/java/com/kusitms/presentation/model/profile/edit/ProfileEditViewModel.kt b/presentation/src/main/java/com/kusitms/presentation/model/profile/edit/ProfileEditViewModel.kt new file mode 100644 index 0000000..a8c3e2c --- /dev/null +++ b/presentation/src/main/java/com/kusitms/presentation/model/profile/edit/ProfileEditViewModel.kt @@ -0,0 +1,28 @@ +package com.kusitms.presentation.model.profile.edit + +import androidx.lifecycle.ViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import javax.inject.Inject + +@HiltViewModel +class ProfileEditViewModel @Inject constructor( + +) : ViewModel() { + private val _uiState = MutableStateFlow(ProfileEditUiState()) + val uiState: StateFlow = _uiState.asStateFlow() + + private val _expanded = MutableStateFlow(false) + val expended: StateFlow = _expanded.asStateFlow() + + fun changeSelectProfileFilter(category: String) { + _uiState.value = _uiState.value.copy(currentSelectedProfileFilter = category) + _expanded.value = false + } + + fun toggleExpanded() { + _expanded.value = !_expanded.value + } +} \ No newline at end of file diff --git a/presentation/src/main/java/com/kusitms/presentation/model/profile/edit/ProfileFilterList.kt b/presentation/src/main/java/com/kusitms/presentation/model/profile/edit/ProfileFilterList.kt new file mode 100644 index 0000000..55a4451 --- /dev/null +++ b/presentation/src/main/java/com/kusitms/presentation/model/profile/edit/ProfileFilterList.kt @@ -0,0 +1,11 @@ +package com.kusitms.presentation.model.profile.edit + +data class ProfileFilterList( + val id: Int, + val name: String, +) + +val categories = listOf( + ProfileFilterList(1, name = "기본 프로필"), + ProfileFilterList(2, name = "추가 프로필"), +) diff --git a/presentation/src/main/java/com/kusitms/presentation/navigation/NavGraph.kt b/presentation/src/main/java/com/kusitms/presentation/navigation/NavGraph.kt index f321cd2..3535f67 100644 --- a/presentation/src/main/java/com/kusitms/presentation/navigation/NavGraph.kt +++ b/presentation/src/main/java/com/kusitms/presentation/navigation/NavGraph.kt @@ -2,7 +2,6 @@ package com.kusitms.presentation.navigation import ProfileDetailScreen import android.os.Build -import androidx.annotation.RequiresApi import androidx.compose.animation.AnimatedContentScope import androidx.compose.animation.AnimatedContentTransitionScope import androidx.compose.animation.EnterTransition @@ -389,7 +388,9 @@ fun MainNavigation() { } kusitmsComposableWithAnimation(NavRoutes.ProfileEdit.route) { - ProfileEditScreen() + ProfileEditScreen( + onBack = { navController.navigateUp() } + ) } diff --git a/presentation/src/main/java/com/kusitms/presentation/ui/profile/edit/ProfileEditScreen.kt b/presentation/src/main/java/com/kusitms/presentation/ui/profile/edit/ProfileEditScreen.kt index 7a6011b..5e20612 100644 --- a/presentation/src/main/java/com/kusitms/presentation/ui/profile/edit/ProfileEditScreen.kt +++ b/presentation/src/main/java/com/kusitms/presentation/ui/profile/edit/ProfileEditScreen.kt @@ -2,26 +2,57 @@ package com.kusitms.presentation.ui.profile.edit import androidx.compose.foundation.background import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row 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.lazy.LazyColumn +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.rotate import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.kusitms.presentation.R +import com.kusitms.presentation.common.ui.KusitmsMarginVerticalSpacer import com.kusitms.presentation.common.ui.KusitsmTopBarBackTextWithIcon import com.kusitms.presentation.common.ui.theme.KusitmsColorPalette import com.kusitms.presentation.common.ui.theme.KusitmsTypo +import com.kusitms.presentation.model.profile.edit.ProfileEditViewModel +import com.kusitms.presentation.model.profile.edit.ProfileFilterList +import com.kusitms.presentation.model.profile.edit.categories +import com.kusitms.presentation.ui.ImageVector.icons.KusitmsIcons +import com.kusitms.presentation.ui.ImageVector.icons.kusitmsicons.ArrowDown +import kotlinx.coroutines.ExperimentalCoroutinesApi +@OptIn(ExperimentalCoroutinesApi::class) @Composable fun ProfileEditScreen( + viewModel: ProfileEditViewModel = hiltViewModel(), + onBack: () -> Unit, ) { + val expanded by viewModel.expended.collectAsStateWithLifecycle() + Column { KusitsmTopBarBackTextWithIcon( text = stringResource(id = R.string.profile_edit_toolbar), - onBackClick = {}, + onBackClick = { + onBack() + }, ) { Text( text = stringResource(id = R.string.profile_edit_modify), @@ -32,6 +63,31 @@ fun ProfileEditScreen( } ) } + KusitmsMarginVerticalSpacer(size = 32) + Card( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp) + .clickable { + viewModel.toggleExpanded() + }, + shape = RoundedCornerShape(8.dp), + colors = CardDefaults.cardColors( + containerColor = KusitmsColorPalette.current.Grey700, + contentColor = KusitmsColorPalette.current.Grey100 + ) + ) { + ProfileFilterButton( + expanded = expanded, + viewModel = viewModel + ) + if (expanded) { + AllProfileFilterList( + partNameList = categories, + viewModel = viewModel + ) + } + } LazyColumn( modifier = Modifier .fillMaxSize() @@ -40,11 +96,80 @@ fun ProfileEditScreen( } } +} + + +@OptIn(ExperimentalCoroutinesApi::class) +@Composable +private fun ProfileFilterButton( + expanded: Boolean, + viewModel: ProfileEditViewModel, +) { + val uiState by viewModel.uiState.collectAsState() + + + Row( + modifier = Modifier + .height(48.dp) + .fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween + ) { + Text( + text = uiState.currentSelectedProfileFilter.takeIf { it.isNotEmpty() } + ?: stringResource(id = R.string.profile_edit_basic), + style = KusitmsTypo.current.Text_Medium, + modifier = Modifier.padding(horizontal = 16.dp, vertical = 12.dp), + color = KusitmsColorPalette.current.Grey100, + ) + Icon( + imageVector = KusitmsIcons.ArrowDown, + contentDescription = stringResource(id = R.string.profile_edit_filter), + tint = KusitmsColorPalette.current.Grey400, + modifier = Modifier + .rotate(if (expanded) 180f else 0f) + .padding(horizontal = 16.dp) + ) + } +} + + +@Composable +fun AllProfileFilterList( + partNameList: List, + viewModel: ProfileEditViewModel, + modifier: Modifier = Modifier, +) { + Column(modifier = modifier) { + partNameList.forEach { profile -> + Box( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp, vertical = 16.dp) + .clickable { + viewModel.changeSelectProfileFilter(profile.name) + + }, + contentAlignment = Alignment.CenterStart + ) { + Text( + text = profile.name, + style = KusitmsTypo.current.Text_Medium, + color = KusitmsColorPalette.current.Grey400, + ) + } + } + } } + + + @Preview(showBackground = true, showSystemUi = true) @Composable fun ProfileEditScreenPreview() { - ProfileEditScreen() + ProfileEditScreen( + onBack = {} + ) } diff --git a/presentation/src/main/res/values/strings.xml b/presentation/src/main/res/values/strings.xml index edd50c5..df8edff 100644 --- a/presentation/src/main/res/values/strings.xml +++ b/presentation/src/main/res/values/strings.xml @@ -232,6 +232,9 @@ 프로필 설정 수정 + 프로필 선택 필터 + 기본 프로필 + 추가 프로필 From 47131aff9acb4b9c204651a5b321a1d1c51a4e1c Mon Sep 17 00:00:00 2001 From: arinming Date: Wed, 7 Feb 2024 19:38:45 +0900 Subject: [PATCH 3/9] =?UTF-8?q?FEAT:=20=EC=9D=B4=EB=A6=84,=20=EC=A0=84?= =?UTF-8?q?=EA=B3=B5=20=EC=9E=85=EB=A0=A5=20(#101)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../profile/edit/ProfileEditViewModel.kt | 52 ++++++++++++ .../ui/profile/edit/ProfileEditScreen.kt | 85 +++++++++++++++++-- 2 files changed, 129 insertions(+), 8 deletions(-) diff --git a/presentation/src/main/java/com/kusitms/presentation/model/profile/edit/ProfileEditViewModel.kt b/presentation/src/main/java/com/kusitms/presentation/model/profile/edit/ProfileEditViewModel.kt index a8c3e2c..704abbb 100644 --- a/presentation/src/main/java/com/kusitms/presentation/model/profile/edit/ProfileEditViewModel.kt +++ b/presentation/src/main/java/com/kusitms/presentation/model/profile/edit/ProfileEditViewModel.kt @@ -1,6 +1,11 @@ package com.kusitms.presentation.model.profile.edit +import android.net.Uri import androidx.lifecycle.ViewModel +import com.kusitms.presentation.model.signIn.InterestItem +import com.kusitms.presentation.model.signIn.LinkItem +import com.kusitms.presentation.model.signIn.LinkType +import com.kusitms.presentation.model.signIn.SignInStatus import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -14,9 +19,45 @@ class ProfileEditViewModel @Inject constructor( private val _uiState = MutableStateFlow(ProfileEditUiState()) val uiState: StateFlow = _uiState.asStateFlow() + private val _isAllFieldsValid = MutableStateFlow(false) + val isAllFieldsValid: StateFlow = _isAllFieldsValid + private val _expanded = MutableStateFlow(false) val expended: StateFlow = _expanded.asStateFlow() + private val _favoriteCategory = MutableStateFlow?>(null) + val favoriteCategory: StateFlow?> = _favoriteCategory + + private val _interests = MutableStateFlow>(emptyList()) + val interests: StateFlow> = _interests.asStateFlow() + + private val _name = MutableStateFlow("") + val name: StateFlow = _name + + private val _major = MutableStateFlow("") + val major: StateFlow = _major + + private val _phoneNum = MutableStateFlow("") + val phoneNum: StateFlow = _phoneNum + + private val _email = MutableStateFlow("") + val email: StateFlow = _email + + private val _selectedImage = MutableStateFlow(null) + val selectedImage: StateFlow = _selectedImage.asStateFlow() + + private val _linkItems = MutableStateFlow>(listOf(LinkItem(LinkType.LINK, ""))) + val linkItems: StateFlow> = _linkItems.asStateFlow() + + private val _introduce = MutableStateFlow("") + val introduce: StateFlow = _introduce + + private val _signInStatus = MutableStateFlow(SignInStatus.DEFAULT) + val signInStatus : StateFlow = _signInStatus + + private val _selectedPart = MutableStateFlow(null) + val selectedPart: StateFlow = _selectedPart + fun changeSelectProfileFilter(category: String) { _uiState.value = _uiState.value.copy(currentSelectedProfileFilter = category) _expanded.value = false @@ -25,4 +66,15 @@ class ProfileEditViewModel @Inject constructor( fun toggleExpanded() { _expanded.value = !_expanded.value } + + fun updateMajor(newMajor: String) { + _major.value = newMajor + validateFields() + } + + private fun validateFields() { + _isAllFieldsValid.value = _major.value.isNotBlank() && + _selectedPart.value != null && + _interests.value.isNotEmpty() + } } \ No newline at end of file diff --git a/presentation/src/main/java/com/kusitms/presentation/ui/profile/edit/ProfileEditScreen.kt b/presentation/src/main/java/com/kusitms/presentation/ui/profile/edit/ProfileEditScreen.kt index 5e20612..5dc32d3 100644 --- a/presentation/src/main/java/com/kusitms/presentation/ui/profile/edit/ProfileEditScreen.kt +++ b/presentation/src/main/java/com/kusitms/presentation/ui/profile/edit/ProfileEditScreen.kt @@ -6,11 +6,11 @@ import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults @@ -19,6 +19,9 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +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.rotate @@ -35,8 +38,12 @@ import com.kusitms.presentation.common.ui.theme.KusitmsTypo import com.kusitms.presentation.model.profile.edit.ProfileEditViewModel import com.kusitms.presentation.model.profile.edit.ProfileFilterList import com.kusitms.presentation.model.profile.edit.categories +import com.kusitms.presentation.ui.ImageVector.StudyIcon import com.kusitms.presentation.ui.ImageVector.icons.KusitmsIcons import com.kusitms.presentation.ui.ImageVector.icons.kusitmsicons.ArrowDown +import com.kusitms.presentation.ui.login.member.TextColumn1 +import com.kusitms.presentation.ui.signIn.KusitmsInputField +import com.kusitms.presentation.ui.signIn.SignInFixedInput import kotlinx.coroutines.ExperimentalCoroutinesApi @OptIn(ExperimentalCoroutinesApi::class) @@ -46,12 +53,27 @@ fun ProfileEditScreen( onBack: () -> Unit, ) { val expanded by viewModel.expended.collectAsStateWithLifecycle() + val email by viewModel.email.collectAsState() + val phoneNum by viewModel.phoneNum.collectAsState() + val name by viewModel.name.collectAsState() + val major by viewModel.major.collectAsState() + val selectedPart by viewModel.selectedPart.collectAsState() + val interests by viewModel.interests.collectAsState() + val likeCategoryText = if (interests.isNotEmpty()) { + interests.joinToString(", ") { it.content } + } else { + stringResource(id = R.string.signin_member_hint1_3) + } + + var isOpenPartBottomSheet by remember { mutableStateOf(false) } + var isOpenLikeCategoryBottomSheet by remember { mutableStateOf(false) } + Column { KusitsmTopBarBackTextWithIcon( text = stringResource(id = R.string.profile_edit_toolbar), onBackClick = { - onBack() + onBack() }, ) { Text( @@ -88,11 +110,61 @@ fun ProfileEditScreen( ) } } - LazyColumn( + Column( modifier = Modifier - .fillMaxSize() + .fillMaxWidth() + .padding(20.dp) .background(KusitmsColorPalette.current.Grey900) + .height(910.dp), + verticalArrangement = Arrangement.Top, + horizontalAlignment = Alignment.Start ) { + Column( + modifier = Modifier + .fillMaxWidth() + .background(KusitmsColorPalette.current.Grey900) + .height(64.dp), + horizontalAlignment = Alignment.Start, + verticalArrangement = Arrangement.Top + + ) { + Row( + horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.Start), + verticalAlignment = Alignment.Top, + ) { + StudyIcon.drawStudyIcon( + modifier = Modifier + .height(24.dp) + .width(24.dp) + ) + TextColumn1() + } + } + Spacer(modifier = Modifier.height(20.dp)) + Text(text = stringResource(id = R.string.signin_member_title1), style = KusitmsTypo.current.SubTitle2_Semibold, color = KusitmsColorPalette.current.Grey300) + Spacer(modifier = Modifier.height(28.dp)) + Text(text = stringResource(id = R.string.signin_member_caption1_1), style = KusitmsTypo.current.Caption1, color = KusitmsColorPalette.current.Grey400) + Spacer(modifier = Modifier.height(5.dp)) + SignInFixedInput(modelValue = name) + Spacer(modifier = Modifier.height(20.dp)) + + //전공 + Text(text = stringResource(id = R.string.signin_member_caption1_2), style = KusitmsTypo.current.Caption1, color = KusitmsColorPalette.current.Grey400) + Spacer(modifier = Modifier.height(5.dp)) + KusitmsInputField( + text = R.string.signin_member_hint1_1, + value = major, + onValueChange = viewModel::updateMajor) + if(major.length > 20) { + Spacer(modifier = Modifier.height(4.dp)) + Text( + text = "최대 20자까지 입력할 수 있어요", + style = KusitmsTypo.current.Caption1, + color = KusitmsColorPalette.current.Grey400 + ) + } + + Spacer(modifier = Modifier.height(24.dp)) } } @@ -134,7 +206,6 @@ private fun ProfileFilterButton( } - @Composable fun AllProfileFilterList( partNameList: List, @@ -164,8 +235,6 @@ fun AllProfileFilterList( } - - @Preview(showBackground = true, showSystemUi = true) @Composable fun ProfileEditScreenPreview() { From 7afbee7c00d54d4c8359252b6ff2416f2a5c8e80 Mon Sep 17 00:00:00 2001 From: arinming Date: Wed, 7 Feb 2024 19:50:33 +0900 Subject: [PATCH 4/9] =?UTF-8?q?FEAT:=20=EA=B8=B0=EB=B3=B8=20=ED=94=84?= =?UTF-8?q?=EB=A1=9C=ED=95=84=20=EC=84=A4=EC=A0=95=20UI=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20(#101)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../profile/edit/ProfileEditViewModel.kt | 14 ++- .../ui/profile/edit/ProfileEditScreen.kt | 98 ++++++++++++++++++- 2 files changed, 106 insertions(+), 6 deletions(-) diff --git a/presentation/src/main/java/com/kusitms/presentation/model/profile/edit/ProfileEditViewModel.kt b/presentation/src/main/java/com/kusitms/presentation/model/profile/edit/ProfileEditViewModel.kt index 704abbb..a241ca6 100644 --- a/presentation/src/main/java/com/kusitms/presentation/model/profile/edit/ProfileEditViewModel.kt +++ b/presentation/src/main/java/com/kusitms/presentation/model/profile/edit/ProfileEditViewModel.kt @@ -72,9 +72,21 @@ class ProfileEditViewModel @Inject constructor( validateFields() } + fun updateEmail(newEmail: String) { + _email.value = newEmail + validateFields() + } + + fun updatePhoneNumber(newPhoneNumber: String) { + _phoneNum.value = newPhoneNumber + validateFields() + } + private fun validateFields() { _isAllFieldsValid.value = _major.value.isNotBlank() && _selectedPart.value != null && - _interests.value.isNotEmpty() + _interests.value.isNotEmpty() && + _email.value.isNotBlank() && + _phoneNum.value.isNotBlank() } } \ No newline at end of file diff --git a/presentation/src/main/java/com/kusitms/presentation/ui/profile/edit/ProfileEditScreen.kt b/presentation/src/main/java/com/kusitms/presentation/ui/profile/edit/ProfileEditScreen.kt index 5dc32d3..889b8be 100644 --- a/presentation/src/main/java/com/kusitms/presentation/ui/profile/edit/ProfileEditScreen.kt +++ b/presentation/src/main/java/com/kusitms/presentation/ui/profile/edit/ProfileEditScreen.kt @@ -11,7 +11,9 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width +import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.Icon @@ -32,6 +34,7 @@ import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.kusitms.presentation.R import com.kusitms.presentation.common.ui.KusitmsMarginVerticalSpacer +import com.kusitms.presentation.common.ui.KusitmsSnackField import com.kusitms.presentation.common.ui.KusitsmTopBarBackTextWithIcon import com.kusitms.presentation.common.ui.theme.KusitmsColorPalette import com.kusitms.presentation.common.ui.theme.KusitmsTypo @@ -52,6 +55,8 @@ fun ProfileEditScreen( viewModel: ProfileEditViewModel = hiltViewModel(), onBack: () -> Unit, ) { + val scrollState = rememberScrollState() + val expanded by viewModel.expended.collectAsStateWithLifecycle() val email by viewModel.email.collectAsState() val phoneNum by viewModel.phoneNum.collectAsState() @@ -115,6 +120,7 @@ fun ProfileEditScreen( .fillMaxWidth() .padding(20.dp) .background(KusitmsColorPalette.current.Grey900) + .verticalScroll(scrollState) .height(910.dp), verticalArrangement = Arrangement.Top, horizontalAlignment = Alignment.Start @@ -141,21 +147,34 @@ fun ProfileEditScreen( } } Spacer(modifier = Modifier.height(20.dp)) - Text(text = stringResource(id = R.string.signin_member_title1), style = KusitmsTypo.current.SubTitle2_Semibold, color = KusitmsColorPalette.current.Grey300) + Text( + text = stringResource(id = R.string.signin_member_title1), + style = KusitmsTypo.current.SubTitle2_Semibold, + color = KusitmsColorPalette.current.Grey300 + ) Spacer(modifier = Modifier.height(28.dp)) - Text(text = stringResource(id = R.string.signin_member_caption1_1), style = KusitmsTypo.current.Caption1, color = KusitmsColorPalette.current.Grey400) + Text( + text = stringResource(id = R.string.signin_member_caption1_1), + style = KusitmsTypo.current.Caption1, + color = KusitmsColorPalette.current.Grey400 + ) Spacer(modifier = Modifier.height(5.dp)) SignInFixedInput(modelValue = name) Spacer(modifier = Modifier.height(20.dp)) //전공 - Text(text = stringResource(id = R.string.signin_member_caption1_2), style = KusitmsTypo.current.Caption1, color = KusitmsColorPalette.current.Grey400) + Text( + text = stringResource(id = R.string.signin_member_caption1_2), + style = KusitmsTypo.current.Caption1, + color = KusitmsColorPalette.current.Grey400 + ) Spacer(modifier = Modifier.height(5.dp)) KusitmsInputField( text = R.string.signin_member_hint1_1, value = major, - onValueChange = viewModel::updateMajor) - if(major.length > 20) { + onValueChange = viewModel::updateMajor + ) + if (major.length > 20) { Spacer(modifier = Modifier.height(4.dp)) Text( text = "최대 20자까지 입력할 수 있어요", @@ -165,7 +184,76 @@ fun ProfileEditScreen( } Spacer(modifier = Modifier.height(24.dp)) + //파트 선택 + Text( + text = stringResource(id = R.string.signin_member_caption1_3), + style = KusitmsTypo.current.Caption1, + color = KusitmsColorPalette.current.Grey400 + ) + Spacer(modifier = Modifier.height(5.dp)) + (if (!selectedPart.isNullOrEmpty()) { + selectedPart + } else { + stringResource(R.string.signin_member_hint1_2) + })?.let { + KusitmsSnackField( + text = it, + onSnackClick = { + isOpenPartBottomSheet = true + } + ) + } + + //관심 카테고리 + Spacer(modifier = Modifier.height(24.dp)) + Text( + text = stringResource(id = R.string.signin_member_caption1_4), + style = KusitmsTypo.current.Caption1, + color = KusitmsColorPalette.current.Grey400 + ) + Spacer(modifier = Modifier.height(5.dp)) + KusitmsSnackField( + text = likeCategoryText, + onSnackClick = { + isOpenLikeCategoryBottomSheet = true + } + ) + + + Spacer(modifier = Modifier.height(40.dp)) + Text( + text = stringResource(id = R.string.signin_member_title2), + style = KusitmsTypo.current.SubTitle2_Semibold, + color = KusitmsColorPalette.current.Grey300 + ) + //이메일 + Spacer(modifier = Modifier.height(24.dp)) + Text( + text = stringResource(id = R.string.signin_member_caption1_5), + style = KusitmsTypo.current.Caption1, + color = KusitmsColorPalette.current.Grey400 + ) + Spacer(modifier = Modifier.height(5.dp)) + KusitmsInputField( + text = R.string.signin_member_hint1_4, + value = email, + onValueChange = viewModel::updateEmail + ) + + //전화번호 + Spacer(modifier = Modifier.height(20.dp)) + Text( + text = stringResource(id = R.string.signin_member_caption1_6), + style = KusitmsTypo.current.Caption1, + color = KusitmsColorPalette.current.Grey400 + ) + Spacer(modifier = Modifier.height(5.dp)) + KusitmsInputField( + text = R.string.signin_member_hint1_5, + value = phoneNum, + onValueChange = viewModel::updatePhoneNumber + ) } } } From 2b8ca8539ded49ccc04b80d2d576a34662cca380 Mon Sep 17 00:00:00 2001 From: arinming Date: Wed, 7 Feb 2024 20:00:01 +0900 Subject: [PATCH 5/9] =?UTF-8?q?FEAT:=20=EC=9D=B4=EB=A9=94=EC=9D=BC,=20?= =?UTF-8?q?=EC=A0=84=ED=99=94=EB=B2=88=ED=98=B8=20=ED=98=95=EC=8B=9D=20?= =?UTF-8?q?=EA=B7=9C=EC=95=BD=20=EC=B6=94=EA=B0=80=20(#101)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../profile/edit/ProfileEditViewModel.kt | 28 +++++++++++++++++++ .../ui/profile/edit/ProfileEditScreen.kt | 17 +++++++++++ 2 files changed, 45 insertions(+) diff --git a/presentation/src/main/java/com/kusitms/presentation/model/profile/edit/ProfileEditViewModel.kt b/presentation/src/main/java/com/kusitms/presentation/model/profile/edit/ProfileEditViewModel.kt index a241ca6..1899d9a 100644 --- a/presentation/src/main/java/com/kusitms/presentation/model/profile/edit/ProfileEditViewModel.kt +++ b/presentation/src/main/java/com/kusitms/presentation/model/profile/edit/ProfileEditViewModel.kt @@ -43,6 +43,13 @@ class ProfileEditViewModel @Inject constructor( private val _email = MutableStateFlow("") val email: StateFlow = _email + private val _emailError = MutableStateFlow(null) + val emailError: StateFlow = _emailError + + private val _phoneNumError = MutableStateFlow(null) + val phoneNumError: StateFlow = _phoneNumError + + private val _selectedImage = MutableStateFlow(null) val selectedImage: StateFlow = _selectedImage.asStateFlow() @@ -74,11 +81,21 @@ class ProfileEditViewModel @Inject constructor( fun updateEmail(newEmail: String) { _email.value = newEmail + if (!isValidEmail(newEmail)) { + _emailError.value = "유효한 이메일 주소를 입력해주세요" + } else { + _emailError.value = null + } validateFields() } fun updatePhoneNumber(newPhoneNumber: String) { _phoneNum.value = newPhoneNumber + if (!isValidPhoneNumber(newPhoneNumber)) { + _phoneNumError.value = "유효한 전화번호를 입력해주세요 (010-1234-1234)" + } else { + _phoneNumError.value = null + } validateFields() } @@ -89,4 +106,15 @@ class ProfileEditViewModel @Inject constructor( _email.value.isNotBlank() && _phoneNum.value.isNotBlank() } + + private fun isValidEmail(email: String): Boolean { + val emailRegex = Regex("^\\w+@[a-zA-Z_]+?\\.[a-zA-Z]{2,3}\$") + return email.matches(emailRegex) + } + + private fun isValidPhoneNumber(phoneNumber: String): Boolean { + val phoneRegex = Regex("^01(?:0|1|[6-9])-(?:\\d{3}|\\d{4})-\\d{4}\$") + return phoneNumber.matches(phoneRegex) + } + } \ No newline at end of file diff --git a/presentation/src/main/java/com/kusitms/presentation/ui/profile/edit/ProfileEditScreen.kt b/presentation/src/main/java/com/kusitms/presentation/ui/profile/edit/ProfileEditScreen.kt index 889b8be..11a6e0f 100644 --- a/presentation/src/main/java/com/kusitms/presentation/ui/profile/edit/ProfileEditScreen.kt +++ b/presentation/src/main/java/com/kusitms/presentation/ui/profile/edit/ProfileEditScreen.kt @@ -69,6 +69,8 @@ fun ProfileEditScreen( } else { stringResource(id = R.string.signin_member_hint1_3) } + val emailError by viewModel.emailError.collectAsState() + val phoneNumError by viewModel.phoneNumError.collectAsState() var isOpenPartBottomSheet by remember { mutableStateOf(false) } var isOpenLikeCategoryBottomSheet by remember { mutableStateOf(false) } @@ -240,6 +242,13 @@ fun ProfileEditScreen( value = email, onValueChange = viewModel::updateEmail ) + emailError?.let { error -> + Text( + text = error, + style = KusitmsTypo.current.Caption1, + color = KusitmsColorPalette.current.Grey400 + ) + } //전화번호 Spacer(modifier = Modifier.height(20.dp)) @@ -254,6 +263,14 @@ fun ProfileEditScreen( value = phoneNum, onValueChange = viewModel::updatePhoneNumber ) + phoneNumError?.let { error -> + Spacer(modifier = Modifier.height(4.dp)) + Text( + text = error, + style = KusitmsTypo.current.Caption1, + color = KusitmsColorPalette.current.Grey400 + ) + } } } } From 6a292bafc291081ee908c9dbc99ac1f2cfb25c13 Mon Sep 17 00:00:00 2001 From: arinming Date: Wed, 7 Feb 2024 20:41:47 +0900 Subject: [PATCH 6/9] =?UTF-8?q?FEAT:=20=EC=B6=94=EA=B0=80=20=ED=94=84?= =?UTF-8?q?=EB=A1=9C=ED=95=84=20=EC=9D=B4=EB=AF=B8=EC=A7=80,=20=ED=95=9C?= =?UTF-8?q?=20=EC=A4=84=20=EC=86=8C=EA=B0=9C=20=EC=B6=94=EA=B0=80=20(#101)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../profile/edit/ProfileEditViewModel.kt | 42 +++- .../ui/profile/edit/ProfileAdd.kt | 203 ++++++++++++++++++ .../ui/profile/edit/ProfileBasic.kt | 201 +++++++++++++++++ .../ui/profile/edit/ProfileEditScreen.kt | 171 +-------------- 4 files changed, 446 insertions(+), 171 deletions(-) create mode 100644 presentation/src/main/java/com/kusitms/presentation/ui/profile/edit/ProfileAdd.kt create mode 100644 presentation/src/main/java/com/kusitms/presentation/ui/profile/edit/ProfileBasic.kt diff --git a/presentation/src/main/java/com/kusitms/presentation/model/profile/edit/ProfileEditViewModel.kt b/presentation/src/main/java/com/kusitms/presentation/model/profile/edit/ProfileEditViewModel.kt index 1899d9a..05b9577 100644 --- a/presentation/src/main/java/com/kusitms/presentation/model/profile/edit/ProfileEditViewModel.kt +++ b/presentation/src/main/java/com/kusitms/presentation/model/profile/edit/ProfileEditViewModel.kt @@ -99,6 +99,47 @@ class ProfileEditViewModel @Inject constructor( validateFields() } + fun updateSelectedImage(uri: Uri?) { + _selectedImage.value = uri + } + + fun updateLinkTypeAt(index: Int, linkType: LinkType) { + val updatedItems = _linkItems.value.toMutableList() + if (index in updatedItems.indices) { + val currentItem = updatedItems[index] + updatedItems[index] = currentItem.copy(linkType = linkType) + _linkItems.value = updatedItems + } + } + + fun addLinkItem() { + val newLinkItem = LinkItem(LinkType.LINK, "") //기본 설정값 + _linkItems.value = _linkItems.value + newLinkItem + } + + fun updateLinkItem(index: Int, linkType: LinkType, url: String) { + val updatedItems = _linkItems.value.toMutableList() + if (index in updatedItems.indices) { + updatedItems[index] = LinkItem(linkType, url) + _linkItems.value = updatedItems + } + } + + fun removeLinkItem() { + if (_linkItems.value.isNotEmpty()) { + _linkItems.value = _linkItems.value.dropLast(1) + } + } + + fun updateIntroduce(introduce: String) { + _introduce.value = introduce + } + + fun updateSignInStatus(signInStatus: SignInStatus) { + _signInStatus.value = signInStatus + } + + private fun validateFields() { _isAllFieldsValid.value = _major.value.isNotBlank() && _selectedPart.value != null && @@ -116,5 +157,4 @@ class ProfileEditViewModel @Inject constructor( val phoneRegex = Regex("^01(?:0|1|[6-9])-(?:\\d{3}|\\d{4})-\\d{4}\$") return phoneNumber.matches(phoneRegex) } - } \ No newline at end of file diff --git a/presentation/src/main/java/com/kusitms/presentation/ui/profile/edit/ProfileAdd.kt b/presentation/src/main/java/com/kusitms/presentation/ui/profile/edit/ProfileAdd.kt new file mode 100644 index 0000000..cc50566 --- /dev/null +++ b/presentation/src/main/java/com/kusitms/presentation/ui/profile/edit/ProfileAdd.kt @@ -0,0 +1,203 @@ +package com.kusitms.presentation.ui.profile.edit + +import android.net.Uri +import androidx.activity.compose.rememberLauncherForActivityResult +import androidx.activity.result.contract.ActivityResultContracts +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +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.width +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Text +import androidx.compose.material3.TextField +import androidx.compose.material3.TextFieldDefaults +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import com.kusitms.presentation.R +import com.kusitms.presentation.common.ui.KusitmsMarginVerticalSpacer +import com.kusitms.presentation.common.ui.theme.KusitmsColorPalette +import com.kusitms.presentation.common.ui.theme.KusitmsTypo +import com.kusitms.presentation.model.profile.edit.ProfileEditViewModel +import com.kusitms.presentation.ui.ImageVector.ImagePhoto +import com.kusitms.presentation.ui.ImageVector.StudyIcon +import com.kusitms.presentation.ui.signIn.TextColumn +import com.kusitms.presentation.ui.signIn.Title2Column +import kotlinx.coroutines.ExperimentalCoroutinesApi + +@OptIn(ExperimentalCoroutinesApi::class) +@Composable +fun ProfileAdd( + viewModel: ProfileEditViewModel = hiltViewModel(), +) { + val scrollState = rememberScrollState() + + Column( + modifier = Modifier + .fillMaxSize() + .verticalScroll(scrollState) + .background(KusitmsColorPalette.current.Grey900), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(4.dp, Alignment.Top) + ) { + Row( + horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.Start), + verticalAlignment = Alignment.Top, + ) { + StudyIcon.drawStudyIcon( + modifier = Modifier + .height(24.dp) + .width(24.dp) + ) + Column( + modifier = Modifier + .fillMaxWidth() + .padding(bottom = 40.dp) + .background(KusitmsColorPalette.current.Grey900), + horizontalAlignment = Alignment.Start, + verticalArrangement = Arrangement.Top + + ) { + Text( + text = stringResource(id = R.string.signin2_text1), + style = KusitmsTypo.current.SubTitle2_Semibold, + color = KusitmsColorPalette.current.Grey300 + ) + Text( + text = stringResource(id = R.string.signin2_text2), + style = KusitmsTypo.current.Caption1, + color = KusitmsColorPalette.current.Sub1 + ) + } + } + PhotoColumn(viewModel) + KusitmsMarginVerticalSpacer(size = 10) + IntroEditColumn(viewModel) + KusitmsMarginVerticalSpacer(size = 4) + } +} + +@OptIn(ExperimentalCoroutinesApi::class) +@Composable +fun PhotoColumn(viewModel: ProfileEditViewModel) { + val imageUri by viewModel.selectedImage.collectAsState() // This should be a Uri? in your ViewModel + + val imagePickerLauncher = + rememberLauncherForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? -> + uri?.let { + viewModel.updateSelectedImage(uri) + } + } + + Box( + modifier = Modifier + .width(96.dp) + .height(96.dp) + .background( + color = KusitmsColorPalette.current.Grey600, + shape = RoundedCornerShape(size = 12.dp) + ) + .clickable { + imagePickerLauncher.launch("image/*") + } + ) { + Column( + modifier = Modifier + .align(Alignment.Center), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally + ) { + ImagePhoto(imageUri) + } + } +} + + +@Composable +fun IntroEditColumn(viewModel: ProfileEditViewModel) { + Column( + modifier = Modifier + .fillMaxWidth() + .background(KusitmsColorPalette.current.Grey900), + verticalArrangement = Arrangement.spacedBy(8.dp, Alignment.CenterVertically), + horizontalAlignment = Alignment.Start, + ) { + Text( + text = stringResource(id = R.string.signin2_title1), + style = KusitmsTypo.current.SubTitle2_Semibold, + color = KusitmsColorPalette.current.Grey300 + ) + IntroEditTextField(viewModel) + } +} + +@OptIn(ExperimentalMaterial3Api::class, ExperimentalCoroutinesApi::class) +@Composable +fun IntroEditTextField(viewModel: ProfileEditViewModel) { + val maxLength = 100 + val textState by viewModel.introduce.collectAsState() + Column( + modifier = Modifier + .fillMaxWidth(), + verticalArrangement = Arrangement.spacedBy(4.dp), + horizontalAlignment = Alignment.Start + ) { + Box( + modifier = Modifier + .fillMaxWidth() + .height(130.dp) + .background(KusitmsColorPalette.current.Grey600, shape = RoundedCornerShape(16.dp)) + ) { + TextField( + value = textState, + onValueChange = { + if (it.length <= maxLength) { + viewModel.updateIntroduce(it) + } + }, + shape = RoundedCornerShape(16.dp), + colors = TextFieldDefaults.colors( + focusedContainerColor = KusitmsColorPalette.current.Grey600, + unfocusedContainerColor = KusitmsColorPalette.current.Grey600, + disabledContainerColor = KusitmsColorPalette.current.Grey600, + cursorColor = KusitmsColorPalette.current.Grey400, + focusedIndicatorColor = Color.Transparent, + unfocusedIndicatorColor = Color.Transparent, + focusedTextColor = KusitmsColorPalette.current.White, + unfocusedTextColor = KusitmsColorPalette.current.White, + disabledLabelColor = KusitmsColorPalette.current.White, + ), + placeholder = { + Text( + stringResource(id = R.string.signin2_placeholder1), + style = KusitmsTypo.current.Text_Medium, + color = KusitmsColorPalette.current.Grey400 + ) + } + ) + } + Text( + text = "${textState.length}/$maxLength", + style = KusitmsTypo.current.Caption1, + color = KusitmsColorPalette.current.Grey400 + ) + } +} + + diff --git a/presentation/src/main/java/com/kusitms/presentation/ui/profile/edit/ProfileBasic.kt b/presentation/src/main/java/com/kusitms/presentation/ui/profile/edit/ProfileBasic.kt new file mode 100644 index 0000000..5067896 --- /dev/null +++ b/presentation/src/main/java/com/kusitms/presentation/ui/profile/edit/ProfileBasic.kt @@ -0,0 +1,201 @@ +package com.kusitms.presentation.ui.profile.edit + +import androidx.compose.foundation.background +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.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.width +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import com.kusitms.presentation.R +import com.kusitms.presentation.common.ui.KusitmsSnackField +import com.kusitms.presentation.common.ui.theme.KusitmsColorPalette +import com.kusitms.presentation.common.ui.theme.KusitmsTypo +import com.kusitms.presentation.model.profile.edit.ProfileEditViewModel +import com.kusitms.presentation.ui.ImageVector.StudyIcon +import com.kusitms.presentation.ui.login.member.TextColumn1 +import com.kusitms.presentation.ui.signIn.KusitmsInputField +import com.kusitms.presentation.ui.signIn.SignInFixedInput +import kotlinx.coroutines.ExperimentalCoroutinesApi + +@OptIn(ExperimentalCoroutinesApi::class) +@Composable +fun ProfileBasic( + viewModel: ProfileEditViewModel = hiltViewModel(), +) { + val email by viewModel.email.collectAsState() + val phoneNum by viewModel.phoneNum.collectAsState() + val name by viewModel.name.collectAsState() + val major by viewModel.major.collectAsState() + val selectedPart by viewModel.selectedPart.collectAsState() + val interests by viewModel.interests.collectAsState() + val likeCategoryText = if (interests.isNotEmpty()) { + interests.joinToString(", ") { it.content } + } else { + stringResource(id = R.string.signin_member_hint1_3) + } + val emailError by viewModel.emailError.collectAsState() + val phoneNumError by viewModel.phoneNumError.collectAsState() + + var isOpenPartBottomSheet by remember { mutableStateOf(false) } + var isOpenLikeCategoryBottomSheet by remember { mutableStateOf(false) } + + + Column( + modifier = Modifier + .fillMaxWidth() + .background(KusitmsColorPalette.current.Grey900) + .height(64.dp), + horizontalAlignment = Alignment.Start, + verticalArrangement = Arrangement.Top + + ) { + Row( + horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.Start), + verticalAlignment = Alignment.Top, + ) { + StudyIcon.drawStudyIcon( + modifier = Modifier + .height(24.dp) + .width(24.dp) + ) + TextColumn1() + } + } + Spacer(modifier = Modifier.height(20.dp)) + Text( + text = stringResource(id = R.string.signin_member_title1), + style = KusitmsTypo.current.SubTitle2_Semibold, + color = KusitmsColorPalette.current.Grey300 + ) + Spacer(modifier = Modifier.height(28.dp)) + Text( + text = stringResource(id = R.string.signin_member_caption1_1), + style = KusitmsTypo.current.Caption1, + color = KusitmsColorPalette.current.Grey400 + ) + Spacer(modifier = Modifier.height(5.dp)) + SignInFixedInput(modelValue = name) + Spacer(modifier = Modifier.height(20.dp)) + + //전공 + Text( + text = stringResource(id = R.string.signin_member_caption1_2), + style = KusitmsTypo.current.Caption1, + color = KusitmsColorPalette.current.Grey400 + ) + Spacer(modifier = Modifier.height(5.dp)) + KusitmsInputField( + text = R.string.signin_member_hint1_1, + value = major, + onValueChange = viewModel::updateMajor + ) + if (major.length > 20) { + Spacer(modifier = Modifier.height(4.dp)) + Text( + text = "최대 20자까지 입력할 수 있어요", + style = KusitmsTypo.current.Caption1, + color = KusitmsColorPalette.current.Grey400 + ) + } + + Spacer(modifier = Modifier.height(24.dp)) + //파트 선택 + + Text( + text = stringResource(id = R.string.signin_member_caption1_3), + style = KusitmsTypo.current.Caption1, + color = KusitmsColorPalette.current.Grey400 + ) + Spacer(modifier = Modifier.height(5.dp)) + (if (!selectedPart.isNullOrEmpty()) { + selectedPart + } else { + stringResource(R.string.signin_member_hint1_2) + })?.let { + KusitmsSnackField( + text = it, + onSnackClick = { + isOpenPartBottomSheet = true + } + ) + } + + //관심 카테고리 + Spacer(modifier = Modifier.height(24.dp)) + Text( + text = stringResource(id = R.string.signin_member_caption1_4), + style = KusitmsTypo.current.Caption1, + color = KusitmsColorPalette.current.Grey400 + ) + Spacer(modifier = Modifier.height(5.dp)) + KusitmsSnackField( + text = likeCategoryText, + onSnackClick = { + isOpenLikeCategoryBottomSheet = true + } + ) + + + Spacer(modifier = Modifier.height(40.dp)) + Text( + text = stringResource(id = R.string.signin_member_title2), + style = KusitmsTypo.current.SubTitle2_Semibold, + color = KusitmsColorPalette.current.Grey300 + ) + //이메일 + Spacer(modifier = Modifier.height(24.dp)) + Text( + text = stringResource(id = R.string.signin_member_caption1_5), + style = KusitmsTypo.current.Caption1, + color = KusitmsColorPalette.current.Grey400 + ) + Spacer(modifier = Modifier.height(5.dp)) + KusitmsInputField( + text = R.string.signin_member_hint1_4, + value = email, + onValueChange = viewModel::updateEmail + ) + emailError?.let { error -> + Text( + text = error, + style = KusitmsTypo.current.Caption1, + color = KusitmsColorPalette.current.Grey400 + ) + } + + //전화번호 + Spacer(modifier = Modifier.height(20.dp)) + Text( + text = stringResource(id = R.string.signin_member_caption1_6), + style = KusitmsTypo.current.Caption1, + color = KusitmsColorPalette.current.Grey400 + ) + Spacer(modifier = Modifier.height(5.dp)) + KusitmsInputField( + text = R.string.signin_member_hint1_5, + value = phoneNum, + onValueChange = viewModel::updatePhoneNumber + ) + phoneNumError?.let { error -> + Spacer(modifier = Modifier.height(4.dp)) + Text( + text = error, + style = KusitmsTypo.current.Caption1, + color = KusitmsColorPalette.current.Grey400 + ) + } +} \ No newline at end of file diff --git a/presentation/src/main/java/com/kusitms/presentation/ui/profile/edit/ProfileEditScreen.kt b/presentation/src/main/java/com/kusitms/presentation/ui/profile/edit/ProfileEditScreen.kt index 11a6e0f..405608b 100644 --- a/presentation/src/main/java/com/kusitms/presentation/ui/profile/edit/ProfileEditScreen.kt +++ b/presentation/src/main/java/com/kusitms/presentation/ui/profile/edit/ProfileEditScreen.kt @@ -6,11 +6,9 @@ import androidx.compose.foundation.layout.Arrangement 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.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.width import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll @@ -21,9 +19,6 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -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.rotate @@ -34,19 +29,14 @@ import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.kusitms.presentation.R import com.kusitms.presentation.common.ui.KusitmsMarginVerticalSpacer -import com.kusitms.presentation.common.ui.KusitmsSnackField import com.kusitms.presentation.common.ui.KusitsmTopBarBackTextWithIcon import com.kusitms.presentation.common.ui.theme.KusitmsColorPalette import com.kusitms.presentation.common.ui.theme.KusitmsTypo import com.kusitms.presentation.model.profile.edit.ProfileEditViewModel import com.kusitms.presentation.model.profile.edit.ProfileFilterList import com.kusitms.presentation.model.profile.edit.categories -import com.kusitms.presentation.ui.ImageVector.StudyIcon import com.kusitms.presentation.ui.ImageVector.icons.KusitmsIcons import com.kusitms.presentation.ui.ImageVector.icons.kusitmsicons.ArrowDown -import com.kusitms.presentation.ui.login.member.TextColumn1 -import com.kusitms.presentation.ui.signIn.KusitmsInputField -import com.kusitms.presentation.ui.signIn.SignInFixedInput import kotlinx.coroutines.ExperimentalCoroutinesApi @OptIn(ExperimentalCoroutinesApi::class) @@ -58,22 +48,6 @@ fun ProfileEditScreen( val scrollState = rememberScrollState() val expanded by viewModel.expended.collectAsStateWithLifecycle() - val email by viewModel.email.collectAsState() - val phoneNum by viewModel.phoneNum.collectAsState() - val name by viewModel.name.collectAsState() - val major by viewModel.major.collectAsState() - val selectedPart by viewModel.selectedPart.collectAsState() - val interests by viewModel.interests.collectAsState() - val likeCategoryText = if (interests.isNotEmpty()) { - interests.joinToString(", ") { it.content } - } else { - stringResource(id = R.string.signin_member_hint1_3) - } - val emailError by viewModel.emailError.collectAsState() - val phoneNumError by viewModel.phoneNumError.collectAsState() - - var isOpenPartBottomSheet by remember { mutableStateOf(false) } - var isOpenLikeCategoryBottomSheet by remember { mutableStateOf(false) } Column { @@ -127,150 +101,7 @@ fun ProfileEditScreen( verticalArrangement = Arrangement.Top, horizontalAlignment = Alignment.Start ) { - Column( - modifier = Modifier - .fillMaxWidth() - .background(KusitmsColorPalette.current.Grey900) - .height(64.dp), - horizontalAlignment = Alignment.Start, - verticalArrangement = Arrangement.Top - - ) { - Row( - horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.Start), - verticalAlignment = Alignment.Top, - ) { - StudyIcon.drawStudyIcon( - modifier = Modifier - .height(24.dp) - .width(24.dp) - ) - TextColumn1() - } - } - Spacer(modifier = Modifier.height(20.dp)) - Text( - text = stringResource(id = R.string.signin_member_title1), - style = KusitmsTypo.current.SubTitle2_Semibold, - color = KusitmsColorPalette.current.Grey300 - ) - Spacer(modifier = Modifier.height(28.dp)) - Text( - text = stringResource(id = R.string.signin_member_caption1_1), - style = KusitmsTypo.current.Caption1, - color = KusitmsColorPalette.current.Grey400 - ) - Spacer(modifier = Modifier.height(5.dp)) - SignInFixedInput(modelValue = name) - Spacer(modifier = Modifier.height(20.dp)) - - //전공 - Text( - text = stringResource(id = R.string.signin_member_caption1_2), - style = KusitmsTypo.current.Caption1, - color = KusitmsColorPalette.current.Grey400 - ) - Spacer(modifier = Modifier.height(5.dp)) - KusitmsInputField( - text = R.string.signin_member_hint1_1, - value = major, - onValueChange = viewModel::updateMajor - ) - if (major.length > 20) { - Spacer(modifier = Modifier.height(4.dp)) - Text( - text = "최대 20자까지 입력할 수 있어요", - style = KusitmsTypo.current.Caption1, - color = KusitmsColorPalette.current.Grey400 - ) - } - - Spacer(modifier = Modifier.height(24.dp)) - //파트 선택 - - Text( - text = stringResource(id = R.string.signin_member_caption1_3), - style = KusitmsTypo.current.Caption1, - color = KusitmsColorPalette.current.Grey400 - ) - Spacer(modifier = Modifier.height(5.dp)) - (if (!selectedPart.isNullOrEmpty()) { - selectedPart - } else { - stringResource(R.string.signin_member_hint1_2) - })?.let { - KusitmsSnackField( - text = it, - onSnackClick = { - isOpenPartBottomSheet = true - } - ) - } - - //관심 카테고리 - Spacer(modifier = Modifier.height(24.dp)) - Text( - text = stringResource(id = R.string.signin_member_caption1_4), - style = KusitmsTypo.current.Caption1, - color = KusitmsColorPalette.current.Grey400 - ) - Spacer(modifier = Modifier.height(5.dp)) - KusitmsSnackField( - text = likeCategoryText, - onSnackClick = { - isOpenLikeCategoryBottomSheet = true - } - ) - - - Spacer(modifier = Modifier.height(40.dp)) - Text( - text = stringResource(id = R.string.signin_member_title2), - style = KusitmsTypo.current.SubTitle2_Semibold, - color = KusitmsColorPalette.current.Grey300 - ) - //이메일 - Spacer(modifier = Modifier.height(24.dp)) - Text( - text = stringResource(id = R.string.signin_member_caption1_5), - style = KusitmsTypo.current.Caption1, - color = KusitmsColorPalette.current.Grey400 - ) - Spacer(modifier = Modifier.height(5.dp)) - KusitmsInputField( - text = R.string.signin_member_hint1_4, - value = email, - onValueChange = viewModel::updateEmail - ) - emailError?.let { error -> - Text( - text = error, - style = KusitmsTypo.current.Caption1, - color = KusitmsColorPalette.current.Grey400 - ) - } - - //전화번호 - Spacer(modifier = Modifier.height(20.dp)) - Text( - text = stringResource(id = R.string.signin_member_caption1_6), - style = KusitmsTypo.current.Caption1, - color = KusitmsColorPalette.current.Grey400 - ) - Spacer(modifier = Modifier.height(5.dp)) - KusitmsInputField( - text = R.string.signin_member_hint1_5, - value = phoneNum, - onValueChange = viewModel::updatePhoneNumber - ) - phoneNumError?.let { error -> - Spacer(modifier = Modifier.height(4.dp)) - Text( - text = error, - style = KusitmsTypo.current.Caption1, - color = KusitmsColorPalette.current.Grey400 - ) - } + ProfileAdd() } } } From 186a4b89982337ff7f1f1beecfd3fcf7dfe70368 Mon Sep 17 00:00:00 2001 From: arinming Date: Wed, 7 Feb 2024 21:53:34 +0900 Subject: [PATCH 7/9] =?UTF-8?q?FEAT:=20=EC=B6=94=EA=B0=80=20=ED=94=84?= =?UTF-8?q?=EB=A1=9C=ED=95=84=20=EC=84=A4=EC=A0=95=20UI=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20(#101)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../profile/edit/ProfileEditViewModel.kt | 1 + .../ui/profile/edit/ProfileAdd.kt | 6 +- .../ui/profile/edit/ProfileLink.kt | 305 ++++++++++++++++++ .../ui/signIn/component/LinkBottomSheet.kt | 12 +- 4 files changed, 318 insertions(+), 6 deletions(-) create mode 100644 presentation/src/main/java/com/kusitms/presentation/ui/profile/edit/ProfileLink.kt diff --git a/presentation/src/main/java/com/kusitms/presentation/model/profile/edit/ProfileEditViewModel.kt b/presentation/src/main/java/com/kusitms/presentation/model/profile/edit/ProfileEditViewModel.kt index 05b9577..ddcc1ce 100644 --- a/presentation/src/main/java/com/kusitms/presentation/model/profile/edit/ProfileEditViewModel.kt +++ b/presentation/src/main/java/com/kusitms/presentation/model/profile/edit/ProfileEditViewModel.kt @@ -112,6 +112,7 @@ class ProfileEditViewModel @Inject constructor( } } + fun addLinkItem() { val newLinkItem = LinkItem(LinkType.LINK, "") //기본 설정값 _linkItems.value = _linkItems.value + newLinkItem diff --git a/presentation/src/main/java/com/kusitms/presentation/ui/profile/edit/ProfileAdd.kt b/presentation/src/main/java/com/kusitms/presentation/ui/profile/edit/ProfileAdd.kt index cc50566..e7766d4 100644 --- a/presentation/src/main/java/com/kusitms/presentation/ui/profile/edit/ProfileAdd.kt +++ b/presentation/src/main/java/com/kusitms/presentation/ui/profile/edit/ProfileAdd.kt @@ -9,6 +9,7 @@ import androidx.compose.foundation.layout.Arrangement 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 @@ -37,8 +38,6 @@ import com.kusitms.presentation.common.ui.theme.KusitmsTypo import com.kusitms.presentation.model.profile.edit.ProfileEditViewModel import com.kusitms.presentation.ui.ImageVector.ImagePhoto import com.kusitms.presentation.ui.ImageVector.StudyIcon -import com.kusitms.presentation.ui.signIn.TextColumn -import com.kusitms.presentation.ui.signIn.Title2Column import kotlinx.coroutines.ExperimentalCoroutinesApi @OptIn(ExperimentalCoroutinesApi::class) @@ -90,6 +89,8 @@ fun ProfileAdd( KusitmsMarginVerticalSpacer(size = 10) IntroEditColumn(viewModel) KusitmsMarginVerticalSpacer(size = 4) + ProfileLink(viewModel) + Spacer(modifier = Modifier.weight(1f)) } } @@ -200,4 +201,3 @@ fun IntroEditTextField(viewModel: ProfileEditViewModel) { } } - diff --git a/presentation/src/main/java/com/kusitms/presentation/ui/profile/edit/ProfileLink.kt b/presentation/src/main/java/com/kusitms/presentation/ui/profile/edit/ProfileLink.kt new file mode 100644 index 0000000..585df75 --- /dev/null +++ b/presentation/src/main/java/com/kusitms/presentation/ui/profile/edit/ProfileLink.kt @@ -0,0 +1,305 @@ +package com.kusitms.presentation.ui.profile.edit + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +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.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.layout.wrapContentHeight +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import com.kusitms.presentation.R +import com.kusitms.presentation.common.ui.KusitmsMarginHorizontalSpacer +import com.kusitms.presentation.common.ui.KusitmsMarginVerticalSpacer +import com.kusitms.presentation.common.ui.theme.KusitmsColorPalette +import com.kusitms.presentation.common.ui.theme.KusitmsTypo +import com.kusitms.presentation.model.profile.edit.ProfileEditViewModel +import com.kusitms.presentation.model.signIn.LinkType +import com.kusitms.presentation.ui.ImageVector.plusIcon +import com.kusitms.presentation.ui.signIn.KusitmsInputField +import com.kusitms.presentation.ui.signIn.component.LinkBottomSheet +import kotlinx.coroutines.ExperimentalCoroutinesApi + +@Composable +fun ProfileLink(viewModel: ProfileEditViewModel) { + LinkColumn(viewModel) +} + + +@OptIn(ExperimentalCoroutinesApi::class) +@Composable +fun LinkColumn(viewModel: ProfileEditViewModel) { + val linkItems by viewModel.linkItems.collectAsState() + val maxLength = 4 + var isOpenLinkBottomSheet by remember { mutableStateOf(false) } + var selectedLinkItemIndex by remember { mutableStateOf(-1) } // 선택된 링크 아이템의 인덱스 + + if (isOpenLinkBottomSheet) { + LinkBottomSheet( + viewModel = viewModel, + isOpenLinkBottomSheet, + selectedLinkItemIndex + ) { isOpen, selectedData -> + isOpenLinkBottomSheet = isOpen + if (!isOpen && selectedData is LinkType) { + viewModel.updateLinkItem( + selectedLinkItemIndex, + selectedData, + linkItems[selectedLinkItemIndex].linkUrl + ) + } + } + } + + Column( + modifier = Modifier + .fillMaxWidth() + .padding(20.dp) + .background(KusitmsColorPalette.current.Grey900), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Row( + modifier = + Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically, + ) { + Text( + style = KusitmsTypo.current.Text_Semibold, + color = KusitmsColorPalette.current.Grey300, + text = stringResource(id = R.string.signin2_title2), + ) + LinkRow1(viewModel, maxLength) + } + Spacer(modifier = Modifier.height(14.dp)) + LinkItemsDisplay(viewModel, onLinkTypeChange = { index -> + selectedLinkItemIndex = index + isOpenLinkBottomSheet = true + }) + } +} + + +@OptIn(ExperimentalCoroutinesApi::class) +@Composable +fun LinkRow1(viewModel: ProfileEditViewModel, maxLength: Int) { + val linkItems by viewModel.linkItems.collectAsState() + Row( + modifier = Modifier + .width(125.dp) + .height(36.dp) + .background( + color = KusitmsColorPalette.current.Grey900, + shape = RoundedCornerShape(size = 8.dp) + ), + horizontalArrangement = Arrangement.spacedBy(4.dp, Alignment.CenterHorizontally), + verticalAlignment = Alignment.CenterVertically, + ) { + plusIcon() + Text( + style = KusitmsTypo.current.Caption1, + color = KusitmsColorPalette.current.Grey300, + text = "추가하기${linkItems.size}/${maxLength}", + modifier = Modifier.clickable { + if (linkItems.size < maxLength) { + viewModel.addLinkItem() + } + } + ) + } +} + +@OptIn(ExperimentalCoroutinesApi::class) +@Composable +fun LinkItemsDisplay(viewModel: ProfileEditViewModel, onLinkTypeChange: (Int) -> Unit) { + val linkItems by viewModel.linkItems.collectAsState() + + linkItems.forEachIndexed { index, _ -> + LinkRow2(viewModel, index, onClick = { onLinkTypeChange(index) }) + KusitmsMarginVerticalSpacer(size = 8) + } +} + + +@OptIn(ExperimentalCoroutinesApi::class) +@Composable +fun LinkRow2( + viewModel: ProfileEditViewModel, + linkItemIndex: Int, + onClick: () -> Unit, +) { + val linkItems by viewModel.linkItems.collectAsState() + val currentLinkItem = linkItems.getOrNull(linkItemIndex) ?: return + Row( + modifier = Modifier + .fillMaxWidth() + .height(48.dp), + horizontalArrangement = Arrangement.spacedBy(0.dp, Alignment.Start), + verticalAlignment = Alignment.CenterVertically, + ) { + KusitmsLinkCheck( + viewModel, + linkItemIndex, + currentLinkItem.linkType, + onClick + ) + IconButton( + onClick = { viewModel.removeLinkItem() }, + ) { + Icon( + painterResource(id = R.drawable.ic_trashcan), + contentDescription = "Localized description", + tint = Color.Unspecified, + modifier = Modifier + .size(25.dp) + ) + } + } +} + + +@Composable +fun KusitmsLinkCheck( + viewModel: ProfileEditViewModel, + linkItemIndex: Int, + currentLinkType: LinkType, + onLinkTypeChange: () -> Unit, +) { + Row( + modifier = Modifier + .width(300.dp) + .height(48.dp), + horizontalArrangement = Arrangement.spacedBy(4.dp, Alignment.Start), + verticalAlignment = Alignment.CenterVertically + ) { + LinkCheckBox( + viewModel = viewModel, + linkItemIndex = linkItemIndex, + currentLinkType = currentLinkType, + onClick = onLinkTypeChange + ) + KusitmsMarginHorizontalSpacer(size = 5) + LinkTextField(viewModel, linkItemIndex) + } +} + +@OptIn(ExperimentalMaterial3Api::class, ExperimentalCoroutinesApi::class) +@Composable +fun LinkTextField(viewModel: ProfileEditViewModel, linkItemIndex: Int) { + val linkItems by viewModel.linkItems.collectAsState() + val linkItem = linkItems[linkItemIndex] + val textState = remember { mutableStateOf(linkItem.linkUrl) } + val isClicked by remember { mutableStateOf(false) } + val borderColor = + if (isClicked) KusitmsColorPalette.current.Main500 else KusitmsColorPalette.current.Grey700 + Box( + modifier = Modifier + .width(220.dp) + .height(48.dp) + .border(width = 1.dp, color = borderColor, shape = RoundedCornerShape(12.dp)) + .background( + color = KusitmsColorPalette.current.Grey700, + shape = RoundedCornerShape(12.dp) + ), + ) { + KusitmsInputField( + text = R.string.signin2_placeholder2, + value = textState.value, + onValueChange = { + textState.value = it + viewModel.updateLinkItem(linkItemIndex, linkItem.linkType, it) + }, + modifier = Modifier + .width(220.dp) + .wrapContentHeight() + ) + } +} + + +@Composable +fun LinkCheckBox( + viewModel: ProfileEditViewModel, + linkItemIndex: Int, + currentLinkType: LinkType, + onClick: () -> Unit, +) { + var isOpenLinkBottomSheet by remember { mutableStateOf(false) } + + if (isOpenLinkBottomSheet) { + LinkBottomSheet( + viewModel, + isOpenLinkBottomSheet, + linkItemIndex + ) { isSelected, selectedLinkType -> + isOpenLinkBottomSheet = isSelected + if (isSelected && selectedLinkType is LinkType) { + viewModel.updateLinkItem( + linkItemIndex, + selectedLinkType, + viewModel.linkItems.value[linkItemIndex].linkUrl + ) + } + } + } + + Row( + modifier = Modifier + .width(110.dp) + .height(48.dp) + .background( + color = KusitmsColorPalette.current.Grey700, + shape = RoundedCornerShape(12.dp) + ) + .padding(start = 12.dp, top = 12.dp, end = 12.dp, bottom = 12.dp), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + val displayText = if (currentLinkType == LinkType.LINK) { + stringResource(id = R.string.signin2_checkbox) + } else { + currentLinkType.displayName + } + + Text( + text = displayText, + style = KusitmsTypo.current.Caption1, + color = KusitmsColorPalette.current.Grey400 + ) + IconButton( + modifier = Modifier.size(24.dp), + onClick = onClick + ) { + Icon( + painter = painterResource(id = R.drawable.ic_under_errow), + contentDescription = null, + tint = KusitmsColorPalette.current.Grey400 + ) + } + } +} + + diff --git a/presentation/src/main/java/com/kusitms/presentation/ui/signIn/component/LinkBottomSheet.kt b/presentation/src/main/java/com/kusitms/presentation/ui/signIn/component/LinkBottomSheet.kt index b7b738b..8124bed 100644 --- a/presentation/src/main/java/com/kusitms/presentation/ui/signIn/component/LinkBottomSheet.kt +++ b/presentation/src/main/java/com/kusitms/presentation/ui/signIn/component/LinkBottomSheet.kt @@ -13,10 +13,12 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp +import androidx.lifecycle.ViewModel import com.kusitms.presentation.R import com.kusitms.presentation.common.ui.KusitmsMarginVerticalSpacer import com.kusitms.presentation.common.ui.theme.KusitmsColorPalette import com.kusitms.presentation.common.ui.theme.KusitmsTypo +import com.kusitms.presentation.model.profile.edit.ProfileEditViewModel import com.kusitms.presentation.model.signIn.SignInViewModel import com.kusitms.presentation.model.signIn.linkCategories import com.kusitms.presentation.ui.ImageVector.xIcon @@ -25,7 +27,7 @@ import com.kusitms.presentation.ui.ImageVector.xIcon @OptIn(ExperimentalMaterial3Api::class) @Composable fun LinkBottomSheet( - viewModel: SignInViewModel, + viewModel: ViewModel, openBottomSheet: Boolean = false, linkItemIndex: Int, onChangeOpenBottomSheet: (Boolean, Any?) -> Unit = { b: Boolean, any: Any? -> } @@ -63,13 +65,17 @@ fun LinkBottomSheet( } @Composable -fun LinkSelectColumn(viewModel: SignInViewModel, linkItemIndex: Int) { +fun LinkSelectColumn(viewModel: ViewModel, linkItemIndex: Int) { LazyColumn(modifier = Modifier.padding(horizontal = 12.dp)) { items(linkCategories) { category -> LinkItem( category = category, onClick = { - viewModel.updateLinkTypeAt(linkItemIndex, category.linkType) + if (viewModel is SignInViewModel) { + viewModel.updateLinkTypeAt(linkItemIndex, category.linkType) + } else if (viewModel is ProfileEditViewModel) { + viewModel.updateLinkTypeAt(linkItemIndex, category.linkType) + } } ) } From f18dbf17975cf51dd5883d098cf83b9335f5cd4a Mon Sep 17 00:00:00 2001 From: arinming Date: Wed, 7 Feb 2024 22:06:59 +0900 Subject: [PATCH 8/9] =?UTF-8?q?FEAT:=20=EA=B8=B0=EB=B3=B8=20=ED=94=84?= =?UTF-8?q?=EB=A1=9C=ED=95=84=20/=20=EC=B6=94=EA=B0=80=20=ED=94=84?= =?UTF-8?q?=EB=A1=9C=ED=95=84=20=EA=B5=AC=EB=B6=84=20(#101)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/model/profile/edit/ProfileEditUiState.kt | 2 +- .../model/profile/edit/ProfileEditViewModel.kt | 4 ---- .../presentation/ui/profile/edit/ProfileEditScreen.kt | 8 ++++++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/presentation/src/main/java/com/kusitms/presentation/model/profile/edit/ProfileEditUiState.kt b/presentation/src/main/java/com/kusitms/presentation/model/profile/edit/ProfileEditUiState.kt index 323d980..499a649 100644 --- a/presentation/src/main/java/com/kusitms/presentation/model/profile/edit/ProfileEditUiState.kt +++ b/presentation/src/main/java/com/kusitms/presentation/model/profile/edit/ProfileEditUiState.kt @@ -1,5 +1,5 @@ package com.kusitms.presentation.model.profile.edit data class ProfileEditUiState( - val currentSelectedProfileFilter: String = "", + val currentSelectedProfileFilter: String = "기본 프로필", ) diff --git a/presentation/src/main/java/com/kusitms/presentation/model/profile/edit/ProfileEditViewModel.kt b/presentation/src/main/java/com/kusitms/presentation/model/profile/edit/ProfileEditViewModel.kt index ddcc1ce..4bf9725 100644 --- a/presentation/src/main/java/com/kusitms/presentation/model/profile/edit/ProfileEditViewModel.kt +++ b/presentation/src/main/java/com/kusitms/presentation/model/profile/edit/ProfileEditViewModel.kt @@ -136,10 +136,6 @@ class ProfileEditViewModel @Inject constructor( _introduce.value = introduce } - fun updateSignInStatus(signInStatus: SignInStatus) { - _signInStatus.value = signInStatus - } - private fun validateFields() { _isAllFieldsValid.value = _major.value.isNotBlank() && diff --git a/presentation/src/main/java/com/kusitms/presentation/ui/profile/edit/ProfileEditScreen.kt b/presentation/src/main/java/com/kusitms/presentation/ui/profile/edit/ProfileEditScreen.kt index 405608b..fbf2148 100644 --- a/presentation/src/main/java/com/kusitms/presentation/ui/profile/edit/ProfileEditScreen.kt +++ b/presentation/src/main/java/com/kusitms/presentation/ui/profile/edit/ProfileEditScreen.kt @@ -48,7 +48,7 @@ fun ProfileEditScreen( val scrollState = rememberScrollState() val expanded by viewModel.expended.collectAsStateWithLifecycle() - + val uiState by viewModel.uiState.collectAsState() Column { KusitsmTopBarBackTextWithIcon( @@ -101,7 +101,11 @@ fun ProfileEditScreen( verticalArrangement = Arrangement.Top, horizontalAlignment = Alignment.Start ) { - ProfileAdd() + if (uiState.currentSelectedProfileFilter == "기본 프로필") { + ProfileBasic(viewModel) + } else { + ProfileAdd(viewModel) + } } } } From 68a506d4d7076385536bb12e72f5e3a5bb1e37b8 Mon Sep 17 00:00:00 2001 From: arinming Date: Wed, 7 Feb 2024 23:16:50 +0900 Subject: [PATCH 9/9] =?UTF-8?q?FEAT:=20=ED=8C=8C=ED=8A=B8=20/=20=EA=B4=80?= =?UTF-8?q?=EC=8B=AC=20=EC=B9=B4=ED=85=8C=EA=B3=A0=EB=A6=AC=20=EB=B0=94?= =?UTF-8?q?=ED=85=80=EC=8B=9C=ED=8A=B8=20=EC=B6=94=EA=B0=80=20(#101)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/profile/edit/ProfileEditCategory.kt | 152 ++++++++++++ .../profile/edit/ProfileEditViewModel.kt | 13 + .../ui/profile/edit/ProfileBasic.kt | 234 +++++++++++++++++- .../ui/signIn/component/PartBottomSheet.kt | 7 +- 4 files changed, 400 insertions(+), 6 deletions(-) create mode 100644 presentation/src/main/java/com/kusitms/presentation/model/profile/edit/ProfileEditCategory.kt diff --git a/presentation/src/main/java/com/kusitms/presentation/model/profile/edit/ProfileEditCategory.kt b/presentation/src/main/java/com/kusitms/presentation/model/profile/edit/ProfileEditCategory.kt new file mode 100644 index 0000000..7a3118b --- /dev/null +++ b/presentation/src/main/java/com/kusitms/presentation/model/profile/edit/ProfileEditCategory.kt @@ -0,0 +1,152 @@ +package com.kusitms.presentation.model.profile.edit + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.statusBarsPadding +import androidx.compose.foundation.layout.systemBarsPadding +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.grid.GridCells +import androidx.compose.foundation.lazy.grid.LazyVerticalGrid +import androidx.compose.foundation.lazy.grid.items +import androidx.compose.foundation.lazy.items +import androidx.compose.material.ExperimentalMaterialApi +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ModalBottomSheet +import androidx.compose.material3.rememberModalBottomSheetState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import com.kusitms.presentation.common.ui.KusitmsTabItem +import com.kusitms.presentation.common.ui.KusitmsTabRow +import com.kusitms.presentation.common.ui.theme.KusitmsColorPalette +import com.kusitms.presentation.model.signIn.InterestItem +import com.kusitms.presentation.model.signIn.PartCategory +import com.kusitms.presentation.model.signIn.mapCategoryToValue +import com.kusitms.presentation.ui.profile.edit.LikeBottomSheetContent +import com.kusitms.presentation.ui.profile.edit.PartSelectItem +import com.kusitms.presentation.ui.signIn.component.LikeCategoryItem +import kotlinx.coroutines.ExperimentalCoroutinesApi + + +@Composable +fun PartSelectColumn(viewModel: ProfileEditViewModel) { + val filteredCategories = com.kusitms.presentation.model.signIn.categories.filter { it.name != "기타" } + LazyColumn( + modifier = Modifier + .padding(horizontal = 24.dp) + ) { + items(filteredCategories) { category -> + PartSelectItem( + category = category, + onClick = { selectedCategory -> + val selectedValue = mapCategoryToValue(selectedCategory.name) + viewModel.updateSelectedPart(selectedValue) + }, + viewModel = viewModel + ) + } + } +} + + + +@OptIn(ExperimentalMaterial3Api::class) +@ExperimentalMaterialApi +@Composable +fun LikeCategoryBottomSheet( + viewModel: ProfileEditViewModel, + openBottomSheet: Boolean = false, + onChangeOpenBottomSheet: (Boolean) -> Unit = {}, +) { + val bottomSheetState = rememberModalBottomSheetState( + skipPartiallyExpanded = true + ) + + if (openBottomSheet) { + ModalBottomSheet( + containerColor = KusitmsColorPalette.current.Grey600, + dragHandle = { Box(Modifier.height(0.dp)) }, + onDismissRequest = { onChangeOpenBottomSheet(false) }, + sheetState = bottomSheetState, + modifier = Modifier + .fillMaxWidth() + .height(704.dp) + ) { + Column( + modifier = Modifier + .fillMaxWidth() + .wrapContentHeight() + .systemBarsPadding() + .statusBarsPadding() + ) { + LikeBottomSheetContent( + viewModel = viewModel, + onClick = { onChangeOpenBottomSheet(false) }) + } + + } + } +} + + + + +@Composable +fun LikeCategoryTab(selectedCategory: PartCategory, onCategorySelected: (PartCategory) -> Unit, viewModel: ProfileEditViewModel) { + KusitmsTabRow( + tabItemList = com.kusitms.presentation.model.signIn.categories, + tabContent = { category -> + KusitmsTabItem( + text = category.name, + isSelected = category == selectedCategory, + onSelect = { onCategorySelected(category) } + ) + } + ) + when (selectedCategory.name) { + "기획" -> LikeCategoryItems(category = com.kusitms.presentation.model.signIn.categories[0], viewModel = viewModel) + "개발" -> LikeCategoryItems(category = com.kusitms.presentation.model.signIn.categories[1], viewModel = viewModel) + "디자인" -> LikeCategoryItems(category = com.kusitms.presentation.model.signIn.categories[2], viewModel = viewModel) + "기타" -> LikeCategoryItems(category = com.kusitms.presentation.model.signIn.categories[3], viewModel = viewModel) + else -> {} + } +} + + +@OptIn(ExperimentalCoroutinesApi::class) +@Composable +fun LikeCategoryItems(category: PartCategory, viewModel: ProfileEditViewModel) { + val selectedInterests = viewModel.interests.collectAsState().value.toMutableSet() + + LazyVerticalGrid( + columns = GridCells.Fixed(2), + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 10.dp, vertical = 16.dp) + .height(436.dp), + horizontalArrangement = Arrangement.spacedBy(12.dp), + verticalArrangement = Arrangement.spacedBy(12.dp) + ) { + items(category.subCategories) { subCategory -> + val interestItem = InterestItem(mapCategoryToValue(category.name), subCategory) + LikeCategoryItem( + subCategoryName = subCategory, + isSelected = interestItem in selectedInterests, + onSelect = { + if (interestItem in selectedInterests) { + selectedInterests.remove(interestItem) + } else { + selectedInterests.add(interestItem) + } + viewModel.updateInterests(selectedInterests.toList()) + } + ) + } + } +} \ No newline at end of file diff --git a/presentation/src/main/java/com/kusitms/presentation/model/profile/edit/ProfileEditViewModel.kt b/presentation/src/main/java/com/kusitms/presentation/model/profile/edit/ProfileEditViewModel.kt index 4bf9725..d86695e 100644 --- a/presentation/src/main/java/com/kusitms/presentation/model/profile/edit/ProfileEditViewModel.kt +++ b/presentation/src/main/java/com/kusitms/presentation/model/profile/edit/ProfileEditViewModel.kt @@ -79,6 +79,17 @@ class ProfileEditViewModel @Inject constructor( validateFields() } + + fun updateSelectedPart(part: String) { + _selectedPart.value = part + validateFields() + } + + fun updateInterests(interestItems: List) { + _interests.value = interestItems + validateFields() + } + fun updateEmail(newEmail: String) { _email.value = newEmail if (!isValidEmail(newEmail)) { @@ -113,6 +124,7 @@ class ProfileEditViewModel @Inject constructor( } + fun addLinkItem() { val newLinkItem = LinkItem(LinkType.LINK, "") //기본 설정값 _linkItems.value = _linkItems.value + newLinkItem @@ -154,4 +166,5 @@ class ProfileEditViewModel @Inject constructor( val phoneRegex = Regex("^01(?:0|1|[6-9])-(?:\\d{3}|\\d{4})-\\d{4}\$") return phoneNumber.matches(phoneRegex) } + } \ No newline at end of file diff --git a/presentation/src/main/java/com/kusitms/presentation/ui/profile/edit/ProfileBasic.kt b/presentation/src/main/java/com/kusitms/presentation/ui/profile/edit/ProfileBasic.kt index 5067896..5851b23 100644 --- a/presentation/src/main/java/com/kusitms/presentation/ui/profile/edit/ProfileBasic.kt +++ b/presentation/src/main/java/com/kusitms/presentation/ui/profile/edit/ProfileBasic.kt @@ -1,14 +1,30 @@ package com.kusitms.presentation.ui.profile.edit import androidx.compose.foundation.background +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement +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.padding +import androidx.compose.foundation.layout.statusBarsPadding +import androidx.compose.foundation.layout.systemBarsPadding import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.ExperimentalMaterialApi +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.Text +import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue @@ -17,21 +33,30 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import com.kusitms.presentation.R +import com.kusitms.presentation.common.ui.KusitmsMarginHorizontalSpacer +import com.kusitms.presentation.common.ui.KusitmsMarginVerticalSpacer import com.kusitms.presentation.common.ui.KusitmsSnackField import com.kusitms.presentation.common.ui.theme.KusitmsColorPalette import com.kusitms.presentation.common.ui.theme.KusitmsTypo +import com.kusitms.presentation.model.profile.edit.LikeCategoryBottomSheet +import com.kusitms.presentation.model.profile.edit.LikeCategoryTab +import com.kusitms.presentation.model.profile.edit.PartSelectColumn import com.kusitms.presentation.model.profile.edit.ProfileEditViewModel +import com.kusitms.presentation.model.signIn.PartCategory import com.kusitms.presentation.ui.ImageVector.StudyIcon import com.kusitms.presentation.ui.login.member.TextColumn1 import com.kusitms.presentation.ui.signIn.KusitmsInputField +import com.kusitms.presentation.ui.signIn.PartSnackTitle import com.kusitms.presentation.ui.signIn.SignInFixedInput import kotlinx.coroutines.ExperimentalCoroutinesApi -@OptIn(ExperimentalCoroutinesApi::class) +@OptIn(ExperimentalMaterialApi::class, ExperimentalCoroutinesApi::class) @Composable fun ProfileBasic( viewModel: ProfileEditViewModel = hiltViewModel(), @@ -53,6 +78,27 @@ fun ProfileBasic( var isOpenPartBottomSheet by remember { mutableStateOf(false) } var isOpenLikeCategoryBottomSheet by remember { mutableStateOf(false) } + if (isOpenPartBottomSheet) { + PartBottomSheet( + viewModel = viewModel, + isOpenPartBottomSheet + ) { + isOpenPartBottomSheet = it + if (!selectedPart.isNullOrBlank()) { + isOpenPartBottomSheet = false + } + } + } + + if (isOpenLikeCategoryBottomSheet) { + LikeCategoryBottomSheet( + viewModel = viewModel, + isOpenLikeCategoryBottomSheet + ) + { + isOpenLikeCategoryBottomSheet = it + } + } Column( modifier = Modifier @@ -198,4 +244,190 @@ fun ProfileBasic( color = KusitmsColorPalette.current.Grey400 ) } +} + + +@OptIn(ExperimentalMaterial3Api::class) +@ExperimentalMaterialApi +@Composable +fun PartBottomSheet( + viewModel: ProfileEditViewModel, + openBottomSheet: Boolean = false, + onChangeOpenBottomSheet: (Boolean) -> Unit = {}, +) { + val bottomSheetState = rememberModalBottomSheetState( + skipPartiallyExpanded = true + ) + + if (openBottomSheet) { + ModalBottomSheet( + containerColor = KusitmsColorPalette.current.Grey600, + dragHandle = { Box(Modifier.height(0.dp)) }, + onDismissRequest = { onChangeOpenBottomSheet(false) }, + sheetState = bottomSheetState, + modifier = Modifier + .fillMaxWidth() + .wrapContentHeight() + ) { + Column( + modifier = Modifier + .fillMaxWidth() + .systemBarsPadding() + .statusBarsPadding(), + horizontalAlignment = Alignment.Start, + verticalArrangement = Arrangement.Top + ) { + PartSnackTitle(onClick = { onChangeOpenBottomSheet(false) }) + KusitmsMarginVerticalSpacer(size = 20) + PartSelectColumn(viewModel = viewModel) + } + } + } +} + + +@OptIn(ExperimentalCoroutinesApi::class) +@Composable +fun PartSelectItem( + category: PartCategory, + onClick: (PartCategory) -> Unit, + viewModel: ProfileEditViewModel, +) { + val isSelected = viewModel.selectedPart.collectAsState().value?.contains(category.name) == true + val background = if (isSelected) KusitmsColorPalette.current.Grey500 else Color.Transparent + Row( + modifier = Modifier + .fillMaxWidth() + .height(56.dp) + .background(color = background, shape = RoundedCornerShape(size = 12.dp)) + .clickable { onClick(category) } + .padding(horizontal = 12.dp), + horizontalArrangement = Arrangement.spacedBy(12.dp, Alignment.Start), + verticalAlignment = Alignment.CenterVertically, + ) { + category.icon?.let { iconRes -> + Icon( + painter = painterResource(id = iconRes), + contentDescription = null, + tint = Color.Unspecified + ) + } + Text( + text = category.name, + style = KusitmsTypo.current.Text_Medium, + color = KusitmsColorPalette.current.Grey100 + ) + } +} + +@OptIn(ExperimentalCoroutinesApi::class) +@Composable +fun LikeBottomSheetContent(viewModel: ProfileEditViewModel, onClick: () -> Unit) { + var selectedCategory by remember { mutableStateOf(com.kusitms.presentation.model.signIn.categories.first()) } + val favoriteCategoryCount by viewModel.interests.collectAsState() + val buttonText = if (favoriteCategoryCount.isNotEmpty()) "확인" else "관심 카테고리를 선택해주세요" + val buttonColor = + if (favoriteCategoryCount.isNotEmpty()) KusitmsColorPalette.current.Grey100 else KusitmsColorPalette.current.Grey500 + val buttonTextColor = + if (favoriteCategoryCount.isNotEmpty()) KusitmsColorPalette.current.Grey600 else KusitmsColorPalette.current.Grey400 + + Column( + modifier = Modifier + .fillMaxSize() + .padding(horizontal = 0.dp) + .background( + color = KusitmsColorPalette.current.Grey600, + ), + horizontalAlignment = Alignment.Start, + verticalArrangement = Arrangement.Top + ) { + KusitmsMarginVerticalSpacer(size = 24) + CategoryBottomSheetTitle( + viewModel = viewModel, + onClick + ) + KusitmsMarginVerticalSpacer(size = 16) + LikeCategoryTab( + selectedCategory = selectedCategory, + onCategorySelected = { category -> selectedCategory = category }, + viewModel = viewModel + ) + Spacer(modifier = Modifier.weight(1f)) + Button( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 20.dp) + .height(56.dp), + onClick = { + onClick() + }, + colors = ButtonDefaults.buttonColors(containerColor = buttonColor), + shape = RoundedCornerShape(size = 16.dp) + ) { + Text( + text = buttonText, + style = KusitmsTypo.current.SubTitle2_Semibold, + color = buttonTextColor + ) + } + KusitmsMarginVerticalSpacer(size = 24) + } + +} + + +@Composable +fun CategoryBottomSheetTitle( + viewModel: ProfileEditViewModel, + onClick: () -> Unit, +) { + val favoriteCategoryCount = viewModel.interests.value.size ?: 0 + Row( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 24.dp) + .height(24.dp), + horizontalArrangement = Arrangement.Start, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = "관심 카테고리", + style = KusitmsTypo.current.SubTitle2_Semibold, + color = KusitmsColorPalette.current.Grey300 + ) + KusitmsMarginHorizontalSpacer(size = 12) + Box( + modifier = Modifier + .height(20.dp) + .width(20.dp) + .background( + color = KusitmsColorPalette.current.Grey500, + shape = RoundedCornerShape(size = 4.dp) + ), + contentAlignment = Alignment.Center + ) { + Text( + text = favoriteCategoryCount.toString(), + style = KusitmsTypo.current.Caption1, + color = KusitmsColorPalette.current.Main400 + ) + } + KusitmsMarginHorizontalSpacer(size = 2) + Text( + text = "개 선택", + style = KusitmsTypo.current.Caption1, + color = KusitmsColorPalette.current.Grey400 + ) + Spacer(modifier = Modifier.weight(1f)) + IconButton(onClick = { + onClick() + }) { + Icon( + painter = painterResource(id = R.drawable.ic_inputx), + contentDescription = "bottomSheetDown", + tint = KusitmsColorPalette.current.Grey300 + ) + } + + } } \ No newline at end of file diff --git a/presentation/src/main/java/com/kusitms/presentation/ui/signIn/component/PartBottomSheet.kt b/presentation/src/main/java/com/kusitms/presentation/ui/signIn/component/PartBottomSheet.kt index 7e80eb8..933b434 100644 --- a/presentation/src/main/java/com/kusitms/presentation/ui/signIn/component/PartBottomSheet.kt +++ b/presentation/src/main/java/com/kusitms/presentation/ui/signIn/component/PartBottomSheet.kt @@ -6,13 +6,11 @@ import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material.ExperimentalMaterialApi -import androidx.compose.material.ScaffoldState import androidx.compose.material.Text import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource @@ -25,7 +23,6 @@ import com.kusitms.presentation.model.signIn.SignInViewModel import com.kusitms.presentation.model.signIn.categories import com.kusitms.presentation.model.signIn.mapCategoryToValue import com.kusitms.presentation.ui.ImageVector.xIcon -import kotlinx.coroutines.launch @OptIn(ExperimentalMaterial3Api::class) @@ -58,7 +55,7 @@ fun PartBottomSheet( horizontalAlignment = Alignment.Start, verticalArrangement = Arrangement.Top ) { - partSnackTitle( onClick = { onChangeOpenBottomSheet(false) } ) + PartSnackTitle( onClick = { onChangeOpenBottomSheet(false) } ) KusitmsMarginVerticalSpacer(size = 20) partSelectColumn(viewModel = viewModel) } @@ -87,7 +84,7 @@ fun partSelectColumn(viewModel: SignInViewModel) { } @Composable -fun partSnackTitle(onClick: () -> Unit) { +fun PartSnackTitle(onClick: () -> Unit) { Row( modifier = Modifier .fillMaxWidth()